From 3e977d7eaf8c8e131852025145798cf7188b2ebb Mon Sep 17 00:00:00 2001 From: anupam-io Date: Tue, 10 Mar 2026 14:01:08 +0530 Subject: [PATCH 1/2] feat: range sdk 2.0.0 --- .editorconfig | 0 .eslintrc.js | 24 - .github/workflows/ci.yml | 49 + .gitignore | 86 +- .husky/pre-commit | 1 + .npmignore | 28 +- .prettierignore | 11 + .prettierrc | 6 +- .vscode/settings.json | 26 - CONTRIBUTING.md | 17 +- README.md | 224 +- dev.md | 20 - eslint.config.mjs | 47 + example/package.json | 20 + example/src/processors/LargeTransfer.ts | 64 + example/src/processors/TxSurge.ts | 66 + example/src/processors/processors.ts | 2 + example/src/start.ts | 30 + example/tsconfig.json | 15 + examples/rpcStatus.ts | 37 - examples/successMessage.ts | 40 - jest.config.ts | 13 + ops/version.sh | 44 + package.json | 131 +- src/__tests__/alerting-redis.test.ts | 73 + src/__tests__/basic.test.ts | 203 + src/__tests__/extractBlockMeta.test.ts | 100 + src/__tests__/fill-findings.test.ts | 28 + src/__tests__/number-fmt.test.ts | 73 + src/__tests__/process-task.test.ts | 196 + src/__tests__/processor-registry.test.ts | 188 + src/__tests__/processor-validation.test.ts | 150 + src/__tests__/redis-keys.test.ts | 27 + src/__tests__/skip-tick.test.ts | 25 + src/__tests__/testing-helpers.test.ts | 47 + src/__tests__/validParam.test.ts | 98 + src/__tests__/validateParameters.test.ts | 98 + src/benchmarking/mtt-bottleneck.spec.ts | 650 ++ src/benchmarking/mtt-performance.spec.ts | 709 ++ src/benchmarking/mtt-stress.spec.ts | 673 ++ src/connections/KafkaConsumer.ts | 66 - src/constants.ts | 148 - src/cosmos/CosmosClient.ts | 105 - src/e2e/bench-decode.ts | 234 + src/e2e/generate-report.ts | 359 + src/e2e/load-test.ts | 318 + src/e2e/pipeline-eth.ts | 194 + src/e2e/pipeline-solana-json.ts | 77 + src/e2e/pipeline-solana.ts | 319 + src/e2e/round-trip-test.ts | 278 + src/e2e/test-processors-eth.ts | 76 + src/e2e/test-processors.ts | 191 + src/e2e/validate-blocks.ts | 125 + src/e2e/validate-cosmos-blocks.ts | 125 + src/e2e/validate-eth-blocks.ts | 125 + src/env.ts | 175 + src/flatbuffers/solana/block.fbs | 89 + src/flatbuffers/solana/block.ts | 25 + src/flatbuffers/solana/block/account-key.ts | 150 + src/flatbuffers/solana/block/block-data.ts | 338 + .../solana/block/inner-instruction.ts | 147 + src/flatbuffers/solana/block/instruction.ts | 237 + src/flatbuffers/solana/block/message.ts | 184 + .../solana/block/sanctioned-entity.ts | 89 + src/flatbuffers/solana/block/solana-block.ts | 252 + .../solana/block/solana-transaction.ts | 116 + src/flatbuffers/solana/block/token-balance.ts | 165 + .../solana/block/transaction-meta.ts | 478 ++ src/flatbuffers/solana/block/transaction.ts | 155 + .../solana/block/ui-token-amount.ts | 154 + src/index.ts | 77 +- src/logger.ts | 18 - src/network.ts | 46 - src/processors/benchmark/AsyncCall.ts | 19 + src/processors/benchmark/BlockLiveness.ts | 47 + src/processors/benchmark/EmptyRule.ts | 17 + src/processors/benchmark/EmptyRuleTick.ts | 17 + src/processors/benchmark/Hang.ts | 19 + src/processors/benchmark/HangTick.ts | 19 + .../benchmark/PercBasedBenchmark.ts | 41 + src/processors/benchmark/ThrowError.ts | 17 + src/processors/benchmark/ThrowErrorTick.ts | 17 + src/processors/benchmark/TickLiveness.ts | 46 + src/processors/index.ts | 71 + src/processors/processors.ts | 7 + src/processors/taskProcessor.ts | 279 + src/scripts/benchmark-runtime.ts | 338 + src/scripts/benchmark.sh | 9 + src/scripts/generate-network-processors.ts | 211 + src/scripts/monitor.ts | 502 ++ src/scripts/producer.ts | 45 + src/sdk.ts | 1174 ---- src/services/AssetManager.ts | 1125 +++ src/services/alertEvent.ts | 32 - src/services/alerting-redis.ts | 73 + src/services/axios.ts | 6 + src/services/base-classes/BaseHelper.ts | 45 + .../base-classes/BooleanStateWatcher.ts | 80 + .../base-classes/NumericCollectionWatcher.ts | 113 + .../base-classes/NumericStateWatcher.ts | 88 + src/services/base-classes/OnBlockHelper.ts | 27 + src/services/base-classes/OnTickHelper.ts | 27 + src/services/cached-requests.ts | 34 + src/services/consumer-redis.ts | 321 + src/services/event-service.ts | 63 + src/services/fetchAlertRules.ts | 68 - src/services/fetchBlock.ts | 45 - src/services/fetchBlocksByRange.ts | 31 - src/services/fetchConfig.ts | 17 - src/services/getCosmosClient.ts | 64 - src/services/postDebugAlert.ts | 39 - src/services/prometheus-metrics.ts | 201 + src/services/prometheus-registry.ts | 6 + src/services/range-api.ts | 167 + src/services/redis-keys.ts | 17 + src/services/rpc.ts | 99 + src/services/slack-monitor.ts | 72 + src/services/stats-service.ts | 1310 ++++ src/services/taskAck.ts | 81 - src/services/tickTaskAck.ts | 37 - src/start.ts | 78 + src/test-sdk.ts | 89 - src/test_data/eth/.gitkeep | 0 src/test_data/osmosis-1/.gitkeep | 0 src/test_data/solana/.gitkeep | 0 src/threadpool/pool.ts | 213 + src/threadpool/runner.ts | 503 ++ src/threadpool/worker.ts | 68 + src/types/IAlertRule.ts | 13 + src/types/ICosmosBlock.ts | 83 + src/types/IEVMBlock.ts | 180 + src/types/IEvent.ts | 22 + src/types/INetwork.ts | 31 + src/types/IRangeAlertRule.ts | 11 - src/types/IRangeConfig.ts | 15 - src/types/IRangeEvent.ts | 22 - src/types/IRangeNetwork.ts | 4 - src/types/IRangeTaskPackage.ts | 24 - src/types/IRule.ts | 205 + src/types/IRunnerConfig.ts | 32 + src/types/ISolanaBlock.ts | 127 + src/types/ITask.ts | 49 + src/types/chain/IRangeBlock.ts | 99 - src/types/chain/IRangeMessage.ts | 22 - src/types/chain/IRangeTransaction.ts | 29 - .../chain/celestia/IRangeBlockCelestiaTrx.ts | 6 - .../celestia/IRangeBlockCelestiaTrxMsg.ts | 973 --- .../cosmoshub-4/IRangeBlockCosmosHub4Trx.ts | 6 - .../IRangeBlockCosmosHub4TrxMsg.ts | 980 --- .../IRangeBlockDydxMainnet1Trx.ts | 6 - .../IRangeBlockDydxMainnet1TrxMsg.ts | 993 --- .../chain/grand-1/IRangeBlockGrand1Trx.ts | 6 - .../chain/grand-1/IRangeBlockGrand1TrxMsg.ts | 568 -- .../chain/mocha-4/IRangeBlockMocha4Trx.ts | 6 - .../chain/mocha-4/IRangeBlockMocha4TrxMsg.ts | 618 -- .../chain/neutron-1/IRangeBlockNeutron1Trx.ts | 6 - .../neutron-1/IRangeBlockNeutron1TrxMsg.ts | 407 -- .../chain/noble-1/IRangeBlockNoble1Trx.ts | 6 - .../chain/noble-1/IRangeBlockNoble1TrxMsg.ts | 643 -- .../osmo-test-5/IRangeBlockOsmoTest5Trx.ts | 6 - .../osmo-test-5/IRangeBlockOsmoTest5TrxMsg.ts | 872 --- .../chain/osmosis-1/IRangeBlockOsmosis1Trx.ts | 6 - .../osmosis-1/IRangeBlockOsmosis1TrxMsg.ts | 1457 ---- .../chain/solana/IRangeBlockSolanaTrx.ts | 125 - .../chain/stride-1/IRangeBlockStride1Trx.ts | 6 - .../stride-1/IRangeBlockStride1TrxMsg.ts | 584 -- src/utils/basic.ts | 171 + src/utils/dayjs.ts | 26 + src/utils/doc-helper.ts | 217 + src/utils/explorer-api.ts | 173 + src/utils/fill-findings.ts | 9 + src/utils/logger.ts | 39 + src/utils/number-fmt.ts | 141 + src/utils/pipeline-setup.ts | 43 + src/utils/processor.ts | 118 + src/utils/redis-keys.ts | 20 + src/utils/redis.ts | 190 + src/utils/risk-score.ts | 26 + src/utils/safe-fetch.ts | 56 + src/utils/skip-tick.ts | 50 + src/utils/slack.ts | 58 + src/utils/solana/balance-change.ts | 115 + src/utils/solana/programs.ts | 49 + src/utils/solana/spl-actions.ts | 7 + src/utils/solana/tx-actions.ts | 255 + src/utils/summary-helpers.ts | 192 + src/utils/testing-helpers.ts | 247 + src/utils/toBuffer.ts | 3 - src/utils/updateRuleParamsInterface.ts | 25 + src/utils/validParam.ts | 56 + src/utils/validateParameters.ts | 85 + src/wrappers/solana-block-wrapper.ts | 531 ++ tests/cosmosClient.ts | 40 - tests/env.ts | 4 - tests/pushBlock.ts | 36 - tests/testBlock.ts | 78 - tsconfig.json | 28 +- tsconfig.test.json | 7 + yarn.lock | 6066 +++++++++++++---- 199 files changed, 24095 insertions(+), 12422 deletions(-) mode change 100755 => 100644 .editorconfig delete mode 100644 .eslintrc.js create mode 100644 .github/workflows/ci.yml create mode 100644 .husky/pre-commit create mode 100644 .prettierignore delete mode 100644 .vscode/settings.json delete mode 100644 dev.md create mode 100644 eslint.config.mjs create mode 100644 example/package.json create mode 100644 example/src/processors/LargeTransfer.ts create mode 100644 example/src/processors/TxSurge.ts create mode 100644 example/src/processors/processors.ts create mode 100644 example/src/start.ts create mode 100644 example/tsconfig.json delete mode 100644 examples/rpcStatus.ts delete mode 100644 examples/successMessage.ts create mode 100644 jest.config.ts create mode 100755 ops/version.sh create mode 100644 src/__tests__/alerting-redis.test.ts create mode 100644 src/__tests__/basic.test.ts create mode 100644 src/__tests__/extractBlockMeta.test.ts create mode 100644 src/__tests__/fill-findings.test.ts create mode 100644 src/__tests__/number-fmt.test.ts create mode 100644 src/__tests__/process-task.test.ts create mode 100644 src/__tests__/processor-registry.test.ts create mode 100644 src/__tests__/processor-validation.test.ts create mode 100644 src/__tests__/redis-keys.test.ts create mode 100644 src/__tests__/skip-tick.test.ts create mode 100644 src/__tests__/testing-helpers.test.ts create mode 100644 src/__tests__/validParam.test.ts create mode 100644 src/__tests__/validateParameters.test.ts create mode 100644 src/benchmarking/mtt-bottleneck.spec.ts create mode 100644 src/benchmarking/mtt-performance.spec.ts create mode 100644 src/benchmarking/mtt-stress.spec.ts delete mode 100644 src/connections/KafkaConsumer.ts delete mode 100644 src/constants.ts delete mode 100644 src/cosmos/CosmosClient.ts create mode 100644 src/e2e/bench-decode.ts create mode 100644 src/e2e/generate-report.ts create mode 100644 src/e2e/load-test.ts create mode 100644 src/e2e/pipeline-eth.ts create mode 100644 src/e2e/pipeline-solana-json.ts create mode 100644 src/e2e/pipeline-solana.ts create mode 100644 src/e2e/round-trip-test.ts create mode 100644 src/e2e/test-processors-eth.ts create mode 100644 src/e2e/test-processors.ts create mode 100644 src/e2e/validate-blocks.ts create mode 100644 src/e2e/validate-cosmos-blocks.ts create mode 100644 src/e2e/validate-eth-blocks.ts create mode 100644 src/env.ts create mode 100644 src/flatbuffers/solana/block.fbs create mode 100644 src/flatbuffers/solana/block.ts create mode 100644 src/flatbuffers/solana/block/account-key.ts create mode 100644 src/flatbuffers/solana/block/block-data.ts create mode 100644 src/flatbuffers/solana/block/inner-instruction.ts create mode 100644 src/flatbuffers/solana/block/instruction.ts create mode 100644 src/flatbuffers/solana/block/message.ts create mode 100644 src/flatbuffers/solana/block/sanctioned-entity.ts create mode 100644 src/flatbuffers/solana/block/solana-block.ts create mode 100644 src/flatbuffers/solana/block/solana-transaction.ts create mode 100644 src/flatbuffers/solana/block/token-balance.ts create mode 100644 src/flatbuffers/solana/block/transaction-meta.ts create mode 100644 src/flatbuffers/solana/block/transaction.ts create mode 100644 src/flatbuffers/solana/block/ui-token-amount.ts delete mode 100644 src/logger.ts delete mode 100644 src/network.ts create mode 100644 src/processors/benchmark/AsyncCall.ts create mode 100644 src/processors/benchmark/BlockLiveness.ts create mode 100644 src/processors/benchmark/EmptyRule.ts create mode 100644 src/processors/benchmark/EmptyRuleTick.ts create mode 100644 src/processors/benchmark/Hang.ts create mode 100644 src/processors/benchmark/HangTick.ts create mode 100644 src/processors/benchmark/PercBasedBenchmark.ts create mode 100644 src/processors/benchmark/ThrowError.ts create mode 100644 src/processors/benchmark/ThrowErrorTick.ts create mode 100644 src/processors/benchmark/TickLiveness.ts create mode 100644 src/processors/index.ts create mode 100644 src/processors/processors.ts create mode 100644 src/processors/taskProcessor.ts create mode 100644 src/scripts/benchmark-runtime.ts create mode 100644 src/scripts/benchmark.sh create mode 100644 src/scripts/generate-network-processors.ts create mode 100644 src/scripts/monitor.ts create mode 100644 src/scripts/producer.ts delete mode 100644 src/sdk.ts create mode 100644 src/services/AssetManager.ts delete mode 100644 src/services/alertEvent.ts create mode 100644 src/services/alerting-redis.ts create mode 100644 src/services/axios.ts create mode 100644 src/services/base-classes/BaseHelper.ts create mode 100644 src/services/base-classes/BooleanStateWatcher.ts create mode 100644 src/services/base-classes/NumericCollectionWatcher.ts create mode 100644 src/services/base-classes/NumericStateWatcher.ts create mode 100644 src/services/base-classes/OnBlockHelper.ts create mode 100644 src/services/base-classes/OnTickHelper.ts create mode 100644 src/services/cached-requests.ts create mode 100644 src/services/consumer-redis.ts create mode 100644 src/services/event-service.ts delete mode 100644 src/services/fetchAlertRules.ts delete mode 100644 src/services/fetchBlock.ts delete mode 100644 src/services/fetchBlocksByRange.ts delete mode 100644 src/services/fetchConfig.ts delete mode 100644 src/services/getCosmosClient.ts delete mode 100644 src/services/postDebugAlert.ts create mode 100644 src/services/prometheus-metrics.ts create mode 100644 src/services/prometheus-registry.ts create mode 100644 src/services/range-api.ts create mode 100644 src/services/redis-keys.ts create mode 100644 src/services/rpc.ts create mode 100644 src/services/slack-monitor.ts create mode 100644 src/services/stats-service.ts delete mode 100644 src/services/taskAck.ts delete mode 100644 src/services/tickTaskAck.ts create mode 100644 src/start.ts delete mode 100644 src/test-sdk.ts create mode 100644 src/test_data/eth/.gitkeep create mode 100644 src/test_data/osmosis-1/.gitkeep create mode 100644 src/test_data/solana/.gitkeep create mode 100644 src/threadpool/pool.ts create mode 100644 src/threadpool/runner.ts create mode 100644 src/threadpool/worker.ts create mode 100644 src/types/IAlertRule.ts create mode 100644 src/types/ICosmosBlock.ts create mode 100644 src/types/IEVMBlock.ts create mode 100644 src/types/IEvent.ts create mode 100644 src/types/INetwork.ts delete mode 100644 src/types/IRangeAlertRule.ts delete mode 100644 src/types/IRangeConfig.ts delete mode 100644 src/types/IRangeEvent.ts delete mode 100644 src/types/IRangeNetwork.ts delete mode 100644 src/types/IRangeTaskPackage.ts create mode 100644 src/types/IRule.ts create mode 100644 src/types/IRunnerConfig.ts create mode 100644 src/types/ISolanaBlock.ts create mode 100644 src/types/ITask.ts delete mode 100644 src/types/chain/IRangeBlock.ts delete mode 100644 src/types/chain/IRangeMessage.ts delete mode 100644 src/types/chain/IRangeTransaction.ts delete mode 100644 src/types/chain/celestia/IRangeBlockCelestiaTrx.ts delete mode 100644 src/types/chain/celestia/IRangeBlockCelestiaTrxMsg.ts delete mode 100644 src/types/chain/cosmoshub-4/IRangeBlockCosmosHub4Trx.ts delete mode 100644 src/types/chain/cosmoshub-4/IRangeBlockCosmosHub4TrxMsg.ts delete mode 100644 src/types/chain/dydx-mainnet-1/IRangeBlockDydxMainnet1Trx.ts delete mode 100644 src/types/chain/dydx-mainnet-1/IRangeBlockDydxMainnet1TrxMsg.ts delete mode 100644 src/types/chain/grand-1/IRangeBlockGrand1Trx.ts delete mode 100644 src/types/chain/grand-1/IRangeBlockGrand1TrxMsg.ts delete mode 100644 src/types/chain/mocha-4/IRangeBlockMocha4Trx.ts delete mode 100644 src/types/chain/mocha-4/IRangeBlockMocha4TrxMsg.ts delete mode 100644 src/types/chain/neutron-1/IRangeBlockNeutron1Trx.ts delete mode 100644 src/types/chain/neutron-1/IRangeBlockNeutron1TrxMsg.ts delete mode 100644 src/types/chain/noble-1/IRangeBlockNoble1Trx.ts delete mode 100644 src/types/chain/noble-1/IRangeBlockNoble1TrxMsg.ts delete mode 100644 src/types/chain/osmo-test-5/IRangeBlockOsmoTest5Trx.ts delete mode 100644 src/types/chain/osmo-test-5/IRangeBlockOsmoTest5TrxMsg.ts delete mode 100644 src/types/chain/osmosis-1/IRangeBlockOsmosis1Trx.ts delete mode 100644 src/types/chain/osmosis-1/IRangeBlockOsmosis1TrxMsg.ts delete mode 100644 src/types/chain/solana/IRangeBlockSolanaTrx.ts delete mode 100644 src/types/chain/stride-1/IRangeBlockStride1Trx.ts delete mode 100644 src/types/chain/stride-1/IRangeBlockStride1TrxMsg.ts create mode 100644 src/utils/basic.ts create mode 100644 src/utils/dayjs.ts create mode 100644 src/utils/doc-helper.ts create mode 100644 src/utils/explorer-api.ts create mode 100644 src/utils/fill-findings.ts create mode 100644 src/utils/logger.ts create mode 100644 src/utils/number-fmt.ts create mode 100644 src/utils/pipeline-setup.ts create mode 100644 src/utils/processor.ts create mode 100644 src/utils/redis-keys.ts create mode 100644 src/utils/redis.ts create mode 100644 src/utils/risk-score.ts create mode 100644 src/utils/safe-fetch.ts create mode 100644 src/utils/skip-tick.ts create mode 100644 src/utils/slack.ts create mode 100644 src/utils/solana/balance-change.ts create mode 100644 src/utils/solana/programs.ts create mode 100644 src/utils/solana/spl-actions.ts create mode 100644 src/utils/solana/tx-actions.ts create mode 100644 src/utils/summary-helpers.ts create mode 100644 src/utils/testing-helpers.ts delete mode 100644 src/utils/toBuffer.ts create mode 100644 src/utils/updateRuleParamsInterface.ts create mode 100644 src/utils/validParam.ts create mode 100644 src/utils/validateParameters.ts create mode 100644 src/wrappers/solana-block-wrapper.ts delete mode 100644 tests/cosmosClient.ts delete mode 100644 tests/env.ts delete mode 100644 tests/pushBlock.ts delete mode 100644 tests/testBlock.ts create mode 100644 tsconfig.test.json diff --git a/.editorconfig b/.editorconfig old mode 100755 new mode 100644 diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index f6c62bee..00000000 --- a/.eslintrc.js +++ /dev/null @@ -1,24 +0,0 @@ -module.exports = { - parser: '@typescript-eslint/parser', - parserOptions: { - project: 'tsconfig.json', - sourceType: 'module', - }, - plugins: ['@typescript-eslint/eslint-plugin'], - extends: [ - 'plugin:@typescript-eslint/recommended', - 'plugin:prettier/recommended', - ], - root: true, - env: { - node: true, - jest: true, - }, - ignorePatterns: ['.eslintrc.js'], - rules: { - '@typescript-eslint/interface-name-prefix': 'off', - '@typescript-eslint/explicit-function-return-type': 'off', - '@typescript-eslint/explicit-module-boundary-types': 'off', - '@typescript-eslint/no-explicit-any': 'off', - }, -}; diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..5ea624c2 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,49 @@ +name: CI +on: + pull_request: + branches: [main] + push: + branches: [main] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 20 + cache: yarn + - run: yarn install --frozen-lockfile + - run: yarn lint + - run: yarn typecheck + - run: yarn build + + unit: + runs-on: ubuntu-latest + needs: build + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 20 + cache: yarn + - run: yarn install --frozen-lockfile + - run: yarn test:unit + + e2e: + runs-on: ubuntu-latest + needs: build + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 20 + cache: yarn + - run: yarn install --frozen-lockfile + - run: yarn build + # - run: yarn test:e2e + # - run: yarn test:validate:solana + # - run: yarn test:validate:eth + # - run: yarn test:validate:cosmos + # - run: yarn test:roundtrip diff --git a/.gitignore b/.gitignore index cfcc06f8..43b2909a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,82 @@ -node_modules -dist -.idea -yarn-error.log +# Dependencies +node_modules/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Build output +dist/ +build/ + +# Environment variables .env -.npmrc +.env.local +.env.development.local +.env.test.local +.env.production.local + +# Logs +logs +*.log + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Coverage directory used by tools like istanbul +coverage/ + +# nyc test coverage +.nyc_output + +# Dependency directories +jspm_packages/ + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity +.yarn/ + +# dotenv environment variables file +.env + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +.logs +.asset-service-cache +.cache +tsconfig.tsbuildinfo + +# Features Plans (local-only) +docs/plans/ +tsconfig.prod.json +.husky/_/ +src/dev +*.txt \ No newline at end of file diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 00000000..2312dc58 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1 @@ +npx lint-staged diff --git a/.npmignore b/.npmignore index ee9185ad..2d22df60 100644 --- a/.npmignore +++ b/.npmignore @@ -1,10 +1,18 @@ -.vscode -examples -src -tests -.editorconfig -.eslintrc.js -.prettierrc -tsconfig.json -.env -yarn-error.log +src/ +dist/start.js +dist/start.d.ts +dist/start.js.map +dist/benchmark.js +dist/benchmark.d.ts +dist/benchmark.js.map +dist/scripts/ +dist/test_data/ +dist/processors/ +dist/e2e/ +dist/flatbuffers/ +dist/dev/ +.logs/ +.asset-service-cache/ +coverage/ +node_modules/ +*.tsbuildinfo diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..3094cf90 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,11 @@ +dist/ +node_modules/ +yarn.lock +package-lock.json +*.log +*.d.ts +coverage/ +.nyc_output/ +.cache/ +.vscode/ +.idea/ \ No newline at end of file diff --git a/.prettierrc b/.prettierrc index a20502b7..7225824f 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,4 +1,8 @@ { + "semi": true, + "trailingComma": "es5", "singleQuote": true, - "trailingComma": "all" + "printWidth": 80, + "tabWidth": 2, + "useTabs": false } diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index f58e6883..00000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "cSpell.words": [ - "Celestia", - "clob", - "Concentratedliquidity", - "cosmoshub", - "Delegator", - "Dydx", - "Dydxprotocol", - "Feegrant", - "Fungify", - "kafkajs", - "osmo", - "Redelegate", - "SASL", - "Subaccount", - "Unbonding", - "Undelegate", - "Unjail" - ], - "editor.defaultFormatter": "esbenp.prettier-vscode", - "editor.formatOnSave": true, - "[typescript]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" - } -} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f9cb6a8b..b17e4285 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,19 +1,19 @@ # Contributing When contributing to this repository, please first discuss the change you wish to make via issue, -email, or any other method with the owners of this repository before making a change. +email, or any other method with the owners of this repository before making a change. Please note we have a code of conduct, please follow it in all your interactions with the project. ## Pull Request Process -1. Ensure any install or build dependencies are removed before the end of the layer when doing a +1. Ensure any install or build dependencies are removed before the end of the layer when doing a build. -2. Update the README.md with details of changes to the interface, this includes new environment +2. Update the README.md with details of changes to the interface, this includes new environment variables, exposed ports, useful file locations and container parameters. 3. Increase the version numbers in any examples files and the README.md to the new version that this Pull Request would represent. The versioning scheme we use is [SemVer](http://semver.org/). -4. You may merge the Pull Request in once you have the sign-off of two other developers, or if you +4. You may merge the Pull Request in once you have the sign-off of two other developers, or if you do not have permission to do that, you may request the second reviewer to merge it for you. ## Code of Conduct @@ -73,7 +73,7 @@ further defined and clarified by project maintainers. ### Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team at [INSERT EMAIL ADDRESS]. All +reported by contacting the project team. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. @@ -85,8 +85,5 @@ members of the project's leadership. ### Attribution -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, -available at [http://contributor-covenant.org/version/1/4][version] - -[homepage]: http://contributor-covenant.org -[version]: http://contributor-covenant.org/version/1/4/ \ No newline at end of file +This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.4, +available at [http://contributor-covenant.org/version/1/4](http://contributor-covenant.org/version/1/4) diff --git a/README.md b/README.md index dd2be0cc..c7533964 100644 --- a/README.md +++ b/README.md @@ -1,148 +1,104 @@ # Range SDK -[Range SDK](https://www.npmjs.com/package/@range-security/range-sdk) is a powerful TypeScript library that simplifies the development of risk, compliance and security rules across multiple blockchain networks. It enables developers to build monitoring and detection logic for a wide range of ecosystems, including Solana, Stellar, EVM-based chains, Cosmos networks, and others. +Build real-time security rules and anomaly detectors for any blockchain. -With the Range SDK, teams can easily extend the security of their protocols by monitoring blockchain activity in real time, detecting issues such as anomalies, invariant violations, risk scenarios, phishing attacks, spam, and other suspicious behaviors. +Range SDK is a TypeScript framework for writing alert rules that run against live blockchain data. Define rules with decorators, process blocks or time-based ticks, and emit events — the SDK handles multi-threaded execution, Redis streaming, and rule lifecycle management. ## Table of Contents -- [Range SDK](#range-sdk) - - [Table of Contents](#table-of-contents) - - [Installation](#installation) - - [Usage](#usage) - - [Features](#features) - - [Documentation](#documentation) - - [How To Contribute](#how-to-contribute) - - [Reporting bugs](#reporting-bugs) - - [License](#license) - - [Credits](#credits) +- [Highlights](#highlights) +- [Quick Start](#quick-start) +- [Rule Anatomy](#rule-anatomy) +- [Requirements](#requirements) +- [Supported Networks](#supported-networks) +- [How To Contribute](#how-to-contribute) +- [Reporting Bugs](#reporting-bugs) +- [License](#license) +- [Credits](#credits) -## Installation +## Highlights + +- **Decorator-based rules** — Define rules with `@Rule()`, typed parameters, and clean async callbacks. No boilerplate. +- **Two trigger modes** — `BlockProcessor` runs on every new block. `TickProcessor` runs on a time interval. Use whichever fits your use case. +- **Multi-chain** — One SDK for Solana, Ethereum, Arbitrum, BNB Chain, Polygon, Osmosis, Cosmos Hub, Noble, dYdX, ZigChain, and [more](https://app.range.org). + +### Built-in Services + +- **Real-Time Block Streaming** — Consume live blocks as they're produced. Your alert logic runs on every new block across any supported chain. +- **Multi-Chain RPC** — Connect to EVM, Cosmos, and Solana through a single unified interface. No need to manage RPC endpoints yourself. +- **Risk Scoring & Address Labels** — Look up wallet labels and get risk scores for any address. Know if a counterparty is sanctioned or suspicious before it's too late. +- **Solana Tx Simulation** — Simulate Solana transactions before they execute. See expected state changes and human-readable summaries. + +## Quick Start ```bash yarn add @range-security/range-sdk ``` -## Usage - -Here's a basic example to get you started: - -```typescript -// Range Implementation of `new-contract-code-stored` alert rule -import { - RangeSDK, - OnBlock, - IRangeBlock, - IRangeAlertRule, - ISubEvent, -} from '@range-security/range-sdk'; - -// Define your OnBlock handler -const myOnBlock: OnBlock = { - callback: async ( - block: IRangeBlock, - rule: IRangeAlertRule, - ): Promise => { - const allMessages = block.transactions.flatMap((tx) => tx.messages); - const targetMessages = allMessages.filter((m) => { - return m.type === 'cosmwasm.wasm.v1.MsgStoreCode'; - }); - - const results = targetMessages.map((m) => ({ - details: { - message: `New CW contract code stored by ${m.value.sender}`, - }, - txHash: m.hash, - addressesInvolved: m.addresses, - })); - - return results; - }, -}; - -(async () => { - // Defining the RangeSDK instance - const range = new RangeSDK({ - token: env.RANGE_TOKEN, - }); - - // Running the RangeSDK instance - await range.init({ - onBlock: myOnBlock, - }); -})(); -``` +See the [`example/`](./example) directory for a complete working project with two sample rules: +- **`large-transfer`** — alerts when a SOL transfer exceeds a threshold +- **`tx-surge`** — alerts when a block's transaction count spikes above the rolling average -```typescript -// Range Implementation of `rpc-status` alert rule -import { - RangeSDK, - OnTick, - IRangeAlertRule, - ISubEvent, -} from '@range-security/range-sdk'; - -// Define your OnTick handler -const myOnTick: OnTick = { - callback: async ( - timestamp: string, - rule: IRangeAlertRule, - ): Promise => { - const parameters = rule.parameters; - - // note: if p.ticker is set as 10, the rule will run on each 10 minutes - if (dayjs(timestamp).get('minute') % p.ticker !== 0) { - return []; - } - - try { - await axios.get(`https://rpc.osmosis.zone/status`); - return []; - } catch (error) { - return [ - { - details: { - message: `Osmosis public RPC is down: ${JSON.stringify(error).slice(0, 100)}...`, - }, - txHash: '', - addressesInvolved: [], - caption: 'Osmosis public RPC down', - }, - ]; - } - }, -}; - -(async () => { - // Defining the RangeSDK instance - const range = new RangeSDK({ - token: env.RANGE_TOKEN, - }); - - // Running the RangeSDK instance - await range.init({ - onTick: myOnTick, - }); -})(); -``` +## Rule Anatomy + +Every rule is a class decorated with `@Rule()`: + +| Field | Description | +|-------|-------------| +| `type` | Unique identifier for this rule type (kebab-case) | +| `label` | Human-readable name shown in the Range App | +| `description` | What the rule does | +| `networks` | Array of network IDs this rule runs on (e.g. `['osmosis-1', 'eth']`) | +| `parameters` | Configurable inputs for the rule | +| `tags` | Categories for filtering (`security`, `governance`, `dex`, `stablecoin`, etc.) | +| `severity` | Alert level: `info`, `low`, `medium`, `high`, `critical` | -For more examples and use-cases, see the open-source rule repositories of several Cosmos chains: +The callback receives: -- [Osmosis Range Rules](https://github.com/rangesecurity/osmosis-range-rules) -- [Cosmos Hub Range Rules](https://github.com/rangesecurity/cosmos-range-rules) +- **BlockProcessor**: `{ block, rule }` — the decoded block data and the rule instance with its parameters. Blocks are typed per chain: `IEVMBlock`, `ISolanaBlock`, `ICosmosBlock`. +- **TickProcessor**: `{ timestamp, rule }` — the current tick timestamp and the rule instance -## Features +Both return `ISubEvent[]` — an array of events to emit (or empty array for no alert). -- Simple and intuitive API -- Advanced security rule building in Typescript -- Easy integration testing with real block data -- Powerful anomaly detection examples -- Integration with most Cosmos chains -- Extensive documentation +### Event Shape -## Documentation +Each event in the returned array has these fields: -Complete documentation can be found at our official documentation site. +| Field | Required | Description | +|-------|----------|-------------| +| `caption` | Yes | Short summary of the alert | +| `details` | Yes | Object with a `message` string and optional extra fields | +| `txHash` | No | Transaction hash related to the alert | +| `addressesInvolved` | No | Array of addresses relevant to the alert | +| `severity` | No | Override the rule-level severity for this specific event | + +## Requirements + +- Node.js >= 18 +- TypeScript >= 5.x + +## Supported Networks + +| Network | Network ID | +|---------|------------| +| Solana | `solana` | +| Ethereum | `eth` | +| Arbitrum | `arb1` | +| BNB Chain | `bnb` | +| Polygon | `pol` | +| Osmosis | `osmosis-1` | +| Cosmos Hub | `cosmoshub-4` | +| Noble | `noble-1` | +| dYdX | `dydx-mainnet-1` | +| Stride | `stride-1` | +| Celestia | `celestia` | +| Neutron | `neutron-1` | +| Dymension | `dymension_1100-1` | +| Agoric | `agoric-3` | +| Provenance | `pio-mainnet-1` | +| Mantra | `mantra-1` | + +More networks are being added regularly. See all supported networks on the [Range App](https://app.range.org). ## How To Contribute @@ -154,22 +110,28 @@ We welcome contributions from the community! To get started: ```bash git clone https://github.com/your-username/range-sdk.git cd range-sdk -npm install +yarn install ``` 3. Make your changes, add tests, and ensure tests pass. 4. Commit your changes and push to your fork. 5. Create a pull request with a detailed explanation of your changes. -Before contributing, please read our [CONTRIBUTING.md](link). +Before contributing, please read our [CONTRIBUTING.md](./CONTRIBUTING.md). + +## Reporting Bugs + +If you encounter any bugs or issues, please [open an issue on GitHub](https://github.com/rangesecurity/range-sdk/issues). When reporting a bug, please provide as much context as possible, including error messages, logs, and steps to reproduce the bug. -## Reporting bugs +## Links -If you encounter any bugs or issues, please [open an issue on GitHub](link). When reporting a bug, please provide as much context as possible, including error messages, logs, and steps to reproduce the bug. +- [Range App](https://app.range.org) +- [Documentation](https://docs.range.org) +- [Get in Touch](https://range.org/get-in-touch) ## License -This project is licensed under the MIT License. See the [LICENSE](link) file for details. +This project is licensed under the MIT License. See the [LICENSE](./LICENSE) file for details. ## Credits diff --git a/dev.md b/dev.md deleted file mode 100644 index 988b37bb..00000000 --- a/dev.md +++ /dev/null @@ -1,20 +0,0 @@ -# Discussion - -## Plan - -We want third parties to run their custom alert rules using our sdk. We are also going to use the sdk for writing our own runners. At some point in time, we are gonna make `range-sdk` and our alert processors public. - -Here is the flow for a third party user: - -- Signup for the sdk and get your unique `range-sdk-code` -- Write the code for your worker in TS similar to our template: - - define the necessary caller function: `onBlock` or `onTransaction` or `onMessage` - - pass them into our Range.init() function -- After running the init() function, the worker will listen for incoming block tasks from kafka topics -- Once a block is received, the worker will process it -- Any generated events will be sent back to a rabbitmq queue -- From `range-team` side: - - provide wrapped kafka access to authorized users - - provide wrapped endpoint access to authorized users - - provide endpoint for accessing certain blocks - - process generated errors or events(storing them in appdb and sending notifications to defined destinations) diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 00000000..ddc638dc --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,47 @@ +import js from '@eslint/js'; +import tseslint from 'typescript-eslint'; +import prettier from 'eslint-plugin-prettier'; +import prettierConfig from 'eslint-config-prettier'; +import globals from 'globals'; + +export default tseslint.config( + { + ignores: ['dist/**', 'node_modules/**', '*.d.ts', 'src/flatbuffers/**', 'src/dev/**'], + }, + js.configs.recommended, + ...tseslint.configs.recommended, + prettierConfig, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + globals: { + ...globals.node, + }, + }, + plugins: { + prettier, + }, + rules: { + 'prettier/prettier': 'error', + '@typescript-eslint/no-unused-vars': 'off', + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/explicit-function-return-type': 'off', + '@typescript-eslint/explicit-module-boundary-types': 'off', + '@typescript-eslint/no-inferrable-types': 'off', + '@typescript-eslint/no-require-imports': 'off', + 'no-console': 'off', + 'no-debugger': 'error', + }, + }, + { + files: ['**/*.js', '**/*.mjs'], + plugins: { + prettier, + }, + rules: { + 'prettier/prettier': 'error', + 'no-console': 'warn', + 'no-debugger': 'error', + }, + } +); diff --git a/example/package.json b/example/package.json new file mode 100644 index 00000000..ee358bf8 --- /dev/null +++ b/example/package.json @@ -0,0 +1,20 @@ +{ + "name": "range-sdk-example", + "version": "0.0.1", + "private": true, + "scripts": { + "build": "tsc", + "dev": "ts-node src/start.ts", + "start": "node dist/start.js" + }, + "dependencies": { + "@range-security/range-sdk": "latest", + "dotenv": "^17.0.0", + "reflect-metadata": "^0.2.2" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "ts-node": "^10.9.2", + "typescript": "^5.8.0" + } +} diff --git a/example/src/processors/LargeTransfer.ts b/example/src/processors/LargeTransfer.ts new file mode 100644 index 00000000..c426e45c --- /dev/null +++ b/example/src/processors/LargeTransfer.ts @@ -0,0 +1,64 @@ +import { + BlockProcessor, + IBlockProcessor, + Rule, + ISubEvent, + ISolanaBlock, +} from '@range-security/range-sdk'; + +interface IParameters { + thresholdSOL: number; +} + +@Rule({ + type: 'large-transfer', + label: 'Large SOL Transfer', + description: 'Alerts when a SOL transfer exceeds a threshold', + networks: ['solana'], + parameters: [ + { + field: 'thresholdSOL', + label: 'Threshold (SOL)', + fieldType: 'Number', + description: 'Minimum SOL amount to trigger an alert', + }, + ], + tags: ['security', 'transfer'], + severity: 'high', +}) +export class LargeTransferProcessor extends BlockProcessor { + async callback({ + rule, + block, + }: IBlockProcessor): Promise { + const thresholdLamports = rule.parameters.thresholdSOL * 1e9; + const events: ISubEvent[] = []; + + for (const tx of block.transactions) { + if (tx.meta.err) continue; + + const { preBalances, postBalances } = tx.meta; + const accountKeys = tx.transaction.message.accountKeys; + + for (let i = 0; i < preBalances.length; i++) { + const diff = preBalances[i] - postBalances[i]; + + if (diff > thresholdLamports) { + const sender = accountKeys[i]?.pubkey || 'unknown'; + const solAmount = diff / 1e9; + + events.push({ + caption: `Large transfer: ${solAmount.toFixed(2)} SOL from ${sender.slice(0, 8)}...`, + details: { + message: `${sender} sent ${solAmount.toFixed(4)} SOL in block ${block.height}`, + }, + txHash: tx.transaction.signatures[0], + addressesInvolved: [sender], + }); + } + } + } + + return events; + } +} diff --git a/example/src/processors/TxSurge.ts b/example/src/processors/TxSurge.ts new file mode 100644 index 00000000..dc78f986 --- /dev/null +++ b/example/src/processors/TxSurge.ts @@ -0,0 +1,66 @@ +import { + BlockProcessor, + IBlockProcessor, + Rule, + ISubEvent, + ISolanaBlock, +} from '@range-security/range-sdk'; + +interface IParameters { + surgePercent: number; +} + +const recentTxCounts: number[] = []; +const WINDOW_SIZE = 10; + +@Rule({ + type: 'tx-surge', + label: 'Transaction Surge', + description: + 'Alerts when transaction count exceeds the rolling average by a percentage', + networks: ['solana'], + parameters: [ + { + field: 'surgePercent', + label: 'Surge Threshold (%)', + fieldType: 'Number', + description: 'Trigger if tx count exceeds avg by this percentage', + }, + ], + tags: ['security', 'unusual'], + severity: 'medium', +}) +export class TxSurgeProcessor extends BlockProcessor { + async callback({ + rule, + block, + }: IBlockProcessor): Promise { + const txCount = block.transactions.length; + const surgePercent = rule.parameters.surgePercent; + + if (recentTxCounts.length >= WINDOW_SIZE) { + const avg = + recentTxCounts.reduce((sum, c) => sum + c, 0) / recentTxCounts.length; + const threshold = avg * (1 + surgePercent / 100); + + if (txCount > threshold) { + recentTxCounts.push(txCount); + if (recentTxCounts.length > WINDOW_SIZE) recentTxCounts.shift(); + + return [ + { + caption: `Tx surge: ${txCount} txs (avg ${avg.toFixed(0)})`, + details: { + message: `Block ${block.height} has ${txCount} transactions, ${((txCount / avg - 1) * 100).toFixed(1)}% above the ${WINDOW_SIZE}-block average of ${avg.toFixed(0)}`, + }, + }, + ]; + } + } + + recentTxCounts.push(txCount); + if (recentTxCounts.length > WINDOW_SIZE) recentTxCounts.shift(); + + return []; + } +} diff --git a/example/src/processors/processors.ts b/example/src/processors/processors.ts new file mode 100644 index 00000000..2a30fe0b --- /dev/null +++ b/example/src/processors/processors.ts @@ -0,0 +1,2 @@ +export { LargeTransferProcessor } from './LargeTransfer'; +export { TxSurgeProcessor } from './TxSurge'; diff --git a/example/src/start.ts b/example/src/start.ts new file mode 100644 index 00000000..6cf0a5d8 --- /dev/null +++ b/example/src/start.ts @@ -0,0 +1,30 @@ +import 'dotenv/config'; +import { startRunner } from '@range-security/range-sdk'; +import { join } from 'path'; + +const testAlertRules = [ + { + ruleType: 'large-transfer', + parameters: { thresholdSOL: 100 }, + triggerMode: 'BLOCK' as const, + }, + { + ruleType: 'tx-surge', + parameters: { surgePercent: 10 }, + triggerMode: 'BLOCK' as const, + }, +]; + +testAlertRules.forEach((rule: any, i) => { + rule.id = i; + rule.network = 'solana'; + rule.createdAt = new Date().toISOString(); +}); + +startRunner({ + processors: join(process.cwd(), 'dist', 'processors', 'processors.js'), + testAlertRules: testAlertRules as any, +}).catch((error) => { + console.error(error); + process.exit(1); +}); diff --git a/example/tsconfig.json b/example/tsconfig.json new file mode 100644 index 00000000..949fbf6b --- /dev/null +++ b/example/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "ES2022", + "outDir": "./dist", + "rootDir": "./src", + "declaration": true, + "esModuleInterop": true, + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + "skipLibCheck": true, + "strictNullChecks": true + }, + "exclude": ["dist"] +} diff --git a/examples/rpcStatus.ts b/examples/rpcStatus.ts deleted file mode 100644 index af69d186..00000000 --- a/examples/rpcStatus.ts +++ /dev/null @@ -1,37 +0,0 @@ -import axios from 'axios'; -import { RangeSDK, ISubEvent, OnTick } from '../src'; - -const myOnTick: OnTick = { - callback: async (): Promise => { - const rpcStatusUrl = `https://rpc.osmosis.zone/status`; - try { - await axios.get(rpcStatusUrl); - return []; - } catch (error) { - return [ - { - details: { - message: 'Osmosis RPC is down', - }, - caption: 'RPC Down', - }, - ]; - } - }, -}; - -(async () => { - if (!process.env.RANGE_SDK_TOKEN) { - throw new Error('Range SDK Token is required'); - } - - // Defining the RangeSDK instance - await RangeSDK.build( - { - token: process.env.RANGE_SDK_TOKEN, - }, - { - onTick: myOnTick, - }, - ); -})(); diff --git a/examples/successMessage.ts b/examples/successMessage.ts deleted file mode 100644 index 0ff01c37..00000000 --- a/examples/successMessage.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { RangeSDK, ISubEvent, OnBlock, IRangeBlock } from '../src'; - -const myOnBlock: OnBlock = { - callback: async (block: IRangeBlock): Promise => { - const alerts: ISubEvent[] = []; - - for (const tx of block.transactions) { - if (!tx.success) { - continue; - } - - for (const m of tx.messages) { - alerts.push({ - details: { - message: 'Success message of type: ' + m.type, - }, - caption: 'Success message', - }); - } - } - - return alerts; - }, -}; - -(async () => { - if (!process.env.RANGE_SDK_TOKEN) { - throw new Error('Range SDK Token is required'); - } - - // Defining the RangeSDK instance - await RangeSDK.build( - { - token: process.env.RANGE_SDK_TOKEN, - }, - { - onBlock: myOnBlock, - }, - ); -})(); diff --git a/jest.config.ts b/jest.config.ts new file mode 100644 index 00000000..aa079cf0 --- /dev/null +++ b/jest.config.ts @@ -0,0 +1,13 @@ +import type { Config } from 'jest'; + +const config: Config = { + preset: 'ts-jest', + testEnvironment: 'node', + testMatch: ['/src/__tests__/**/*.test.ts'], + moduleFileExtensions: ['ts', 'js', 'json'], + transform: { + '^.+\\.ts$': ['ts-jest', { tsconfig: 'tsconfig.test.json' }], + }, +}; + +export default config; diff --git a/ops/version.sh b/ops/version.sh new file mode 100755 index 00000000..b6f9599f --- /dev/null +++ b/ops/version.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +set -euo pipefail + +BUMP="${1:-patch}" +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PKG="$SCRIPT_DIR/../package.json" + +if [[ ! -f "$PKG" ]]; then + echo "Error: package.json not found at $PKG" >&2 + exit 1 +fi + +if [[ "$BUMP" != "patch" && "$BUMP" != "minor" && "$BUMP" != "major" ]]; then + echo "Usage: $0 [patch|minor|major]" >&2 + echo " Default: patch" >&2 + exit 1 +fi + +CURRENT=$(jq -r '.version' "$PKG") +IFS='.' read -r MAJOR MINOR PATCH <<< "$CURRENT" + +case "$BUMP" in + major) MAJOR=$((MAJOR + 1)); MINOR=0; PATCH=0 ;; + minor) MINOR=$((MINOR + 1)); PATCH=0 ;; + patch) PATCH=$((PATCH + 1)) ;; +esac + +NEW_VERSION="$MAJOR.$MINOR.$PATCH" +TAG="v$NEW_VERSION" + +echo "Bumping version: $CURRENT -> $NEW_VERSION ($BUMP)" + +# Update package.json +jq --arg v "$NEW_VERSION" '.version = $v' "$PKG" > "$PKG.tmp" && mv "$PKG.tmp" "$PKG" + +# Commit, tag, push +cd "$SCRIPT_DIR/.." +git add package.json +git commit -m "chore: bump version to $TAG" +git tag "$TAG" +git push +git push --tags + +echo "Done! Released $TAG" diff --git a/package.json b/package.json index 5b7a5311..c616641b 100644 --- a/package.json +++ b/package.json @@ -1,47 +1,102 @@ { "name": "@range-security/range-sdk", - "version": "1.9.5", - "description": "SDK for easy custom alerts", - "main": "dist/src/index.js", - "types": "dist/src/index.d.ts", - "license": "MIT", - "private": false, + "version": "1.1.6", + "description": "TypeScript framework for writing blockchain alert rules", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "files": [ + "dist/**/*.js", + "dist/**/*.d.ts", + "dist/**/*.js.map", + "dist/assets/**/*", + "!dist/e2e/**", + "!dist/dev/**", + "!dist/scripts/**", + "!dist/test_data/**", + "!dist/start.*", + "!dist/benchmark.*", + "!dist/test.*" + ], "scripts": { - "build": "tsc --esModuleInterop --resolveJsonModule --declaration", - "start": "node dist/index.js", - "dev": "tsc-watch --onSuccess \"node dist/src/index.js\"", - "example": "tsc-watch --onSuccess \"node dist/examples/alertProcessors.js\"", - "pushBlock": "tsc-watch --onSuccess \"node dist/tests/pushBlock.js\"", - "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix", - "format": "prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"", - "pub": "rm -rf dist && npm run build && npm publish --access public" + "build": "rm -rf dist tsconfig.tsbuildinfo && tsc && copyfiles -u 1 \"src/assets/**/*\" dist", + "watch": "tsc -w", + "fb": "yarn fb:solana", + "fb:solana": "flatc --ts --gen-object-api -o src/flatbuffers/solana src/flatbuffers/solana/block.fbs", + "lint": "eslint \"src/**/*.ts\"", + "lint:fix": "eslint \"src/**/*.ts\" --fix", + "format": "prettier --write \"src/**/*.ts\"", + "prettier": "prettier --check \"src/**/*.ts\"", + "test:unit": "jest --testPathPatterns=src/__tests__", + "test:binary": "node dist/e2e/redis-binary-test.js", + "test:e2e": "node dist/e2e/pipeline-solana.js && node dist/e2e/pipeline-eth.js", + "test:e2e:solana": "node dist/e2e/pipeline-solana.js", + "test:e2e:solana-json": "yarn build; node dist/e2e/pipeline-solana-json.js", + "test:e2e:eth": "node dist/e2e/pipeline-eth.js", + "test:validate:solana": "node dist/e2e/validate-blocks.js src/test_data/solana", + "test:validate:eth": "node dist/e2e/validate-eth-blocks.js src/test_data/eth", + "test:validate:cosmos": "node dist/e2e/validate-cosmos-blocks.js src/test_data/osmosis-1", + "test:roundtrip": "node dist/e2e/round-trip-test.js src/test_data/solana", + "test:report": "node dist/e2e/generate-report.js", + "typecheck": "tsc --noEmit", + "prepare": "husky" }, - "devDependencies": { - "@types/mocha": "^10.0.1", - "@types/node": "^20.4.5", - "@typescript-eslint/eslint-plugin": "^6.7.2", - "@typescript-eslint/parser": "^6.7.2", - "eslint": "^8.49.0", - "eslint-config-prettier": "^9.0.0", - "eslint-plugin-prettier": "^5.0.0", - "mocha": "^10.2.0", - "prettier": "^3.0.3", - "tsc-watch": "^6.0.4", - "typescript": "^5.1.6" + "keywords": [ + "blockchain", + "alerts", + "security", + "solana", + "evm", + "cosmos", + "monitoring" + ], + "author": "Range Security", + "license": "MIT", + "publishConfig": { + "access": "public", + "registry": "https://registry.npmjs.org/" }, "dependencies": { - "@cosmjs/stargate": "^0.31.0", - "@cosmjs/tendermint-rpc": "^0.31.0", - "axios": "^1.4.0", - "dayjs": "^1.11.10", - "kafkajs": "^2.2.4", - "lru-cache": "^10.0.1", - "osmojs": "^16.14.0", - "pino": "^8.15.1", - "zod": "^3.21.4" + "@solana/web3.js": "^1.68.0", + "axios": "^1.11.0", + "commander": "^14.0.0", + "dayjs": "^1.11.13", + "dotenv": "^17.2.1", + "ethers": "^6.15.0", + "express": "^5.2.1", + "flatbuffers": "^25.2.10", + "node-cron": "^4.2.1", + "osmojs": "^16.15.0", + "piscina": "^5.1.4", + "prom-client": "^15.1.3", + "redis": "^4.6.0", + "reflect-metadata": "^0.2.2", + "winston": "^3.17.0", + "zod": "^4.0.14" + }, + "devDependencies": { + "@eslint/js": "^10.0.0", + "@types/express": "^5.0.6", + "@types/jest": "^30.0.0", + "@types/node": "^20.5.0", + "copyfiles": "^2.4.1", + "eslint": "^10.0.0", + "eslint-config-prettier": "^10.1.5", + "eslint-plugin-prettier": "^5.5.4", + "globals": "^17.0.0", + "husky": "^9.1.7", + "jest": "^30.2.0", + "lint-staged": "^16.3.2", + "prettier": "^3.6.2", + "testcontainers": "^11.12.0", + "ts-jest": "^29.4.6", + "ts-node": "^10.9.1", + "typescript": "^5.8.3", + "typescript-eslint": "^8.52.0" }, - "repository": { - "type": "git", - "url": "https://github.com/rangesecurity" + "lint-staged": { + "src/**/*.ts": [ + "eslint --fix", + "prettier --write" + ] } } diff --git a/src/__tests__/alerting-redis.test.ts b/src/__tests__/alerting-redis.test.ts new file mode 100644 index 00000000..882fe135 --- /dev/null +++ b/src/__tests__/alerting-redis.test.ts @@ -0,0 +1,73 @@ +/** + * Tests the in-memory testRedis Map path used when NODE_ENV=test. + * No real Redis connection is needed. + */ +import { + redisGet, + redisSet, + redisGetJson, + redisSetJson, + loadCache, + saveCache, +} from '../services/alerting-redis'; + +describe('alerting-redis (test env — in-memory Map)', () => { + describe('redisGet / redisSet', () => { + it('returns undefined for missing key', async () => { + const val = await redisGet('nonexistent-key-' + Date.now()); + expect(val).toBeUndefined(); + }); + + it('stores and retrieves a string value', async () => { + const key = 'test-key-' + Date.now(); + await redisSet(key, 'hello'); + const val = await redisGet(key); + expect(val).toBe('hello'); + }); + + it('overwrites existing value', async () => { + const key = 'overwrite-key-' + Date.now(); + await redisSet(key, 'first'); + await redisSet(key, 'second'); + const val = await redisGet(key); + expect(val).toBe('second'); + }); + }); + + describe('redisGetJson / redisSetJson', () => { + it('returns empty object for missing key', async () => { + const val = await redisGetJson('missing-json-' + Date.now()); + expect(val).toEqual({}); + }); + + it('stores and retrieves JSON object', async () => { + const key = 'json-key-' + Date.now(); + await redisSetJson(key, { count: 42, items: ['a', 'b'] }); + const val = await redisGetJson(key); + expect(val).toEqual({ count: 42, items: ['a', 'b'] }); + }); + }); + + describe('loadCache / saveCache', () => { + it('returns empty object when no cache exists', async () => { + const rule = { id: 'no-cache-rule-' + Date.now() } as any; + const cache = await loadCache(rule); + expect(cache).toEqual({}); + }); + + it('saves and loads cache for a rule', async () => { + const rule = { id: 'cached-rule-' + Date.now() } as any; + await saveCache(rule, { lastBlock: 100, state: 'ok' }); + const cache = await loadCache(rule); + expect(cache).toEqual({ lastBlock: 100, state: 'ok' }); + }); + + it('overwrites cache on second save', async () => { + const rule = { id: 'overwrite-cache-' + Date.now() } as any; + await saveCache(rule, { v: 1 }); + await saveCache(rule, { v: 2 }); + const cache = await loadCache(rule); + expect(cache).toEqual({ v: 2 }); + }); + }); +}); diff --git a/src/__tests__/basic.test.ts b/src/__tests__/basic.test.ts new file mode 100644 index 00000000..4625e40f --- /dev/null +++ b/src/__tests__/basic.test.ts @@ -0,0 +1,203 @@ +import { + capitalizeFirstLetter, + camelCaseToTitleCase, + safeJsonParse, + deepClone, + filterCommonAddresses, + formatAddresses, + splitAmountDenom, + getRunnerNetwork, + arraySum, + safeJsonStringify, + removeBigintFromObject, + findValuesFromAttributes, + getObjectFromAttributes, + getSenderFromMessage, +} from '../utils/basic'; + +describe('capitalizeFirstLetter', () => { + it('capitalizes first letter', () => { + expect(capitalizeFirstLetter('hello')).toBe('Hello'); + }); + it('handles empty string', () => { + expect(capitalizeFirstLetter('')).toBe(''); + }); +}); + +describe('camelCaseToTitleCase', () => { + it('converts camelCase to Title Case', () => { + expect(camelCaseToTitleCase('helloWorld')).toBe('Hello World'); + }); + it('handles single word', () => { + expect(camelCaseToTitleCase('hello')).toBe('Hello'); + }); + it('handles multiple uppercase letters', () => { + expect(camelCaseToTitleCase('myTestValue')).toBe('My Test Value'); + }); +}); + +describe('safeJsonParse', () => { + it('parses valid JSON', () => { + expect(safeJsonParse('{"a":1}')).toEqual({ a: 1 }); + }); + it('returns null for invalid JSON', () => { + expect(safeJsonParse('not json')).toBeNull(); + }); +}); + +describe('deepClone', () => { + it('creates a deep copy', () => { + const obj = { a: { b: 1 } }; + const clone = deepClone(obj); + clone.a.b = 2; + expect(obj.a.b).toBe(1); + }); +}); + +describe('filterCommonAddresses', () => { + it('returns addresses present in both arrays', () => { + expect(filterCommonAddresses(['a', 'b', 'c'], ['b', 'c', 'd'])).toEqual([ + 'b', + 'c', + ]); + }); + it('returns empty array when no overlap', () => { + expect(filterCommonAddresses(['a'], ['b'])).toEqual([]); + }); + it('handles empty arrays', () => { + expect(filterCommonAddresses([], ['b'])).toEqual([]); + }); + it('deduplicates input addresses', () => { + expect(filterCommonAddresses(['a', 'a', 'b'], ['a'])).toEqual(['a']); + }); +}); + +describe('formatAddresses', () => { + it('returns empty string for empty array', () => { + expect(formatAddresses([])).toBe(''); + }); + it('joins up to 3 addresses', () => { + expect(formatAddresses(['a', 'b', 'c'])).toBe('a, b, c'); + }); + it('truncates with count for more than 3', () => { + expect(formatAddresses(['a', 'b', 'c', 'd', 'e'])).toBe( + 'a, b, c and 2 others' + ); + }); +}); + +describe('splitAmountDenom', () => { + it('splits amount and denom', () => { + expect(splitAmountDenom('1000uosmo')).toEqual({ + amount: 1000, + denom: 'uosmo', + }); + }); + it('throws for invalid format', () => { + expect(() => splitAmountDenom('invalid')).toThrow( + 'String format is incorrect' + ); + }); +}); + +describe('getRunnerNetwork', () => { + it('extracts network from range-runner prefix', () => { + expect(getRunnerNetwork('range-runner-eth.abc123')).toBe('eth'); + }); + it('extracts network from piscina-runner prefix', () => { + expect(getRunnerNetwork('piscina-runner-solana.xyz')).toBe('solana'); + }); + it('extracts network from zerodhadow-runner prefix', () => { + expect(getRunnerNetwork('zerodhadow-runner-arb1.token')).toBe('arb1'); + }); + it('handles cosmos chain IDs', () => { + expect(getRunnerNetwork('range-runner-osmosis-1.xyz')).toBe('osmosis-1'); + }); +}); + +describe('arraySum', () => { + it('sums numbers', () => { + expect(arraySum([1, 2, 3])).toBe(6); + }); + it('returns 0 for empty array', () => { + expect(arraySum([])).toBe(0); + }); +}); + +describe('safeJsonStringify', () => { + it('stringifies regular objects', () => { + expect(safeJsonStringify({ a: 1 })).toBe('{"a":1}'); + }); + it('converts bigint to string', () => { + expect(safeJsonStringify({ val: BigInt(123) })).toBe('{"val":"123"}'); + }); +}); + +describe('removeBigintFromObject', () => { + it('converts bigints to strings', () => { + expect(removeBigintFromObject({ a: BigInt(42), b: 'hello' })).toEqual({ + a: '42', + b: 'hello', + }); + }); + it('handles nested objects', () => { + expect(removeBigintFromObject({ a: { b: BigInt(1) } })).toEqual({ + a: { b: '1' }, + }); + }); + it('handles arrays with objects containing bigints', () => { + expect( + removeBigintFromObject([{ a: BigInt(1) }, { b: BigInt(2) }]) + ).toEqual([{ a: '1' }, { b: '2' }]); + }); + it('returns primitives as-is', () => { + expect(removeBigintFromObject(null)).toBeNull(); + expect(removeBigintFromObject(42)).toBe(42); + }); +}); + +describe('findValuesFromAttributes', () => { + const attrs = [ + { key: 'sender', value: 'alice' }, + { key: 'receiver', value: 'bob' }, + { key: 'amount', value: '100' }, + ]; + + it('returns values for requested keys', () => { + expect(findValuesFromAttributes(attrs, ['sender', 'amount'])).toEqual({ + sender: 'alice', + amount: '100', + }); + }); + it('returns null for null attributes', () => { + expect(findValuesFromAttributes(null, ['sender'])).toBeNull(); + }); +}); + +describe('getObjectFromAttributes', () => { + it('converts attributes array to object', () => { + const attrs = [ + { key: 'a', value: '1' }, + { key: 'b', value: '2' }, + ]; + expect(getObjectFromAttributes(attrs)).toEqual({ a: '1', b: '2' }); + }); + it('returns null for null input', () => { + expect(getObjectFromAttributes(null)).toBeNull(); + }); +}); + +describe('getSenderFromMessage', () => { + it('finds sender from events', () => { + const msg = { + events: [{ attributes: [{ key: 'sender', value: 'alice' }] }], + }; + expect(getSenderFromMessage(msg)).toBe('alice'); + }); + it('returns null when no sender', () => { + const msg = { + events: [{ attributes: [{ key: 'receiver', value: 'bob' }] }], + }; + expect(getSenderFromMessage(msg)).toBeNull(); + }); +}); diff --git a/src/__tests__/extractBlockMeta.test.ts b/src/__tests__/extractBlockMeta.test.ts new file mode 100644 index 00000000..121d829a --- /dev/null +++ b/src/__tests__/extractBlockMeta.test.ts @@ -0,0 +1,100 @@ +jest.mock('../wrappers/solana-block-wrapper', () => ({ + SolanaBlockWrapper: jest.fn(), + createSolanaBlockFromJson: jest.fn(), +})); + +import { extractBlockMeta } from '../processors/taskProcessor'; + +describe('extractBlockMeta', () => { + describe('normalized blocks (Solana/Cosmos)', () => { + it('extracts from block with top-level height/network/timestamp', () => { + const meta = extractBlockMeta({ + height: 12345, + network: 'solana', + timestamp: '2024-01-01T00:00:00Z', + }); + expect(meta).toEqual({ + height: '12345', + network: 'solana', + timestamp: '2024-01-01T00:00:00Z', + }); + }); + + it('coerces numeric height to string', () => { + const meta = extractBlockMeta({ + height: 999, + network: 'osmosis-1', + timestamp: '2024-06-15T12:00:00Z', + }); + expect(meta.height).toBe('999'); + }); + + it('handles missing timestamp gracefully', () => { + const meta = extractBlockMeta({ + height: 1, + network: 'eth', + timestamp: undefined, + }); + expect(meta.timestamp).toBe(''); + }); + }); + + describe('EVM blocks (hex-encoded)', () => { + it('parses hex height and timestamp from block.block.result', () => { + const meta = extractBlockMeta({ + block: { + result: { + number: '0x1a4', // 420 + timestamp: '0x65b0c800', // 2024-01-24T00:00:00Z (approx) + }, + }, + chain_id: 1, + }); + expect(meta.height).toBe('420'); + expect(meta.network).toBe('1'); + }); + + it('handles missing timestamp in EVM block', () => { + const meta = extractBlockMeta({ + block: { + result: { + number: '0xa', + }, + }, + }); + expect(meta.height).toBe('10'); + expect(meta.timestamp).toBe('undefined'); + }); + + it('uses chain_id as network string', () => { + const meta = extractBlockMeta({ + block: { + result: { + number: '0x1', + }, + }, + chain_id: 56, + }); + expect(meta.network).toBe('56'); + }); + }); + + describe('fallback (unknown format)', () => { + it('falls back to raw values when no recognized format', () => { + const meta = extractBlockMeta({ + height: 42, + timestamp: 'some-ts', + }); + // No network → not the first branch, no block.result → not EVM, falls to default + expect(meta.height).toBe('42'); + expect(meta.timestamp).toBe('some-ts'); + expect(meta.network).toBe(''); + }); + + it('handles completely empty block', () => { + const meta = extractBlockMeta({}); + expect(meta.height).toBe('0'); + expect(meta.network).toBe(''); + }); + }); +}); diff --git a/src/__tests__/fill-findings.test.ts b/src/__tests__/fill-findings.test.ts new file mode 100644 index 00000000..284b2106 --- /dev/null +++ b/src/__tests__/fill-findings.test.ts @@ -0,0 +1,28 @@ +import { fillFindings } from '../utils/fill-findings'; + +describe('fillFindings', () => { + it('replaces template variables', () => { + const result = fillFindings('Hello {{name}}, you have {{count}} items', { + name: 'Alice', + count: '3', + }); + expect(result).toBe('Hello Alice, you have 3 items'); + }); + + it('replaces missing variables with "unknown"', () => { + const result = fillFindings('{{a}} and {{b}}', { a: 'yes' }); + expect(result).toBe('yes and unknown'); + }); + + it('returns template unchanged when no variables', () => { + expect(fillFindings('no vars here', {})).toBe('no vars here'); + }); + + it('handles empty template', () => { + expect(fillFindings('', { a: 'b' })).toBe(''); + }); + + it('replaces multiple occurrences of same variable', () => { + expect(fillFindings('{{x}} and {{x}}', { x: 'hi' })).toBe('hi and hi'); + }); +}); diff --git a/src/__tests__/number-fmt.test.ts b/src/__tests__/number-fmt.test.ts new file mode 100644 index 00000000..3d31c306 --- /dev/null +++ b/src/__tests__/number-fmt.test.ts @@ -0,0 +1,73 @@ +import { + secToHumanReadable, + fmtMsgType, + fmtSec, + fmtMin, + format, +} from '../utils/number-fmt'; + +describe('format (number formatting)', () => { + it('formats 0', () => { + expect(format(0)).toBe('0'); + }); + it('formats small numbers', () => { + expect(format(42)).toBe('42'); + expect(format(999.99)).toBe('999.99'); + }); + it('formats thousands as K', () => { + expect(format(1500)).toBe('1.5K'); + expect(format(50000)).toBe('50K'); + }); + it('formats millions as M', () => { + expect(format(1_500_000)).toBe('1.5M'); + }); + it('formats billions as B', () => { + expect(format(2_500_000_000)).toBe('2.5B'); + }); + it('formats trillions as T', () => { + expect(format(1_000_000_000_000)).toBe('1T'); + }); + it('formats negative numbers', () => { + expect(format(-1500)).toBe('-1.5K'); + }); + it('formats very small numbers as ~0', () => { + expect(format(0.0000001)).toBe('~0'); + }); + it('formats very large numbers in scientific notation', () => { + const result = format(1e16); + expect(result).toMatch(/e\+/); + }); +}); + +describe('secToHumanReadable', () => { + it('formats seconds', () => { + expect(secToHumanReadable(30, 'second')).toBe('30 seconds'); + }); + it('formats minutes', () => { + expect(secToHumanReadable(90, 'second')).toBe('1 minute 30 seconds'); + }); + it('formats hours', () => { + expect(secToHumanReadable(3661, 'second')).toBe('1 hour 1 minute 1 second'); + }); +}); + +describe('fmtMsgType', () => { + it('formats cosmos message type', () => { + expect(fmtMsgType('cosmos.gov.v1.MsgVote')).toBe('MsgVote(cosmos)'); + }); + it('handles simple type', () => { + expect(fmtMsgType('transfer')).toBe('transfer(transfer)'); + }); +}); + +describe('fmtSec', () => { + it('delegates to secToHumanReadable with seconds', () => { + expect(fmtSec(60)).toBe('1 minute'); + }); +}); + +describe('fmtMin', () => { + it('delegates to secToHumanReadable with minutes', () => { + expect(fmtMin(60)).toBe('1 hour'); + }); +}); diff --git a/src/__tests__/process-task.test.ts b/src/__tests__/process-task.test.ts new file mode 100644 index 00000000..a79c1205 --- /dev/null +++ b/src/__tests__/process-task.test.ts @@ -0,0 +1,196 @@ +import 'reflect-metadata'; +import { + ProcessorRegistry, + BlockProcessor, + TickProcessor, + IBlockProcessor, + ITickProcessor, +} from '../utils/processor'; +import { ISubEvent } from '../types/IEvent'; +import { ITask } from '../types/ITask'; + +// Mock heavy dependencies to avoid pulling in flatbuffers/redis/etc +jest.mock('../services/AssetManager', () => ({ + initAssetService: jest.fn().mockResolvedValue(undefined), +})); +jest.mock('../wrappers/solana-block-wrapper', () => ({ + SolanaBlockWrapper: jest.fn(), +})); +jest.mock('./../../src/processors/processors', () => ({})); + +// Import after mocks are set up +import { processTask } from '../processors/index'; + +beforeEach(() => { + (ProcessorRegistry as any).processorMap = new Map(); +}); + +class MockBlockProcessor extends BlockProcessor { + async callback({ rule, block }: IBlockProcessor): Promise { + return [ + { + caption: `Block ${block.height}`, + details: { message: `Processed block ${block.height}` }, + txHash: 'tx123', + addressesInvolved: ['addr1'], + }, + ]; + } +} + +class MockTickProcessor extends TickProcessor { + async callback({ rule, timestamp }: ITickProcessor): Promise { + return [ + { + caption: 'Tick event', + details: { message: `Tick at ${timestamp}` }, + }, + ]; + } +} + +function makeBlockTask(ruleType: string, blockData: object): ITask { + const json = JSON.stringify(blockData); + const encoded = new TextEncoder().encode(json); + const sab = new SharedArrayBuffer(encoded.length); + new Uint8Array(sab).set(encoded); + + return { + alertRule: { + id: 'rule-1', + ruleType, + network: 'eth', + parameters: {}, + createdAt: new Date().toISOString(), + triggerMode: 'BLOCK', + }, + blockInfo: { network: 'eth', height: '100', time: '2024-01-01T00:00:00Z' }, + sharedBuffer: sab, + sharedBufferLength: encoded.length, + flatBuffer: false, + processorsFile: 'unused', + }; +} + +function makeTickTask(ruleType: string): ITask { + return { + alertRule: { + id: 'rule-2', + ruleType, + network: 'osmosis-1', + parameters: {}, + createdAt: new Date().toISOString(), + triggerMode: 'TICK', + }, + tickInfo: { time: '2024-01-01T00:00:00Z' }, + processorsFile: 'unused', + }; +} + +describe('processTask', () => { + it('throws for unknown rule type', async () => { + const task = makeBlockTask('nonexistent', { height: 1 }); + await expect(processTask(task)).rejects.toThrow( + 'Unknown rule type: nonexistent' + ); + }); + + it('processes a block task', async () => { + ProcessorRegistry.register( + { + type: 'mock-block', + label: 'Mock', + description: '', + parameters: [], + networks: ['eth'], + tags: ['security'], + }, + MockBlockProcessor + ); + + const task = makeBlockTask('mock-block', { height: 100, transactions: [] }); + const events = await processTask(task); + + expect(events).toHaveLength(1); + expect(events[0].caption).toBe('Block 100'); + expect(events[0].alertRuleId).toBe('rule-1'); + expect(events[0].network).toBe('eth'); + expect(events[0].blockNumber).toBe('100'); + expect(events[0].txHash).toBe('tx123'); + expect(events[0].addressesInvolved).toEqual(['addr1']); + expect(events[0].id).toBeDefined(); // UUID generated + }); + + it('processes a tick task', async () => { + ProcessorRegistry.register( + { + type: 'mock-tick', + label: 'Mock', + description: '', + parameters: [], + networks: ['eth'], + tags: ['security'], + }, + MockTickProcessor + ); + + const task = makeTickTask('mock-tick'); + const events = await processTask(task); + + expect(events).toHaveLength(1); + expect(events[0].caption).toBe('Tick event'); + expect(events[0].alertRuleId).toBe('rule-2'); + expect(events[0].time).toBe('2024-01-01T00:00:00Z'); + }); + + it('throws for task with neither blockInfo nor tickInfo', async () => { + ProcessorRegistry.register( + { + type: 'mock', + label: 'Mock', + description: '', + parameters: [], + networks: ['eth'], + tags: ['security'], + }, + MockBlockProcessor + ); + + const task: ITask = { + alertRule: { + id: 'rule-3', + ruleType: 'mock', + network: 'eth', + parameters: {}, + createdAt: new Date().toISOString(), + triggerMode: 'BLOCK', + }, + processorsFile: 'unused', + }; + + await expect(processTask(task)).rejects.toThrow('Invalid task type'); + }); + + it('generates deterministic event IDs', async () => { + ProcessorRegistry.register( + { + type: 'det-test', + label: 'Det', + description: '', + parameters: [], + networks: ['eth'], + tags: ['security'], + }, + MockBlockProcessor + ); + + const task1 = makeBlockTask('det-test', { height: 100 }); + const task2 = makeBlockTask('det-test', { height: 100 }); + + const events1 = await processTask(task1); + const events2 = await processTask(task2); + + // Same input = same UUID (deterministic via MD5) + expect(events1[0].id).toBe(events2[0].id); + }); +}); diff --git a/src/__tests__/processor-registry.test.ts b/src/__tests__/processor-registry.test.ts new file mode 100644 index 00000000..c65ad3b9 --- /dev/null +++ b/src/__tests__/processor-registry.test.ts @@ -0,0 +1,188 @@ +import 'reflect-metadata'; +import { + BlockProcessor, + TickProcessor, + ProcessorRegistry, + IBlockProcessor, + ITickProcessor, +} from '../utils/processor'; +import { ISubEvent } from '../types/IEvent'; + +// Reset registry between tests +beforeEach(() => { + (ProcessorRegistry as any).processorMap = new Map(); +}); + +class TestBlockProcessor extends BlockProcessor { + async callback({ rule, block }: IBlockProcessor): Promise { + return []; + } +} + +class TestTickProcessor extends TickProcessor { + async callback({ rule, timestamp }: ITickProcessor): Promise { + return [{ caption: 'tick', details: { message: 'tick fired' } }]; + } +} + +describe('ProcessorRegistry', () => { + describe('register + get', () => { + it('registers and retrieves a block processor', () => { + ProcessorRegistry.register( + { + type: 'test-block', + label: 'Test', + description: '', + parameters: [], + tags: ['security'], + networks: ['eth'], + }, + TestBlockProcessor + ); + const info = ProcessorRegistry.get('test-block'); + expect(info).toBeDefined(); + expect(info!.rule.type).toBe('test-block'); + expect(info!.instance.taskType).toBe('BLOCK'); + }); + + it('registers and retrieves a tick processor', () => { + ProcessorRegistry.register( + { + type: 'test-tick', + label: 'Test', + description: '', + parameters: [], + tags: ['security'], + networks: ['eth'], + }, + TestTickProcessor + ); + const info = ProcessorRegistry.get('test-tick'); + expect(info).toBeDefined(); + expect(info!.instance.taskType).toBe('TICK'); + }); + + it('returns undefined for unknown rule type', () => { + expect(ProcessorRegistry.get('nonexistent')).toBeUndefined(); + }); + + it('throws on duplicate rule type', () => { + ProcessorRegistry.register( + { + type: 'dup', + label: 'First', + description: '', + parameters: [], + tags: ['security'], + networks: ['eth'], + }, + TestBlockProcessor + ); + expect(() => + ProcessorRegistry.register( + { + type: 'dup', + label: 'Second', + description: '', + parameters: [], + tags: ['security'], + networks: ['eth'], + }, + TestTickProcessor + ) + ).toThrow('duplicate rule type "dup"'); + }); + + it('throws when networks is missing or empty', () => { + expect(() => + ProcessorRegistry.register( + { + type: 'no-networks', + label: 'No Networks', + description: '', + parameters: [], + tags: ['security'], + networks: [], + }, + TestBlockProcessor + ) + ).toThrow('must specify at least one network'); + + expect(() => + ProcessorRegistry.register( + { + type: 'no-networks-2', + label: 'No Networks', + description: '', + parameters: [], + tags: ['security'], + } as any, + TestBlockProcessor + ) + ).toThrow('must specify at least one network'); + }); + }); + + describe('getAlertTemplates', () => { + beforeEach(() => { + ProcessorRegistry.register( + { + type: 'solana-rule', + label: 'Solana Rule', + description: '', + parameters: [], + tags: ['solana'], + networks: ['solana'], + }, + TestBlockProcessor + ); + ProcessorRegistry.register( + { + type: 'eth-rule', + label: 'ETH Rule', + description: '', + parameters: [], + tags: ['security'], + networks: ['eth'], + }, + TestBlockProcessor + ); + ProcessorRegistry.register( + { + type: 'multi-rule', + label: 'Multi Network', + description: '', + parameters: [], + tags: ['security'], + networks: ['eth', 'solana'], + }, + TestTickProcessor + ); + }); + + it('returns all templates when no network filter', () => { + const templates = ProcessorRegistry.getAlertTemplates(); + expect(templates.size).toBe(3); + }); + + it('filters by network', () => { + const templates = ProcessorRegistry.getAlertTemplates('solana'); + expect(templates.size).toBe(2); // solana-rule + multi-rule + expect(templates.has('solana-rule')).toBe(true); + expect(templates.has('multi-rule')).toBe(true); + expect(templates.has('eth-rule')).toBe(false); + }); + + it('sets default severity to info', () => { + const templates = ProcessorRegistry.getAlertTemplates(); + const rule = templates.get('solana-rule'); + expect(rule!.severity).toBe('info'); + }); + + it('sets trigger from instance taskType', () => { + const templates = ProcessorRegistry.getAlertTemplates(); + expect(templates.get('solana-rule')!.trigger).toBe('BLOCK'); + expect(templates.get('multi-rule')!.trigger).toBe('TICK'); + }); + }); +}); diff --git a/src/__tests__/processor-validation.test.ts b/src/__tests__/processor-validation.test.ts new file mode 100644 index 00000000..31257e94 --- /dev/null +++ b/src/__tests__/processor-validation.test.ts @@ -0,0 +1,150 @@ +import 'reflect-metadata'; +import { + BlockProcessor, + TickProcessor, + ProcessorRegistry, + IBlockProcessor, + ITickProcessor, +} from '../utils/processor'; +import { ISubEvent } from '../types/IEvent'; + +beforeEach(() => { + (ProcessorRegistry as any).processorMap = new Map(); +}); + +class ValidBlockProcessor extends BlockProcessor { + async callback({ rule, block }: IBlockProcessor): Promise { + return []; + } +} + +describe('ProcessorRegistry validation', () => { + it('throws on empty rule type', () => { + expect(() => + ProcessorRegistry.register( + { + type: '', + label: 'Bad', + description: '', + parameters: [], + networks: ['eth'], + tags: ['security'], + }, + ValidBlockProcessor + ) + ).toThrow('rule.type must be a non-empty string'); + }); + + it('throws on whitespace-only rule type', () => { + expect(() => + ProcessorRegistry.register( + { + type: ' ', + label: 'Bad', + description: '', + parameters: [], + networks: ['eth'], + tags: ['security'], + }, + ValidBlockProcessor + ) + ).toThrow('rule.type must be a non-empty string'); + }); + + it('throws on duplicate rule type', () => { + ProcessorRegistry.register( + { + type: 'my-rule', + label: 'First', + description: '', + parameters: [], + networks: ['eth'], + tags: ['security'], + }, + ValidBlockProcessor + ); + expect(() => + ProcessorRegistry.register( + { + type: 'my-rule', + label: 'Second', + description: '', + parameters: [], + networks: ['eth'], + tags: ['security'], + }, + ValidBlockProcessor + ) + ).toThrow('duplicate rule type "my-rule"'); + }); + + it('throws when class lacks callback or taskType', () => { + class BadProcessor {} + expect(() => + ProcessorRegistry.register( + { + type: 'bad', + label: 'Bad', + description: '', + parameters: [], + networks: ['eth'], + tags: ['security'], + }, + BadProcessor as any + ) + ).toThrow('must extend BlockProcessor or TickProcessor'); + }); + + it('warns on duplicate parameter fields', () => { + const warnSpy = jest.spyOn(console, 'warn').mockImplementation(); + ProcessorRegistry.register( + { + type: 'dup-params', + label: 'Dup Params', + description: '', + parameters: [ + { + field: 'addr', + label: 'Addr 1', + fieldType: 'Address', + description: '', + }, + { + field: 'addr', + label: 'Addr 2', + fieldType: 'Address', + description: '', + }, + ], + networks: ['eth'], + tags: ['security'], + }, + ValidBlockProcessor + ); + expect(warnSpy).toHaveBeenCalledWith( + expect.stringContaining('duplicate parameter fields: addr') + ); + warnSpy.mockRestore(); + }); + + it('allows valid registration without warnings', () => { + const warnSpy = jest.spyOn(console, 'warn').mockImplementation(); + ProcessorRegistry.register( + { + type: 'valid-rule', + label: 'Valid', + description: '', + parameters: [ + { field: 'a', label: 'A', fieldType: 'Number', description: '' }, + { field: 'b', label: 'B', fieldType: 'Text', description: '' }, + ], + networks: ['eth'], + tags: ['security'], + }, + ValidBlockProcessor + ); + expect(warnSpy).not.toHaveBeenCalled(); + expect(ProcessorRegistry.get('valid-rule')).toBeDefined(); + warnSpy.mockRestore(); + }); +}); diff --git a/src/__tests__/redis-keys.test.ts b/src/__tests__/redis-keys.test.ts new file mode 100644 index 00000000..6667fb90 --- /dev/null +++ b/src/__tests__/redis-keys.test.ts @@ -0,0 +1,27 @@ +import { RedisKeys } from '../services/redis-keys'; + +describe('RedisKeys', () => { + it('generates alert rule cache key', () => { + expect(RedisKeys.alertRuleCacheKey({ id: 'rule-123' })).toBe( + 'rule-cache:rule-123' + ); + }); + + it('generates cached function key', () => { + expect(RedisKeys.getCachedFunctionKey('myFunc')).toBe( + 'cached:function:{myFunc}' + ); + }); + + it('generates bg aggregation key', () => { + expect(RedisKeys.getBgAggregationKey('volume')).toBe( + 'bg:aggregation:volume' + ); + }); + + it('generates program IDL key', () => { + expect(RedisKeys.getProgramIdlKey('11111111111111111111111111111111')).toBe( + 'solanafm:idl:11111111111111111111111111111111' + ); + }); +}); diff --git a/src/__tests__/skip-tick.test.ts b/src/__tests__/skip-tick.test.ts new file mode 100644 index 00000000..4a11d055 --- /dev/null +++ b/src/__tests__/skip-tick.test.ts @@ -0,0 +1,25 @@ +import { skipTick } from '../utils/skip-tick'; + +// NODE_ENV=test → skipTick always returns false in test env +describe('skipTick (test env)', () => { + it('always returns false in test environment', () => { + const result = skipTick({ + timestamp: new Date().toISOString(), + ticker: 30, + salt: 'rule-123', + }); + expect(result).toBe(false); + }); + + it('returns false regardless of threshold', () => { + // Even with an old timestamp that would normally be skipped + const oldTimestamp = new Date(Date.now() - 120 * 60 * 1000).toISOString(); // 2 hours ago + const result = skipTick({ + timestamp: oldTimestamp, + ticker: 30, + threshold: 60, + salt: 'any-salt', + }); + expect(result).toBe(false); + }); +}); diff --git a/src/__tests__/testing-helpers.test.ts b/src/__tests__/testing-helpers.test.ts new file mode 100644 index 00000000..52c956ab --- /dev/null +++ b/src/__tests__/testing-helpers.test.ts @@ -0,0 +1,47 @@ +import { createNewAlertRule, getTestTimestamp } from '../utils/testing-helpers'; + +describe('createNewAlertRule', () => { + it('creates a rule with defaults', () => { + const rule = createNewAlertRule({ ruleType: 'test-rule' }); + expect(rule.ruleType).toBe('test-rule'); + expect(rule.id).toBeDefined(); + expect(rule.network).toBe('osmosis-1'); + expect(rule.severity).toBe('debug'); + expect(rule.triggerMode).toBe('BLOCK'); + expect(rule.parameters).toEqual({}); + }); + + it('throws when ruleType is missing', () => { + expect(() => createNewAlertRule({ ruleType: '' })).toThrow( + 'You forget to set ruleType' + ); + }); + + it('allows overriding defaults', () => { + const rule = createNewAlertRule({ + ruleType: 'custom', + network: 'solana', + severity: 'high', + parameters: { threshold: 10 }, + }); + expect(rule.network).toBe('solana'); + expect(rule.severity).toBe('high'); + expect(rule.parameters.threshold).toBe(10); + }); +}); + +describe('getTestTimestamp', () => { + it('returns ISO string', () => { + const ts = getTestTimestamp(); + expect(new Date(ts).toISOString()).toBe(ts); + }); + + it('adds hours offset', () => { + const now = new Date(); + const ts = getTestTimestamp(1); + const diff = new Date(ts).getTime() - now.getTime(); + // Should be roughly 1 hour (allow 5 second tolerance) + expect(diff).toBeGreaterThan(3595000); + expect(diff).toBeLessThan(3605000); + }); +}); diff --git a/src/__tests__/validParam.test.ts b/src/__tests__/validParam.test.ts new file mode 100644 index 00000000..0549ceaf --- /dev/null +++ b/src/__tests__/validParam.test.ts @@ -0,0 +1,98 @@ +import { + validParam, + invalidParam, + validGreaterThan, + invalidGreaterThan, + validSubString, + isSmallerThan, + isNotSmallerThan, +} from '../utils/validParam'; + +describe('validParam', () => { + it('returns true when ruleParam is undefined', () => { + expect(validParam('anything', undefined)).toBe(true); + }); + + it('matches string to string', () => { + expect(validParam('alice', 'alice')).toBe(true); + expect(validParam('alice', 'bob')).toBe(false); + }); + + it('checks if string input is in array ruleParam', () => { + expect(validParam('alice', ['alice', 'bob'])).toBe(true); + expect(validParam('charlie', ['alice', 'bob'])).toBe(false); + }); + + it('returns true for empty array ruleParam', () => { + expect(validParam('anything', [])).toBe(true); + }); + + it('checks if array input contains string ruleParam', () => { + expect(validParam(['alice', 'bob'], 'alice')).toBe(true); + expect(validParam(['alice', 'bob'], 'charlie')).toBe(false); + }); + + it('checks overlap between two arrays', () => { + expect(validParam(['a', 'b'], ['b', 'c'])).toBe(true); + expect(validParam(['a', 'b'], ['c', 'd'])).toBe(false); + }); + + it('returns true for empty ruleParam array with array input', () => { + expect(validParam(['a'], [])).toBe(true); + }); +}); + +describe('invalidParam', () => { + it('negates validParam', () => { + expect(invalidParam('alice', 'alice')).toBe(false); + expect(invalidParam('alice', 'bob')).toBe(true); + }); +}); + +describe('validGreaterThan', () => { + it('returns true when threshold is undefined', () => { + expect(validGreaterThan(5, undefined)).toBe(true); + }); + it('compares numbers', () => { + expect(validGreaterThan(10, 5)).toBe(true); + expect(validGreaterThan(5, 10)).toBe(false); + expect(validGreaterThan(5, 5)).toBe(false); + }); + it('handles string inputs', () => { + expect(validGreaterThan('10', '5')).toBe(true); + }); +}); + +describe('invalidGreaterThan', () => { + it('negates validGreaterThan', () => { + expect(invalidGreaterThan(10, 5)).toBe(false); + expect(invalidGreaterThan(5, 10)).toBe(true); + }); +}); + +describe('validSubString', () => { + it('returns true when param is falsy', () => { + expect(validSubString('hello', undefined)).toBe(true); + }); + it('checks substring', () => { + expect(validSubString('hello world', 'world')).toBe(true); + expect(validSubString('hello', 'world')).toBe(false); + }); +}); + +describe('isSmallerThan', () => { + it('returns true when threshold is undefined', () => { + expect(isSmallerThan(5, undefined)).toBe(true); + }); + it('compares numbers', () => { + expect(isSmallerThan(5, 10)).toBe(true); + expect(isSmallerThan(10, 5)).toBe(false); + }); +}); + +describe('isNotSmallerThan', () => { + it('negates isSmallerThan', () => { + expect(isNotSmallerThan(5, 10)).toBe(false); + expect(isNotSmallerThan(10, 5)).toBe(true); + }); +}); diff --git a/src/__tests__/validateParameters.test.ts b/src/__tests__/validateParameters.test.ts new file mode 100644 index 00000000..ba7192e8 --- /dev/null +++ b/src/__tests__/validateParameters.test.ts @@ -0,0 +1,98 @@ +import 'reflect-metadata'; +import { ValidateParameters } from '../utils/validateParameters'; +import { BlockProcessor, IBlockProcessor } from '../utils/processor'; +import { ISubEvent } from '../types/IEvent'; + +describe('ValidateParameters decorator', () => { + it('throws when rule is missing from args', () => { + class TestProcessor extends BlockProcessor { + @ValidateParameters() + async callback(ctx: IBlockProcessor): Promise { + return []; + } + } + // Attach rule metadata (simulating @Rule decorator) + (TestProcessor.prototype as any).__rule = { + type: 'test', + parameters: [], + }; + + const proc = new TestProcessor(); + expect(() => proc.callback({} as any)).toThrow('Rule is required'); + }); + + it('injects validated params into context', async () => { + let capturedParams: any; + class TestProcessor extends BlockProcessor { + @ValidateParameters() + async callback(ctx: IBlockProcessor): Promise { + capturedParams = (ctx as any).params; + return []; + } + } + (TestProcessor.prototype as any).__rule = { + type: 'test', + parameters: [ + { field: 'threshold', fieldType: 'Number', optional: false }, + ], + }; + + const proc = new TestProcessor(); + await proc.callback({ + rule: { parameters: { threshold: 10 } }, + block: {}, + } as any); + + expect(capturedParams).toEqual({ threshold: 10 }); + }); + + it('throws for missing required field', () => { + class TestProcessor extends BlockProcessor { + @ValidateParameters() + async callback(ctx: IBlockProcessor): Promise { + return []; + } + } + (TestProcessor.prototype as any).__rule = { + type: 'test', + parameters: [ + { field: 'required_field', fieldType: 'Text', optional: false }, + ], + }; + + const proc = new TestProcessor(); + expect(() => + proc.callback({ + rule: { parameters: {} }, + block: {}, + } as any) + ).toThrow('Missing required field required_field'); + }); + + it('skips optional undefined fields', async () => { + let capturedParams: any; + class TestProcessor extends BlockProcessor { + @ValidateParameters() + async callback(ctx: IBlockProcessor): Promise { + capturedParams = (ctx as any).params; + return []; + } + } + (TestProcessor.prototype as any).__rule = { + type: 'test', + parameters: [ + { field: 'opt', fieldType: 'Text', optional: true }, + { field: 'req', fieldType: 'Text', optional: false }, + ], + }; + + const proc = new TestProcessor(); + await proc.callback({ + rule: { parameters: { req: 'hello' } }, + block: {}, + } as any); + + expect(capturedParams).toEqual({ req: 'hello' }); + expect(capturedParams.opt).toBeUndefined(); + }); +}); diff --git a/src/benchmarking/mtt-bottleneck.spec.ts b/src/benchmarking/mtt-bottleneck.spec.ts new file mode 100644 index 00000000..b6202b94 --- /dev/null +++ b/src/benchmarking/mtt-bottleneck.spec.ts @@ -0,0 +1,650 @@ +import { initPool, runTask, closePool, pool } from './../threadpool/pool'; +import { join } from 'path'; +import { getCachedBlock, createNewAlertRule } from './../utils/testing-helpers'; +import { processPayload } from './../processors/taskProcessor'; +import { IAlertRule } from './../types/IAlertRule'; + +/** + * MTT Bottleneck Analysis Tests + * + * These tests isolate and measure specific components to identify bottlenecks: + * - FlatBuffer serialization overhead + * - SharedArrayBuffer allocation and transfer + * - Worker communication overhead + * - Pool task distribution efficiency + * - Stats service file I/O impact + */ + +interface ComponentTimings { + serialization: number; + bufferAllocation: number; + taskExecution: number; + resultProcessing: number; +} + +class BottleneckAnalyzer { + private timings: Map = new Map(); + + recordTiming(component: string, duration: number) { + if (!this.timings.has(component)) { + this.timings.set(component, []); + } + this.timings.get(component)!.push(duration); + } + + getStats(component: string) { + const values = this.timings.get(component) || []; + if (values.length === 0) return null; + + const sorted = [...values].sort((a, b) => a - b); + const sum = values.reduce((a, b) => a + b, 0); + + return { + count: values.length, + min: sorted[0], + max: sorted[sorted.length - 1], + avg: sum / values.length, + p50: sorted[Math.floor(sorted.length * 0.5)], + p95: sorted[Math.floor(sorted.length * 0.95)], + p99: sorted[Math.floor(sorted.length * 0.99)], + total: sum, + }; + } + + printReport() { + console.log('\n' + '='.repeat(70)); + console.log('BOTTLENECK ANALYSIS REPORT'); + console.log('='.repeat(70)); + + const components = Array.from(this.timings.keys()).sort(); + + for (const component of components) { + const stats = this.getStats(component); + if (!stats) continue; + + console.log(`\n${component}:`); + console.log(` Samples: ${stats.count}`); + console.log(` Total Time: ${stats.total.toFixed(2)}ms`); + console.log( + ` Min/Avg/Max: ${stats.min.toFixed(2)}ms / ${stats.avg.toFixed(2)}ms / ${stats.max.toFixed(2)}ms` + ); + console.log( + ` P50/P95/P99: ${stats.p50.toFixed(2)}ms / ${stats.p95.toFixed(2)}ms / ${stats.p99.toFixed(2)}ms` + ); + } + + // Calculate total overhead + const totalComponents = components + .filter((c) => !c.includes('Total')) + .map((c) => this.getStats(c)!.total) + .reduce((a, b) => a + b, 0); + + const totalStats = this.getStats('Total Execution'); + if (totalStats) { + const overhead = + ((totalComponents - totalStats.total) / totalStats.total) * 100; + console.log(`\nOverhead Analysis:`); + console.log(` Component Sum: ${totalComponents.toFixed(2)}ms`); + console.log(` Total Execution: ${totalStats.total.toFixed(2)}ms`); + console.log(` Framework Overhead: ${overhead.toFixed(2)}%`); + } + + console.log('\n' + '='.repeat(70) + '\n'); + } + + getBottlenecks(): string[] { + const bottlenecks: string[] = []; + const componentStats = Array.from(this.timings.keys()) + .map((component) => ({ + component, + stats: this.getStats(component)!, + })) + .filter(({ stats }) => stats !== null); + + // Find components that take >20% of total time + const totalTime = componentStats.reduce( + (sum, { stats }) => sum + stats.total, + 0 + ); + + for (const { component, stats } of componentStats) { + const percentage = (stats.total / totalTime) * 100; + if (percentage > 20) { + bottlenecks.push( + `${component} (${percentage.toFixed(1)}% of total time)` + ); + } + } + + return bottlenecks; + } +} + +describe('MTT Bottleneck Analysis', () => { + beforeAll(async () => { + await initPool({ + filename: join(__dirname, '../dist/threadpool/worker.js'), + maxThreads: 8, + concurrentTasksPerWorker: 1, + }); + }); + + afterAll(async () => { + await closePool(); + }); + + describe('Component Timing Analysis', () => { + it('should measure FlatBuffer serialization overhead', async () => { + const analyzer = new BottleneckAnalyzer(); + const iterations = 100; + + const block = await getCachedBlock('solana', '348694694'); + + for (let i = 0; i < iterations; i++) { + const serStart = Date.now(); + const encoded = new TextEncoder().encode(JSON.stringify(block)); + const serEnd = Date.now(); + + analyzer.recordTiming('JSON Serialization', serEnd - serStart); + + // Also measure allocation + const allocStart = Date.now(); + const sharedBuffer = new SharedArrayBuffer(encoded.length); + new Uint8Array(sharedBuffer).set(encoded); + const allocEnd = Date.now(); + + analyzer.recordTiming( + 'SharedArrayBuffer Allocation', + allocEnd - allocStart + ); + } + + analyzer.printReport(); + + const serStats = analyzer.getStats('JSON Serialization'); + const allocStats = analyzer.getStats('SharedArrayBuffer Allocation'); + + console.log( + `\nSerialization is ${((serStats!.avg / allocStats!.avg) * 100).toFixed(0)}% of total buffer prep time` + ); + + expect(serStats!.avg).toBeLessThan(100); // Serialization should be fast + expect(allocStats!.avg).toBeLessThan(50); // Allocation should be fast + }); + + it('should measure end-to-end task execution breakdown', async () => { + const analyzer = new BottleneckAnalyzer(); + const iterations = 50; + + for (let i = 0; i < iterations; i++) { + const totalStart = Date.now(); + + // 1. Block loading (simulated - already cached) + const loadStart = Date.now(); + const block = await getCachedBlock('solana', '348694694'); + const loadEnd = Date.now(); + analyzer.recordTiming('1. Block Loading', loadEnd - loadStart); + + // 2. Serialization + const serStart = Date.now(); + const encoded = new TextEncoder().encode(JSON.stringify(block)); + const sharedBuffer = new SharedArrayBuffer(encoded.length); + new Uint8Array(sharedBuffer).set(encoded); + const serEnd = Date.now(); + analyzer.recordTiming( + '2. Serialization + Buffer Prep', + serEnd - serStart + ); + + const blockInfo = { + height: String(block.height), + network: String(block.network), + time: String(block.timestamp), + }; + + // 3. Task submission + const taskStart = Date.now(); + const rule = createNewAlertRule({ + ruleType: 'EmptyRule', + id: `timing-${i}`, + }); + + const taskPromise = runTask({ + alertRule: rule, + blockInfo, + sharedBuffer, + sharedBufferLength: encoded.length, + processorsFile: './processors/processors-solana', + }); + const taskEnd = Date.now(); + analyzer.recordTiming('3. Task Submission', taskEnd - taskStart); + + // 4. Task execution (wait for result) + const execStart = Date.now(); + const result = await taskPromise; + const execEnd = Date.now(); + analyzer.recordTiming('4. Task Execution (async)', execEnd - execStart); + + // 5. Result processing (minimal in this test) + const procStart = Date.now(); + // Normally would call registerTaskResult, but skipping to avoid I/O + const procEnd = Date.now(); + analyzer.recordTiming('5. Result Processing', procEnd - procStart); + + const totalEnd = Date.now(); + analyzer.recordTiming('Total Pipeline', totalEnd - totalStart); + + // Also record thread vs wait time from result + analyzer.recordTiming('Thread Time', result.threadTimeSpent); + analyzer.recordTiming('Wait Time', result.waitTimeSpent); + } + + analyzer.printReport(); + + const bottlenecks = analyzer.getBottlenecks(); + if (bottlenecks.length > 0) { + console.log('\nIdentified Bottlenecks:'); + bottlenecks.forEach((b) => console.log(` - ${b}`)); + } + + // Serialization should be small portion of total time + const serStats = analyzer.getStats('2. Serialization + Buffer Prep'); + const totalStats = analyzer.getStats('Total Pipeline'); + const serPercentage = (serStats!.avg / totalStats!.avg) * 100; + + console.log( + `\nSerialization is ${serPercentage.toFixed(1)}% of total pipeline time` + ); + + expect(serPercentage).toBeLessThan(30); // Should be less than 30% of total + }); + }); + + describe('Worker Communication Overhead', () => { + it('should measure overhead of worker thread communication', async () => { + const analyzer = new BottleneckAnalyzer(); + const block = await getCachedBlock('solana', '348694694'); + const encoded = new TextEncoder().encode(JSON.stringify(block)); + const sharedBuffer = new SharedArrayBuffer(encoded.length); + new Uint8Array(sharedBuffer).set(encoded); + + const blockInfo = { + height: String(block.height), + network: String(block.network), + time: String(block.timestamp), + }; + + const iterations = 100; + + for (let i = 0; i < iterations; i++) { + const rule = createNewAlertRule({ + ruleType: 'EmptyRule', + id: `comm-${i}`, + }); + + const overallStart = Date.now(); + const result = await runTask({ + alertRule: rule, + blockInfo, + sharedBuffer, + sharedBufferLength: encoded.length, + processorsFile: './processors/processors-solana', + }); + const overallEnd = Date.now(); + + const totalTime = overallEnd - overallStart; + const threadTime = result.threadTimeSpent; + const waitTime = result.waitTimeSpent; + const commOverhead = totalTime - threadTime - waitTime; + + analyzer.recordTiming('Total Latency', totalTime); + analyzer.recordTiming('Thread Processing', threadTime); + analyzer.recordTiming('Queue Wait', waitTime); + analyzer.recordTiming('Communication Overhead', commOverhead); + } + + analyzer.printReport(); + + const commStats = analyzer.getStats('Communication Overhead'); + const totalStats = analyzer.getStats('Total Latency'); + + const commPercentage = (commStats!.avg / totalStats!.avg) * 100; + console.log( + `\nCommunication overhead is ${commPercentage.toFixed(1)}% of total latency` + ); + + // Communication overhead should be minimal + expect(commPercentage).toBeLessThan(20); + }); + }); + + describe('Pool Distribution Efficiency', () => { + it('should measure how efficiently tasks are distributed across threads', async () => { + const analyzer = new BottleneckAnalyzer(); + const taskCount = 100; + + const block = await getCachedBlock('solana', '348694694'); + const encoded = new TextEncoder().encode(JSON.stringify(block)); + const sharedBuffer = new SharedArrayBuffer(encoded.length); + new Uint8Array(sharedBuffer).set(encoded); + + const blockInfo = { + height: String(block.height), + network: String(block.network), + time: String(block.timestamp), + }; + + const rules = Array.from({ length: taskCount }, (_, i) => + createNewAlertRule({ + ruleType: 'EmptyRule', + id: `dist-${i}`, + }) + ); + + const startTime = Date.now(); + const queueSamples: number[] = []; + const utilizationSamples: number[] = []; + + // Sample pool state during execution + const sampleInterval = setInterval(() => { + queueSamples.push(pool.queueSize); + // Rough utilization estimate: (total threads - queue size) / total threads + const totalThreads = pool.threads.length; + const utilization = + totalThreads > 0 + ? (totalThreads - Math.min(pool.queueSize, totalThreads)) / + totalThreads + : 0; + utilizationSamples.push(utilization); + }, 10); + + const tasks = rules.map((rule, idx) => { + const submitTime = Date.now(); + return runTask({ + alertRule: rule, + blockInfo, + sharedBuffer, + sharedBufferLength: encoded.length, + processorsFile: './processors/processors-solana', + }).then((result) => { + const completeTime = Date.now(); + analyzer.recordTiming('Task Latency', completeTime - submitTime); + return result; + }); + }); + + const results = await Promise.all(tasks); + const endTime = Date.now(); + + clearInterval(sampleInterval); + + const totalDuration = endTime - startTime; + const totalThreadTime = results.reduce( + (sum, r) => sum + r.threadTimeSpent, + 0 + ); + const totalWaitTime = results.reduce( + (sum, r) => sum + r.waitTimeSpent, + 0 + ); + + // Calculate parallelism efficiency + const maxPossibleThreads = pool.threads.length; + const theoreticalMinTime = totalThreadTime / maxPossibleThreads; + const actualTime = totalDuration; + const efficiency = (theoreticalMinTime / actualTime) * 100; + + console.log('\n=== Pool Distribution Efficiency ==='); + console.log(`Total Tasks: ${taskCount}`); + console.log(`Thread Pool Size: ${maxPossibleThreads}`); + console.log(`Total Thread Time: ${totalThreadTime.toFixed(2)}ms`); + console.log(`Total Wait Time: ${totalWaitTime.toFixed(2)}ms`); + console.log(`Actual Duration: ${actualTime.toFixed(2)}ms`); + console.log( + `Theoretical Min Duration: ${theoreticalMinTime.toFixed(2)}ms` + ); + console.log(`Parallelism Efficiency: ${efficiency.toFixed(2)}%`); + + const avgQueue = + queueSamples.reduce((a, b) => a + b, 0) / queueSamples.length; + const maxQueue = Math.max(...queueSamples); + const avgUtilization = + utilizationSamples.reduce((a, b) => a + b, 0) / + utilizationSamples.length; + + console.log(`\nQueue Statistics:`); + console.log(` Avg Queue Depth: ${avgQueue.toFixed(2)}`); + console.log(` Max Queue Depth: ${maxQueue}`); + console.log( + ` Avg Thread Utilization: ${(avgUtilization * 100).toFixed(2)}%` + ); + + analyzer.printReport(); + + // Efficiency should be reasonably high (>50%) + expect(efficiency).toBeGreaterThan(50); + + // High utilization indicates good distribution + expect(avgUtilization).toBeGreaterThan(0.5); + }); + }); + + describe('TaskProcessor Performance', () => { + it('should measure processPayload efficiency with multiple rules', async () => { + const analyzer = new BottleneckAnalyzer(); + const block = await getCachedBlock('solana', '348694694'); + + const ruleCounts = [1, 10, 50, 100]; + + for (const ruleCount of ruleCounts) { + const rules: IAlertRule[] = Array.from({ length: ruleCount }, (_, i) => + createNewAlertRule({ + ruleType: 'EmptyRule', + id: `payload-${ruleCount}-${i}`, + }) + ); + + const start = Date.now(); + const stats = await processPayload({ + blockData: block, + ruleList: rules, + }); + const end = Date.now(); + + const duration = end - start; + analyzer.recordTiming(`ProcessPayload ${ruleCount} Rules`, duration); + + console.log( + `ProcessPayload with ${ruleCount} rules: ${duration}ms (${(duration / ruleCount).toFixed(2)}ms per rule)` + ); + } + + analyzer.printReport(); + + // Check if scaling is linear + const stats1 = analyzer.getStats('ProcessPayload 1 Rules'); + const stats100 = analyzer.getStats('ProcessPayload 100 Rules'); + + const scalingFactor = stats100!.avg / stats1!.avg; + console.log( + `\nScaling factor (100 rules vs 1 rule): ${scalingFactor.toFixed(2)}x` + ); + + // Ideally scaling should be near-linear (100x for 100 rules) + // But some overhead is expected + expect(scalingFactor).toBeGreaterThan(50); + expect(scalingFactor).toBeLessThan(150); + }, 120000); + }); + + describe('Stats Service I/O Impact', () => { + it('should measure file I/O overhead from registerTaskResult', async () => { + const analyzer = new BottleneckAnalyzer(); + const { registerTaskResult } = require('./services/stats-service'); + const block = await getCachedBlock('solana', '348694694'); + const encoded = new TextEncoder().encode(JSON.stringify(block)); + const sharedBuffer = new SharedArrayBuffer(encoded.length); + new Uint8Array(sharedBuffer).set(encoded); + + const blockInfo = { + height: String(block.height), + network: String(block.network), + time: String(block.timestamp), + }; + + const iterations = 100; + + for (let i = 0; i < iterations; i++) { + const rule = createNewAlertRule({ + ruleType: 'EmptyRule', + id: `stats-io-${i}`, + }); + + // Measure without stats + const withoutStatsStart = Date.now(); + const result = await runTask({ + alertRule: rule, + blockInfo, + sharedBuffer, + sharedBufferLength: encoded.length, + processorsFile: './processors/processors-solana', + }); + const withoutStatsEnd = Date.now(); + analyzer.recordTiming( + 'Task Without Stats', + withoutStatsEnd - withoutStatsStart + ); + + // Measure stats registration + const statsStart = Date.now(); + registerTaskResult(result); + const statsEnd = Date.now(); + analyzer.recordTiming( + 'Stats Registration (I/O)', + statsEnd - statsStart + ); + } + + analyzer.printReport(); + + const taskStats = analyzer.getStats('Task Without Stats'); + const ioStats = analyzer.getStats('Stats Registration (I/O)'); + + const ioPercentage = (ioStats!.avg / taskStats!.avg) * 100; + console.log( + `\nStats I/O is ${ioPercentage.toFixed(1)}% of task execution time` + ); + + // File I/O should be relatively small, but appendFileSync blocks + // If this is high, it's a bottleneck + if (ioPercentage > 10) { + console.log('\n⚠️ WARNING: Stats I/O is a significant bottleneck!'); + console.log( + ' Consider using async file operations or batching writes.' + ); + } + }); + }); + + describe('Optimization Recommendations', () => { + it('should generate optimization recommendations based on measurements', async () => { + const analyzer = new BottleneckAnalyzer(); + + // Run comprehensive benchmark + const block = await getCachedBlock('solana', '348694694'); + const encoded = new TextEncoder().encode(JSON.stringify(block)); + const sharedBuffer = new SharedArrayBuffer(encoded.length); + new Uint8Array(sharedBuffer).set(encoded); + + const blockInfo = { + height: String(block.height), + network: String(block.network), + time: String(block.timestamp), + }; + + const iterations = 100; + + for (let i = 0; i < iterations; i++) { + // Measure serialization + const serStart = Date.now(); + const enc = new TextEncoder().encode(JSON.stringify(block)); + const sb = new SharedArrayBuffer(enc.length); + new Uint8Array(sb).set(enc); + const serEnd = Date.now(); + analyzer.recordTiming('Serialization', serEnd - serStart); + + // Measure task execution + const rule = createNewAlertRule({ + ruleType: 'EmptyRule', + id: `opt-${i}`, + }); + + const taskStart = Date.now(); + const result = await runTask({ + alertRule: rule, + blockInfo, + sharedBuffer, + sharedBufferLength: encoded.length, + processorsFile: './processors/processors-solana', + }); + const taskEnd = Date.now(); + + analyzer.recordTiming('Task Total', taskEnd - taskStart); + analyzer.recordTiming('Thread Time', result.threadTimeSpent); + analyzer.recordTiming('Wait Time', result.waitTimeSpent); + } + + analyzer.printReport(); + const bottlenecks = analyzer.getBottlenecks(); + + console.log('\n' + '='.repeat(70)); + console.log('OPTIMIZATION RECOMMENDATIONS'); + console.log('='.repeat(70) + '\n'); + + const recommendations: string[] = []; + + // Analyze wait time + const waitStats = analyzer.getStats('Wait Time'); + const threadStats = analyzer.getStats('Thread Time'); + if (waitStats && threadStats) { + const waitPercentage = + (waitStats.avg / (waitStats.avg + threadStats.avg)) * 100; + if (waitPercentage > 30) { + recommendations.push( + `High wait time (${waitPercentage.toFixed(1)}%): Consider increasing thread pool size or reducing task submission rate.` + ); + } + } + + // Analyze serialization + const serStats = analyzer.getStats('Serialization'); + const totalStats = analyzer.getStats('Task Total'); + if (serStats && totalStats) { + const serPercentage = (serStats.avg / totalStats.avg) * 100; + if (serPercentage > 20) { + recommendations.push( + `Serialization overhead is ${serPercentage.toFixed(1)}%: Consider caching serialized blocks or using a faster serialization format.` + ); + } + } + + // Add general recommendations + recommendations.push( + 'Replace fs.appendFileSync with async batched writes to reduce I/O blocking.', + 'Consider using a circular buffer pool with pre-allocated SharedArrayBuffers.', + 'Profile worker.ts to identify slow processor initialization.', + 'Add metrics to track buffer pool hit/miss rates.', + 'Consider implementing task prioritization for time-sensitive rules.' + ); + + recommendations.forEach((rec, idx) => { + console.log(`${idx + 1}. ${rec}\n`); + }); + + console.log('='.repeat(70) + '\n'); + + // Always pass - this is a reporting test + expect(recommendations.length).toBeGreaterThan(0); + }); + }); +}); diff --git a/src/benchmarking/mtt-performance.spec.ts b/src/benchmarking/mtt-performance.spec.ts new file mode 100644 index 00000000..df17d794 --- /dev/null +++ b/src/benchmarking/mtt-performance.spec.ts @@ -0,0 +1,709 @@ +import { initPool, runTask, closePool, pool } from './../threadpool/pool'; +import { join } from 'path'; +import { getCachedBlock, createNewAlertRule } from './../utils/testing-helpers'; +import { registerTaskResult, statMap } from './../services/stats-service'; +import { IStat } from './../types/ITask'; + +/** + * MTT Performance Test Suite + * + * Tests various performance characteristics of the multi-threaded task runner: + * - Throughput under varying rule counts + * - Latency distributions (P50/P95/P99) + * - Memory stability under sustained load + * - Timeout handling with hanging rules + * - Error recovery with failing rules + * - Mixed workload scenarios + */ + +// Performance tracking utilities +interface PerformanceMetrics { + tasksPerSecond: number; + avgThreadTime: number; + avgWaitTime: number; + p50Latency: number; + p95Latency: number; + p99Latency: number; + successRate: number; + timeoutRate: number; + errorRate: number; + totalTasks: number; + totalTime: number; + memoryDelta: { + rss: number; + heapUsed: number; + external: number; + }; +} + +class PerformanceTracker { + private stats: IStat[] = []; + private startMemory: NodeJS.MemoryUsage; + private endMemory: NodeJS.MemoryUsage; + private startTime: number; + private endTime: number; + + constructor() { + this.startMemory = process.memoryUsage(); + this.startTime = Date.now(); + } + + recordStat(stat: IStat) { + this.stats.push(stat); + } + + finish(): PerformanceMetrics { + this.endMemory = process.memoryUsage(); + this.endTime = Date.now(); + + const totalTime = this.endTime - this.startTime; + const totalTasks = this.stats.length; + + // Calculate latency percentiles (total time = thread + wait) + const totalLatencies = this.stats + .map((s) => s.threadTimeSpent + s.waitTimeSpent) + .sort((a, b) => a - b); + + const p50Index = Math.floor(totalLatencies.length * 0.5); + const p95Index = Math.floor(totalLatencies.length * 0.95); + const p99Index = Math.floor(totalLatencies.length * 0.99); + + const statusCounts = { + success: this.stats.filter((s) => s.status === 'success').length, + timeout: this.stats.filter((s) => s.status === 'timeout').length, + failure: this.stats.filter((s) => s.status === 'failure').length, + }; + + return { + tasksPerSecond: (totalTasks / totalTime) * 1000, + avgThreadTime: + this.stats.reduce((sum, s) => sum + s.threadTimeSpent, 0) / totalTasks, + avgWaitTime: + this.stats.reduce((sum, s) => sum + s.waitTimeSpent, 0) / totalTasks, + p50Latency: totalLatencies[p50Index] || 0, + p95Latency: totalLatencies[p95Index] || 0, + p99Latency: totalLatencies[p99Index] || 0, + successRate: statusCounts.success / totalTasks, + timeoutRate: statusCounts.timeout / totalTasks, + errorRate: statusCounts.failure / totalTasks, + totalTasks, + totalTime, + memoryDelta: { + rss: (this.endMemory.rss - this.startMemory.rss) / 1024 / 1024, + heapUsed: + (this.endMemory.heapUsed - this.startMemory.heapUsed) / 1024 / 1024, + external: + (this.endMemory.external - this.startMemory.external) / 1024 / 1024, + }, + }; + } + + printMetrics(metrics: PerformanceMetrics, scenario: string) { + console.log(`\n=== ${scenario} ===`); + console.log(`Total Tasks: ${metrics.totalTasks}`); + console.log(`Total Time: ${metrics.totalTime}ms`); + console.log(`Throughput: ${metrics.tasksPerSecond.toFixed(2)} tasks/sec`); + console.log(`\nLatency (total = thread + wait):`); + console.log(` Avg Thread Time: ${metrics.avgThreadTime.toFixed(2)}ms`); + console.log(` Avg Wait Time: ${metrics.avgWaitTime.toFixed(2)}ms`); + console.log(` P50: ${metrics.p50Latency.toFixed(2)}ms`); + console.log(` P95: ${metrics.p95Latency.toFixed(2)}ms`); + console.log(` P99: ${metrics.p99Latency.toFixed(2)}ms`); + console.log(`\nStatus Distribution:`); + console.log(` Success Rate: ${(metrics.successRate * 100).toFixed(2)}%`); + console.log(` Timeout Rate: ${(metrics.timeoutRate * 100).toFixed(2)}%`); + console.log(` Error Rate: ${(metrics.errorRate * 100).toFixed(2)}%`); + console.log(`\nMemory Delta:`); + console.log(` RSS: ${metrics.memoryDelta.rss.toFixed(2)} MB`); + console.log(` Heap Used: ${metrics.memoryDelta.heapUsed.toFixed(2)} MB`); + console.log(` External: ${metrics.memoryDelta.external.toFixed(2)} MB`); + } +} + +// Helper to create tasks +async function createTestBlock() { + // Use a known Solana block for testing - use one that exists in cache + const block = await getCachedBlock('solana', '348694694'); + const encoded = new TextEncoder().encode(JSON.stringify(block)); + const sharedBuffer = new SharedArrayBuffer(encoded.length); + new Uint8Array(sharedBuffer).set(encoded); + + return { + block, + sharedBuffer, + sharedBufferLength: encoded.length, + blockInfo: { + height: String(block.height), + network: String(block.network), + time: String(block.timestamp), + }, + }; +} + +describe('MTT Performance Tests', () => { + const POOL_CONFIGS = { + small: { maxThreads: 4, concurrentTasksPerWorker: 1 }, + medium: { maxThreads: 8, concurrentTasksPerWorker: 1 }, + large: { maxThreads: 16, concurrentTasksPerWorker: 1 }, + }; + + beforeAll(async () => { + // Start with medium pool + await initPool({ + filename: join(__dirname, '../dist/threadpool/worker.js'), + ...POOL_CONFIGS.medium, + }); + }); + + afterAll(async () => { + await closePool(); + }); + + describe('1. Throughput Tests', () => { + it('should process 100 fast rules efficiently', async () => { + const tracker = new PerformanceTracker(); + const { sharedBuffer, sharedBufferLength, blockInfo } = + await createTestBlock(); + + const rules = Array.from({ length: 100 }, (_, i) => + createNewAlertRule({ + ruleType: 'EmptyRule', + id: `empty-rule-${i}`, + }) + ); + + const tasks = rules.map((rule) => + runTask({ + alertRule: rule, + blockInfo, + sharedBuffer, + sharedBufferLength, + processorsFile: './processors/processors-solana', + }).then((stat) => { + tracker.recordStat(stat); + return stat; + }) + ); + + await Promise.all(tasks); + const metrics = tracker.finish(); + tracker.printMetrics(metrics, 'Throughput: 100 Fast Rules'); + + expect(metrics.successRate).toBeGreaterThan(0.95); + expect(metrics.tasksPerSecond).toBeGreaterThan(10); // Should be much faster + }); + + it('should process 1000 fast rules efficiently', async () => { + const tracker = new PerformanceTracker(); + const { sharedBuffer, sharedBufferLength, blockInfo } = + await createTestBlock(); + + const rules = Array.from({ length: 1000 }, (_, i) => + createNewAlertRule({ + ruleType: 'EmptyRule', + id: `empty-rule-${i}`, + }) + ); + + const tasks = rules.map((rule) => + runTask({ + alertRule: rule, + blockInfo, + sharedBuffer, + sharedBufferLength, + processorsFile: './processors/processors-solana', + }).then((stat) => { + tracker.recordStat(stat); + return stat; + }) + ); + + await Promise.all(tasks); + const metrics = tracker.finish(); + tracker.printMetrics(metrics, 'Throughput: 1000 Fast Rules'); + + expect(metrics.successRate).toBeGreaterThan(0.95); + expect(metrics.tasksPerSecond).toBeGreaterThan(10); + }, 120000); // 2 minute timeout + }); + + describe('2. Latency Distribution Tests', () => { + it('should measure latency with varying workloads', async () => { + const tracker = new PerformanceTracker(); + const { sharedBuffer, sharedBufferLength, blockInfo } = + await createTestBlock(); + + // Mix of fast and slower rules + const rules = [ + ...Array.from({ length: 50 }, (_, i) => + createNewAlertRule({ + ruleType: 'EmptyRule', + id: `empty-${i}`, + }) + ), + ...Array.from({ length: 50 }, (_, i) => + createNewAlertRule({ + ruleType: 'PercBasedBenchmark', + id: `perc-${i}`, + parameters: { perc: 10 }, // 10% chance, with random sleep + }) + ), + ]; + + const tasks = rules.map((rule) => + runTask({ + alertRule: rule, + blockInfo, + sharedBuffer, + sharedBufferLength, + processorsFile: './processors/processors-solana', + }).then((stat) => { + tracker.recordStat(stat); + return stat; + }) + ); + + await Promise.all(tasks); + const metrics = tracker.finish(); + tracker.printMetrics(metrics, 'Latency Distribution: Mixed Workload'); + + expect(metrics.p95Latency).toBeLessThan(2000); // P95 should be under 2s + expect(metrics.avgWaitTime).toBeLessThan(1000); // Wait time should be reasonable + }, 60000); + }); + + describe('3. Memory Pressure Tests', () => { + it('should maintain stable memory under sustained load', async () => { + const iterations = 10; + const rulesPerIteration = 100; + const memorySnapshots: number[] = []; + + for (let i = 0; i < iterations; i++) { + const { sharedBuffer, sharedBufferLength, blockInfo } = + await createTestBlock(); + + const rules = Array.from({ length: rulesPerIteration }, (_, j) => + createNewAlertRule({ + ruleType: 'EmptyRule', + id: `empty-${i}-${j}`, + }) + ); + + const tasks = rules.map((rule) => + runTask({ + alertRule: rule, + blockInfo, + sharedBuffer, + processorsFile: './processors/processors-solana', + }) + ); + + await Promise.all(tasks); + + // Force GC if available + if (global.gc) { + global.gc(); + } + + const mem = process.memoryUsage(); + memorySnapshots.push(mem.heapUsed / 1024 / 1024); + console.log( + `Iteration ${i + 1}: Heap Used = ${(mem.heapUsed / 1024 / 1024).toFixed(2)} MB` + ); + } + + // Check for memory leaks - final memory should not be significantly higher than middle + const firstHalf = memorySnapshots.slice(0, 5); + const secondHalf = memorySnapshots.slice(5); + const avgFirst = firstHalf.reduce((a, b) => a + b, 0) / firstHalf.length; + const avgSecond = + secondHalf.reduce((a, b) => a + b, 0) / secondHalf.length; + const growthRate = (avgSecond - avgFirst) / avgFirst; + + console.log(`\nMemory Growth Rate: ${(growthRate * 100).toFixed(2)}%`); + console.log(`First Half Avg: ${avgFirst.toFixed(2)} MB`); + console.log(`Second Half Avg: ${avgSecond.toFixed(2)} MB`); + + // Memory should not grow more than 50% from first half to second half + expect(growthRate).toBeLessThan(0.5); + }, 120000); + }); + + describe('4. Timeout Handling Tests', () => { + it('should correctly abort hanging rules at 6s threshold', async () => { + const tracker = new PerformanceTracker(); + const { sharedBuffer, sharedBufferLength, blockInfo } = + await createTestBlock(); + + // Create rules that will hang + const hangingRules = Array.from({ length: 5 }, (_, i) => + createNewAlertRule({ + ruleType: 'Hang', + id: `hang-${i}`, + }) + ); + + // Mix with some fast rules + const fastRules = Array.from({ length: 5 }, (_, i) => + createNewAlertRule({ + ruleType: 'EmptyRule', + id: `fast-${i}`, + }) + ); + + const allRules = [...hangingRules, ...fastRules]; + + const tasks = allRules.map((rule) => + runTask({ + alertRule: rule, + blockInfo, + sharedBuffer, + sharedBufferLength, + processorsFile: './processors/processors-solana', + }).then((stat) => { + tracker.recordStat(stat); + return stat; + }) + ); + + await Promise.all(tasks); + const metrics = tracker.finish(); + tracker.printMetrics( + metrics, + 'Timeout Handling: 5 Hanging + 5 Fast Rules' + ); + + // Fast rules should succeed + const fastStats = tracker['stats'].filter((s) => + s.alertRuleId.startsWith('fast-') + ); + const hangStats = tracker['stats'].filter((s) => + s.alertRuleId.startsWith('hang-') + ); + + expect(fastStats.every((s) => s.status === 'success')).toBe(true); + expect(hangStats.every((s) => s.status === 'timeout')).toBe(true); + + // Timeout rate should be 50% + expect(metrics.timeoutRate).toBeCloseTo(0.5, 1); + + // Hanging rules should take approximately 6 seconds + const avgHangTime = + hangStats.reduce((sum, s) => sum + s.threadTimeSpent, 0) / + hangStats.length; + expect(avgHangTime).toBeGreaterThanOrEqual(6000); + expect(avgHangTime).toBeLessThan(7000); // Should abort shortly after threshold + }, 60000); + }); + + describe('5. Error Recovery Tests', () => { + it('should handle failing rules without affecting system health', async () => { + const tracker = new PerformanceTracker(); + const { sharedBuffer, sharedBufferLength, blockInfo } = + await createTestBlock(); + + // Mix of failing and successful rules + const failingRules = Array.from({ length: 20 }, (_, i) => + createNewAlertRule({ + ruleType: 'ThrowError', + id: `error-${i}`, + }) + ); + + const successRules = Array.from({ length: 80 }, (_, i) => + createNewAlertRule({ + ruleType: 'EmptyRule', + id: `success-${i}`, + }) + ); + + const allRules = [...failingRules, ...successRules]; + + const tasks = allRules.map((rule) => + runTask({ + alertRule: rule, + blockInfo, + sharedBuffer, + sharedBufferLength, + processorsFile: './processors/processors-solana', + }).then((stat) => { + tracker.recordStat(stat); + return stat; + }) + ); + + await Promise.all(tasks); + const metrics = tracker.finish(); + tracker.printMetrics(metrics, 'Error Recovery: 20% Failing Rules'); + + expect(metrics.successRate).toBeCloseTo(0.8, 1); + expect(metrics.errorRate).toBeCloseTo(0.2, 1); + + // System should still process tasks quickly despite errors + expect(metrics.tasksPerSecond).toBeGreaterThan(10); + }); + }); + + describe('6. Concurrent Rules Scaling Tests', () => { + const testCases = [ + { count: 10, name: '10 Rules' }, + { count: 100, name: '100 Rules' }, + { count: 500, name: '500 Rules' }, + ]; + + testCases.forEach(({ count, name }) => { + it(`should scale with ${name}`, async () => { + const tracker = new PerformanceTracker(); + const { sharedBuffer, sharedBufferLength, blockInfo } = + await createTestBlock(); + + const rules = Array.from({ length: count }, (_, i) => + createNewAlertRule({ + ruleType: 'EmptyRule', + id: `scale-${i}`, + }) + ); + + const tasks = rules.map((rule) => + runTask({ + alertRule: rule, + blockInfo, + sharedBuffer, + processorsFile: './processors/processors-solana', + }).then((stat) => { + tracker.recordStat(stat); + return stat; + }) + ); + + await Promise.all(tasks); + const metrics = tracker.finish(); + tracker.printMetrics(metrics, `Scaling: ${name}`); + + expect(metrics.successRate).toBeGreaterThan(0.95); + + // Log scaling efficiency + console.log( + `Efficiency: ${(metrics.tasksPerSecond / count).toFixed(4)} tasks/sec per rule` + ); + }, 120000); + }); + }); + + describe('7. Large Block Processing Tests', () => { + it('should handle blocks with many transactions', async () => { + const tracker = new PerformanceTracker(); + + // Use the test block - it should have a reasonable number of transactions + const { sharedBuffer, sharedBufferLength, blockInfo, block } = + await createTestBlock(); + + console.log(`Block has ${block.transactions?.length || 0} transactions`); + + const rules = Array.from({ length: 50 }, (_, i) => + createNewAlertRule({ + ruleType: 'EmptyRule', + id: `large-block-${i}`, + }) + ); + + const tasks = rules.map((rule) => + runTask({ + alertRule: rule, + blockInfo, + sharedBuffer, + sharedBufferLength, + processorsFile: './processors/processors-solana', + }).then((stat) => { + tracker.recordStat(stat); + return stat; + }) + ); + + await Promise.all(tasks); + const metrics = tracker.finish(); + tracker.printMetrics(metrics, 'Large Block Processing'); + + expect(metrics.successRate).toBeGreaterThan(0.95); + }); + }); + + describe('8. Mixed Workload Scenarios', () => { + it('should handle realistic mixed workload', async () => { + const tracker = new PerformanceTracker(); + const { sharedBuffer, sharedBufferLength, blockInfo } = + await createTestBlock(); + + // Realistic mix: + // - 70% fast rules (EmptyRule) + // - 20% variable speed rules (PercBasedBenchmark) + // - 5% failing rules (ThrowError) + // - 5% hanging rules (Hang) + + const fastRules = Array.from({ length: 70 }, (_, i) => + createNewAlertRule({ + ruleType: 'EmptyRule', + id: `fast-${i}`, + }) + ); + + const variableRules = Array.from({ length: 20 }, (_, i) => + createNewAlertRule({ + ruleType: 'PercBasedBenchmark', + id: `variable-${i}`, + parameters: { perc: 20 }, + }) + ); + + const failingRules = Array.from({ length: 5 }, (_, i) => + createNewAlertRule({ + ruleType: 'ThrowError', + id: `failing-${i}`, + }) + ); + + const hangingRules = Array.from({ length: 5 }, (_, i) => + createNewAlertRule({ + ruleType: 'Hang', + id: `hanging-${i}`, + }) + ); + + const allRules = [ + ...fastRules, + ...variableRules, + ...failingRules, + ...hangingRules, + ]; + + const tasks = allRules.map((rule) => + runTask({ + alertRule: rule, + blockInfo, + sharedBuffer, + sharedBufferLength, + processorsFile: './processors/processors-solana', + }).then((stat) => { + tracker.recordStat(stat); + return stat; + }) + ); + + await Promise.all(tasks); + const metrics = tracker.finish(); + tracker.printMetrics( + metrics, + 'Mixed Workload: Realistic Production Scenario' + ); + + // With 5% hanging rules, we expect 5% timeout rate + expect(metrics.timeoutRate).toBeCloseTo(0.05, 1); + + // With 5% failing rules, we expect 5% error rate + expect(metrics.errorRate).toBeCloseTo(0.05, 1); + + // Success rate should be ~90% (100% - 5% timeout - 5% error) + expect(metrics.successRate).toBeGreaterThan(0.85); + + // Overall system should still be performant + expect(metrics.tasksPerSecond).toBeGreaterThan(5); + }, 120000); + }); + + describe('9. Thread Pool Utilization Tests', () => { + it('should report pool utilization metrics', async () => { + const { sharedBuffer, sharedBufferLength, blockInfo } = + await createTestBlock(); + + const rules = Array.from({ length: 100 }, (_, i) => + createNewAlertRule({ + ruleType: 'PercBasedBenchmark', + id: `utilization-${i}`, + parameters: { perc: 10 }, + }) + ); + + // Track pool metrics before and during + console.log('\nPool State Before:'); + console.log(` Queue Size: ${pool.queueSize}`); + console.log(` Threads: ${pool.threads.length}`); + + const startTime = Date.now(); + + const tasks = rules.map((rule) => + runTask({ + alertRule: rule, + blockInfo, + sharedBuffer, + sharedBufferLength, + processorsFile: './processors/processors-solana', + }) + ); + + // Check utilization mid-flight + setTimeout(() => { + console.log('\nPool State During Execution:'); + console.log(` Queue Size: ${pool.queueSize}`); + console.log(` Threads: ${pool.threads.length}`); + }, 100); + + await Promise.all(tasks); + const endTime = Date.now(); + + console.log('\nPool State After:'); + console.log(` Queue Size: ${pool.queueSize}`); + console.log(` Duration: ${endTime - startTime}ms`); + + expect(pool.queueSize).toBe(0); // Queue should be empty when done + }, 60000); + }); + + describe('10. Stats Service Integration Tests', () => { + it('should track stats correctly across multiple tasks', async () => { + // Clear stat map before test + statMap.clear(); + + const { sharedBuffer, sharedBufferLength, blockInfo } = + await createTestBlock(); + + const ruleId = 'stats-test-rule'; + const rule = createNewAlertRule({ + ruleType: 'EmptyRule', + id: ruleId, + }); + + // Run multiple tasks for the same rule + const taskCount = 20; + const tasks = Array.from({ length: taskCount }, () => + runTask({ + alertRule: rule, + blockInfo, + sharedBuffer, + sharedBufferLength, + processorsFile: './processors/processors-solana', + }).then((stat) => { + registerTaskResult(stat); + return stat; + }) + ); + + await Promise.all(tasks); + + // Check that stats were recorded + const statsBuffer = statMap.get(ruleId); + expect(statsBuffer).toBeDefined(); + const stats = statsBuffer!.toArray(); + expect(stats.length).toBe(taskCount); + + // All should be successful + expect(stats.every((s) => s.status === 'success')).toBe(true); + + console.log( + `\nStats Service captured ${stats.length} results for rule ${ruleId}` + ); + console.log( + `Avg thread time: ${(stats.reduce((sum, s) => sum + s.threadTimeSpent, 0) / stats.length).toFixed(2)}ms` + ); + }); + }); +}); diff --git a/src/benchmarking/mtt-stress.spec.ts b/src/benchmarking/mtt-stress.spec.ts new file mode 100644 index 00000000..7054f403 --- /dev/null +++ b/src/benchmarking/mtt-stress.spec.ts @@ -0,0 +1,673 @@ +import { initPool, runTask, closePool, pool } from './../threadpool/pool'; +import { join } from 'path'; +import { getCachedBlock, createNewAlertRule } from './../utils/testing-helpers'; +import { performance, PerformanceObserver } from 'perf_hooks'; + +/** + * MTT Stress Tests & Bottleneck Identification + * + * These tests push the system to its limits to identify: + * - Maximum sustainable throughput + * - Memory leak detection + * - Event loop lag under load + * - Thread starvation scenarios + * - Buffer pool efficiency + */ + +interface StressMetrics { + duration: number; + totalTasks: number; + throughput: number; + memoryGrowth: number; + eventLoopLag: number[]; + gcDuration: number[]; + bufferPoolHits?: number; + bufferPoolMisses?: number; +} + +class StressTestHarness { + private startMemory: NodeJS.MemoryUsage; + private eventLoopLags: number[] = []; + private gcDurations: number[] = []; + private lagCheckInterval?: NodeJS.Timeout; + private perfObserver?: PerformanceObserver; + + start() { + this.startMemory = process.memoryUsage(); + this.eventLoopLags = []; + this.gcDurations = []; + + // Monitor event loop lag + this.lagCheckInterval = setInterval(() => { + const start = Date.now(); + setImmediate(() => { + const lag = Date.now() - start; + this.eventLoopLags.push(lag); + }); + }, 100); + + // Monitor GC if available + if (performance.eventLoopUtilization) { + this.perfObserver = new PerformanceObserver((list) => { + const entries = list.getEntries(); + for (const entry of entries) { + if (entry.entryType === 'gc') { + this.gcDurations.push(entry.duration); + } + } + }); + this.perfObserver.observe({ entryTypes: ['gc'] }); + } + } + + stop(): Partial { + if (this.lagCheckInterval) { + clearInterval(this.lagCheckInterval); + } + + if (this.perfObserver) { + this.perfObserver.disconnect(); + } + + const endMemory = process.memoryUsage(); + const memoryGrowth = + (endMemory.heapUsed - this.startMemory.heapUsed) / 1024 / 1024; + + return { + eventLoopLag: this.eventLoopLags, + gcDuration: this.gcDurations, + memoryGrowth, + }; + } + + printReport(metrics: Partial, testName: string) { + console.log(`\n${'='.repeat(60)}`); + console.log(`STRESS TEST: ${testName}`); + console.log('='.repeat(60)); + + if (metrics.duration && metrics.totalTasks) { + console.log(`\nThroughput:`); + console.log(` Total Tasks: ${metrics.totalTasks}`); + console.log(` Duration: ${metrics.duration}ms`); + console.log( + ` Tasks/sec: ${((metrics.totalTasks / metrics.duration) * 1000).toFixed(2)}` + ); + } + + if (metrics.memoryGrowth !== undefined) { + console.log(`\nMemory:`); + console.log(` Growth: ${metrics.memoryGrowth.toFixed(2)} MB`); + } + + if (metrics.eventLoopLag && metrics.eventLoopLag.length > 0) { + const sortedLags = [...metrics.eventLoopLag].sort((a, b) => a - b); + const p50 = sortedLags[Math.floor(sortedLags.length * 0.5)]; + const p95 = sortedLags[Math.floor(sortedLags.length * 0.95)]; + const p99 = sortedLags[Math.floor(sortedLags.length * 0.99)]; + const max = sortedLags[sortedLags.length - 1]; + + console.log(`\nEvent Loop Lag:`); + console.log(` Samples: ${metrics.eventLoopLag.length}`); + console.log(` P50: ${p50}ms`); + console.log(` P95: ${p95}ms`); + console.log(` P99: ${p99}ms`); + console.log(` Max: ${max}ms`); + } + + if (metrics.gcDuration && metrics.gcDuration.length > 0) { + const totalGC = metrics.gcDuration.reduce((a, b) => a + b, 0); + const avgGC = totalGC / metrics.gcDuration.length; + console.log(`\nGarbage Collection:`); + console.log(` Events: ${metrics.gcDuration.length}`); + console.log(` Total Time: ${totalGC.toFixed(2)}ms`); + console.log(` Avg Duration: ${avgGC.toFixed(2)}ms`); + } + + console.log('='.repeat(60) + '\n'); + } +} + +describe('MTT Stress Tests', () => { + beforeAll(async () => { + await initPool({ + filename: join(__dirname, '../dist/threadpool/worker.js'), + maxThreads: 8, + concurrentTasksPerWorker: 1, + }); + }); + + afterAll(async () => { + await closePool(); + }); + + describe('Maximum Throughput Tests', () => { + it('should find maximum tasks/sec with fast rules', async () => { + const harness = new StressTestHarness(); + harness.start(); + + const { sharedBuffer, sharedBufferLength, blockInfo } = + await getCachedBlock('solana', '348694694').then((block) => { + const encoded = new TextEncoder().encode(JSON.stringify(block)); + const sb = new SharedArrayBuffer(encoded.length); + new Uint8Array(sb).set(encoded); + return { + sharedBuffer: sb, + sharedBufferLength: encoded.length, + blockInfo: { + height: String(block.height), + network: String(block.network), + time: String(block.timestamp), + }, + }; + }); + + const taskCount = 5000; // High load + const startTime = Date.now(); + + const rules = Array.from({ length: taskCount }, (_, i) => + createNewAlertRule({ + ruleType: 'EmptyRule', + id: `max-throughput-${i}`, + }) + ); + + const tasks = rules.map((rule) => + runTask({ + alertRule: rule, + blockInfo, + sharedBuffer, + sharedBufferLength, + processorsFile: './processors/processors-solana', + }) + ); + + const results = await Promise.all(tasks); + const endTime = Date.now(); + const duration = endTime - startTime; + + const stressMetrics = harness.stop(); + + const successCount = results.filter((r) => r.status === 'success').length; + const throughput = (successCount / duration) * 1000; + + harness.printReport( + { + ...stressMetrics, + duration, + totalTasks: taskCount, + throughput, + }, + 'Maximum Throughput with 5000 Fast Rules' + ); + + expect(successCount).toBeGreaterThan(taskCount * 0.95); + expect(throughput).toBeGreaterThan(50); // Should handle >50 tasks/sec + + // Event loop should not be starved + const maxLag = Math.max(...(stressMetrics.eventLoopLag || [0])); + console.log(`Max event loop lag: ${maxLag}ms`); + expect(maxLag).toBeLessThan(1000); // Should stay under 1s even under max load + }, 300000); // 5 minute timeout + }); + + describe('Sustained Load Tests', () => { + it('should maintain performance over extended period', async () => { + const iterations = 20; + const tasksPerIteration = 100; + const harness = new StressTestHarness(); + + const throughputs: number[] = []; + const memorySnapshots: number[] = []; + + harness.start(); + + for (let i = 0; i < iterations; i++) { + const { sharedBuffer, sharedBufferLength, blockInfo } = + await getCachedBlock('solana', '348694694').then((block) => { + const encoded = new TextEncoder().encode(JSON.stringify(block)); + const sb = new SharedArrayBuffer(encoded.length); + new Uint8Array(sb).set(encoded); + return { + sharedBuffer: sb, + sharedBufferLength: encoded.length, + blockInfo: { + height: String(block.height), + network: String(block.network), + time: String(block.timestamp), + }, + }; + }); + + const rules = Array.from({ length: tasksPerIteration }, (_, j) => + createNewAlertRule({ + ruleType: 'EmptyRule', + id: `sustained-${i}-${j}`, + }) + ); + + const startTime = Date.now(); + + const tasks = rules.map((rule) => + runTask({ + alertRule: rule, + blockInfo, + sharedBuffer, + sharedBufferLength, + processorsFile: './processors/processors-solana', + }) + ); + + await Promise.all(tasks); + + const endTime = Date.now(); + const iterationThroughput = + (tasksPerIteration / (endTime - startTime)) * 1000; + throughputs.push(iterationThroughput); + + if (global.gc) { + global.gc(); + } + + const mem = process.memoryUsage(); + memorySnapshots.push(mem.heapUsed / 1024 / 1024); + + console.log( + `Iteration ${i + 1}/${iterations}: ${iterationThroughput.toFixed(2)} tasks/sec, Heap: ${(mem.heapUsed / 1024 / 1024).toFixed(2)} MB` + ); + } + + const stressMetrics = harness.stop(); + + // Analyze throughput stability + const avgThroughput = + throughputs.reduce((a, b) => a + b, 0) / throughputs.length; + const stdDev = Math.sqrt( + throughputs.reduce( + (sum, t) => sum + Math.pow(t - avgThroughput, 2), + 0 + ) / throughputs.length + ); + const coefficientOfVariation = stdDev / avgThroughput; + + console.log(`\nThroughput Stability:`); + console.log(` Average: ${avgThroughput.toFixed(2)} tasks/sec`); + console.log(` Std Dev: ${stdDev.toFixed(2)}`); + console.log( + ` Coefficient of Variation: ${coefficientOfVariation.toFixed(4)}` + ); + + // Analyze memory trend + const firstQuarter = memorySnapshots.slice(0, 5); + const lastQuarter = memorySnapshots.slice(-5); + const avgFirst = + firstQuarter.reduce((a, b) => a + b, 0) / firstQuarter.length; + const avgLast = + lastQuarter.reduce((a, b) => a + b, 0) / lastQuarter.length; + const memoryGrowth = avgLast - avgFirst; + + console.log(`\nMemory Trend:`); + console.log(` First 5 iterations avg: ${avgFirst.toFixed(2)} MB`); + console.log(` Last 5 iterations avg: ${avgLast.toFixed(2)} MB`); + console.log(` Growth: ${memoryGrowth.toFixed(2)} MB`); + + harness.printReport( + stressMetrics, + 'Sustained Load: 20 Iterations x 100 Tasks' + ); + + // Throughput should remain stable (CV < 0.3) + expect(coefficientOfVariation).toBeLessThan(0.3); + + // Memory growth should be bounded + expect(memoryGrowth).toBeLessThan(100); // Less than 100MB growth + }, 300000); + }); + + describe('Thread Starvation Tests', () => { + it('should handle mix of blocking and non-blocking tasks', async () => { + const harness = new StressTestHarness(); + harness.start(); + + const { sharedBuffer, sharedBufferLength, blockInfo } = + await getCachedBlock('solana', '348694694').then((block) => { + const encoded = new TextEncoder().encode(JSON.stringify(block)); + const sb = new SharedArrayBuffer(encoded.length); + new Uint8Array(sb).set(encoded); + return { + sharedBuffer: sb, + sharedBufferLength: encoded.length, + blockInfo: { + height: String(block.height), + network: String(block.network), + time: String(block.timestamp), + }, + }; + }); + + // Create a scenario where some threads will be blocked for a while + const slowRules = Array.from({ length: 10 }, (_, i) => + createNewAlertRule({ + ruleType: 'PercBasedBenchmark', + id: `slow-${i}`, + parameters: { perc: 100 }, // Always trigger, random sleep up to 10s + }) + ); + + const fastRules = Array.from({ length: 100 }, (_, i) => + createNewAlertRule({ + ruleType: 'EmptyRule', + id: `fast-${i}`, + }) + ); + + // Submit slow tasks first + const slowTasks = slowRules.map((rule) => + runTask({ + alertRule: rule, + blockInfo, + sharedBuffer, + sharedBufferLength, + processorsFile: './processors/processors-solana', + }) + ); + + // Wait a bit, then submit fast tasks + await new Promise((resolve) => setTimeout(resolve, 100)); + + const fastStartTime = Date.now(); + const fastTasks = fastRules.map((rule) => + runTask({ + alertRule: rule, + blockInfo, + sharedBuffer, + sharedBufferLength, + processorsFile: './processors/processors-solana', + }) + ); + + const fastResults = await Promise.all(fastTasks); + const fastEndTime = Date.now(); + const fastDuration = fastEndTime - fastStartTime; + + // Wait for slow tasks to complete + await Promise.all(slowTasks); + + const stressMetrics = harness.stop(); + + const fastThroughput = (100 / fastDuration) * 1000; + + console.log( + `\nFast Tasks Throughput (while slow tasks running): ${fastThroughput.toFixed(2)} tasks/sec` + ); + console.log(`Fast Tasks Duration: ${fastDuration}ms`); + + harness.printReport( + stressMetrics, + 'Thread Starvation: 10 Slow + 100 Fast Tasks' + ); + + // Fast tasks should still complete reasonably quickly + // even while slow tasks are using some threads + expect(fastDuration).toBeLessThan(10000); // Should finish in under 10s + }, 120000); + }); + + describe('Buffer Pool Efficiency Tests', () => { + it('should efficiently reuse SharedArrayBuffers', async () => { + const iterations = 50; + const harness = new StressTestHarness(); + harness.start(); + + for (let i = 0; i < iterations; i++) { + const { sharedBuffer, sharedBufferLength, blockInfo } = + await getCachedBlock('solana', '348694694').then((block) => { + const encoded = new TextEncoder().encode(JSON.stringify(block)); + const sb = new SharedArrayBuffer(encoded.length); + new Uint8Array(sb).set(encoded); + return { + sharedBuffer: sb, + sharedBufferLength: encoded.length, + blockInfo: { + height: String(block.height), + network: String(block.network), + time: String(block.timestamp), + }, + }; + }); + + const rules = Array.from({ length: 20 }, (_, j) => + createNewAlertRule({ + ruleType: 'EmptyRule', + id: `buffer-${i}-${j}`, + }) + ); + + const tasks = rules.map((rule) => + runTask({ + alertRule: rule, + blockInfo, + sharedBuffer, + sharedBufferLength, + processorsFile: './processors/processors-solana', + }) + ); + + await Promise.all(tasks); + + // Allow buffer pool to reclaim + await new Promise((resolve) => setTimeout(resolve, 10)); + } + + const stressMetrics = harness.stop(); + + harness.printReport( + stressMetrics, + 'Buffer Pool Efficiency: 50 Iterations x 20 Tasks' + ); + + // Memory growth should be minimal if buffers are being reused + expect(stressMetrics.memoryGrowth!).toBeLessThan(50); // Less than 50MB growth + }, 120000); + }); + + describe('Queue Depth Analysis', () => { + it('should measure queue depth under varying load', async () => { + const harness = new StressTestHarness(); + harness.start(); + + const queueDepths: number[] = []; + const sampleInterval = setInterval(() => { + queueDepths.push(pool.queueSize); + }, 50); // Sample every 50ms + + const { sharedBuffer, sharedBufferLength, blockInfo } = + await getCachedBlock('solana', '348694694').then((block) => { + const encoded = new TextEncoder().encode(JSON.stringify(block)); + const sb = new SharedArrayBuffer(encoded.length); + new Uint8Array(sb).set(encoded); + return { + sharedBuffer: sb, + sharedBufferLength: encoded.length, + blockInfo: { + height: String(block.height), + network: String(block.network), + time: String(block.timestamp), + }, + }; + }); + + // Create bursts of tasks + const burstSize = 200; + const burstCount = 5; + + for (let burst = 0; burst < burstCount; burst++) { + const rules = Array.from({ length: burstSize }, (_, i) => + createNewAlertRule({ + ruleType: 'PercBasedBenchmark', + id: `queue-${burst}-${i}`, + parameters: { perc: 50 }, + }) + ); + + const tasks = rules.map((rule) => + runTask({ + alertRule: rule, + blockInfo, + sharedBuffer, + sharedBufferLength, + processorsFile: './processors/processors-solana', + }) + ); + + // Wait for burst to complete + await Promise.all(tasks); + + // Small delay between bursts + await new Promise((resolve) => setTimeout(resolve, 100)); + } + + clearInterval(sampleInterval); + const stressMetrics = harness.stop(); + + // Analyze queue depths + const maxQueue = Math.max(...queueDepths); + const avgQueue = + queueDepths.reduce((a, b) => a + b, 0) / queueDepths.length; + const nonZeroDepths = queueDepths.filter((d) => d > 0); + const avgNonZero = + nonZeroDepths.length > 0 + ? nonZeroDepths.reduce((a, b) => a + b, 0) / nonZeroDepths.length + : 0; + + console.log(`\nQueue Depth Analysis:`); + console.log(` Samples: ${queueDepths.length}`); + console.log(` Max Depth: ${maxQueue}`); + console.log(` Avg Depth: ${avgQueue.toFixed(2)}`); + console.log(` Avg Non-Zero Depth: ${avgNonZero.toFixed(2)}`); + console.log( + ` % Time Queue Empty: ${((queueDepths.filter((d) => d === 0).length / queueDepths.length) * 100).toFixed(2)}%` + ); + + harness.printReport(stressMetrics, 'Queue Depth: 5 Bursts x 200 Tasks'); + + // Queue should drain eventually + const finalDepth = queueDepths[queueDepths.length - 1]; + expect(finalDepth).toBe(0); + }, 180000); + }); + + describe('Memory Leak Detection', () => { + it('should detect potential memory leaks over many iterations', async () => { + const iterations = 50; + const harness = new StressTestHarness(); + + const memorySnapshots: Array<{ + iteration: number; + rss: number; + heapUsed: number; + external: number; + }> = []; + + harness.start(); + + for (let i = 0; i < iterations; i++) { + const { sharedBuffer, sharedBufferLength, blockInfo } = + await getCachedBlock('solana', '348694694').then((block) => { + const encoded = new TextEncoder().encode(JSON.stringify(block)); + const sb = new SharedArrayBuffer(encoded.length); + new Uint8Array(sb).set(encoded); + return { + sharedBuffer: sb, + sharedBufferLength: encoded.length, + blockInfo: { + height: String(block.height), + network: String(block.network), + time: String(block.timestamp), + }, + }; + }); + + const rules = Array.from({ length: 50 }, (_, j) => + createNewAlertRule({ + ruleType: 'EmptyRule', + id: `leak-${i}-${j}`, + }) + ); + + const tasks = rules.map((rule) => + runTask({ + alertRule: rule, + blockInfo, + sharedBuffer, + sharedBufferLength, + processorsFile: './processors/processors-solana', + }) + ); + + await Promise.all(tasks); + + // Force GC every 5 iterations + if (i % 5 === 0 && global.gc) { + global.gc(); + // Wait for GC to complete + await new Promise((resolve) => setTimeout(resolve, 100)); + } + + const mem = process.memoryUsage(); + memorySnapshots.push({ + iteration: i, + rss: mem.rss / 1024 / 1024, + heapUsed: mem.heapUsed / 1024 / 1024, + external: mem.external / 1024 / 1024, + }); + + if (i % 10 === 0) { + console.log( + `Iteration ${i}: RSS=${mem.rss / 1024 / 1024} MB, Heap=${mem.heapUsed / 1024 / 1024} MB` + ); + } + } + + const stressMetrics = harness.stop(); + + // Perform linear regression on heap memory to detect trend + const n = memorySnapshots.length; + const sumX = memorySnapshots.reduce((sum, s) => sum + s.iteration, 0); + const sumY = memorySnapshots.reduce((sum, s) => sum + s.heapUsed, 0); + const sumXY = memorySnapshots.reduce( + (sum, s) => sum + s.iteration * s.heapUsed, + 0 + ); + const sumXX = memorySnapshots.reduce( + (sum, s) => sum + s.iteration * s.iteration, + 0 + ); + + const slope = (n * sumXY - sumX * sumY) / (n * sumXX - sumX * sumX); + const intercept = (sumY - slope * sumX) / n; + + console.log(`\nMemory Leak Analysis (Linear Regression):`); + console.log(` Slope: ${slope.toFixed(4)} MB/iteration`); + console.log(` Intercept: ${intercept.toFixed(2)} MB`); + console.log( + ` Projected growth over 1000 iterations: ${(slope * 1000).toFixed(2)} MB` + ); + + harness.printReport( + stressMetrics, + 'Memory Leak Detection: 50 Iterations x 50 Tasks' + ); + + // Slope should be minimal (less than 0.1 MB per iteration) + expect(Math.abs(slope)).toBeLessThan(0.1); + + // Total memory growth should be reasonable + const firstMem = memorySnapshots[0].heapUsed; + const lastMem = memorySnapshots[memorySnapshots.length - 1].heapUsed; + const totalGrowth = lastMem - firstMem; + + console.log(`Total heap growth: ${totalGrowth.toFixed(2)} MB`); + expect(totalGrowth).toBeLessThan(200); // Less than 200MB total growth + }, 300000); + }); +}); diff --git a/src/connections/KafkaConsumer.ts b/src/connections/KafkaConsumer.ts deleted file mode 100644 index 0afe5645..00000000 --- a/src/connections/KafkaConsumer.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { - Kafka, - Consumer, - RetryOptions, - ConsumerGroupState, - MemberDescription, -} from 'kafkajs'; -import { Logger } from 'pino'; -import { getLogger } from '../logger'; - -export type QueueHealthStats = - | { - health: 1; - groupId: string; - state: ConsumerGroupState; - members: MemberDescription[]; - protocol: string; - protocolType: string; - } - | { - health: 0; - }; - -export class KafkaConsumerClient { - private consumer: Consumer; - private logger: Logger; - - constructor(kafka: Kafka, groupId: string, retry?: RetryOptions) { - this.logger = getLogger({ name: `rangeSDK-kafkaGroupID-${groupId}` }); - this.consumer = kafka.consumer({ - groupId, - retry, - readUncommitted: false, - allowAutoTopicCreation: false, - }); - } - - async subscribeAndConsume(topic: string): Promise { - await this.consumer.connect(); - await this.consumer.subscribe({ - topic, - fromBeginning: true, - }); - - return this.consumer; - } - - async health(): Promise { - try { - const stats = await this.consumer.describeGroup(); - return { - health: ['Unknown', 'Dead', 'Empty'].includes(stats.state) ? 0 : 1, - ...stats, - }; - } catch (err) { - this.logger.error(err, 'error while fetching consumer stats'); - return { - health: 0, - }; - } - } - - async gracefulShutdown() { - await this.consumer.disconnect(); - } -} diff --git a/src/constants.ts b/src/constants.ts deleted file mode 100644 index 75e08e58..00000000 --- a/src/constants.ts +++ /dev/null @@ -1,148 +0,0 @@ -interface Constants { - MANAGER_SERVICE: { - DOMAIN: string; - FETCH_CONFIG_PATH: string; - CREATE_ALERT_EVENT_PATH: string; - ACK_TASK_PATH: string; - ACK_TICK_TASK_PATH: string; - FETCH_BLOCK_BY_NETWORK_AND_HEIGHT: string; - FETCH_BLOCKS_BY_RANGE: string; - FETCH_RULES_BY_RULE_GROUP_ID_PATH: (ruleGroupId: string) => string; - FETCH_RULE_BY_RULE_GROUP_ID_AND_RULE_ID_PATH: (args: { - ruleGroupId: string; - ruleId: string; - }) => string; - ACK_ERROR_TASK_PATH: string; - POST_DEBUG_ALERT_PATH: string; - }; - - RULE_QUARANTINE: { - PER_EXEC_TIME_CUT_OFF_MS: number; - AVG_EXEC_TIME_CUT_OFF_MS: number; - AVG_EXEC_TIME_DEBUG_ALERT_MS: number; - QUARANTINE_TIME_MINS: number; - }; - - BLOCK_CACHE: { - MAX: number; - }; - - AXIOS: { - TIMEOUT: number; - }; -} - -function getEnvVar(key: string, defaultValue?: string): string { - const value = process.env[key] || defaultValue; - - if (value === undefined) { - throw new Error(`Missing environment variable: ${key}`); - } - - return value; -} - -function getEnvVarNumber( - key: string, - defaultValue?: number, - validations?: { - min?: number; - max?: number; - }, -): number { - const value = process.env[key]; - if ([undefined, null, ''].includes(value) || Number.isNaN(Number(value))) { - if ((!defaultValue && defaultValue !== 0) || Number.isNaN(defaultValue)) { - throw new Error(`Missing environment variable: ${key}`); - } - - return defaultValue; - } - - const parsed = Number(value); - if (validations) { - if ( - Object.prototype.hasOwnProperty.call(validations, 'min') && - parsed < (validations.min as number) - ) { - throw new Error( - `Environment variable fails validation: min allowed val: ${validations.min}`, - ); - } - if ( - Object.prototype.hasOwnProperty.call(validations, 'max') && - parsed > (validations.max as number) - ) { - throw new Error( - `Environment variable fails validation: max allowed val: ${validations.max}`, - ); - } - } - - return parsed; -} - -export const constants: Constants = { - MANAGER_SERVICE: { - DOMAIN: getEnvVar( - 'RANGE_SDK_MANAGER_SERVICE_DOMAIN', - 'https://manager.range.org', - ), - FETCH_CONFIG_PATH: '/v1.0/range-sdk/config', - CREATE_ALERT_EVENT_PATH: '/v1.0/alert-event', - ACK_TASK_PATH: '/v1.0/rule-group/block/ack', - ACK_TICK_TASK_PATH: '/v1.0/rule-group/tick/ack', - FETCH_BLOCK_BY_NETWORK_AND_HEIGHT: '/v1.0/rule-group/block', - FETCH_BLOCKS_BY_RANGE: '/v1.0/rule-group/block/by-range', - FETCH_RULES_BY_RULE_GROUP_ID_PATH: (ruleGroupId: string) => - `/v1.0/rule-group/${ruleGroupId}/rules`, - FETCH_RULE_BY_RULE_GROUP_ID_AND_RULE_ID_PATH: (args: { - ruleGroupId: string; - ruleId: string; - }) => `/v1.0/rule-group/${args.ruleGroupId}/rule/${args.ruleId}`, - ACK_ERROR_TASK_PATH: '/v1.0/rule-group/block/error/ack', - POST_DEBUG_ALERT_PATH: '/v1.0/range-sdk/debug-alert', - }, - - RULE_QUARANTINE: { - PER_EXEC_TIME_CUT_OFF_MS: getEnvVarNumber( - 'RULE_QUARANTINE_PER_EXEC_TIME_CUT_OFF_MS', - 15000, - { - min: 5000, - max: 15000, - }, - ), - AVG_EXEC_TIME_CUT_OFF_MS: getEnvVarNumber( - 'RULE_QUARANTINE_AVG_EXEC_TIME_CUT_OFF_MS', - 1000, - { - min: 1000, - max: 3000, - }, - ), - AVG_EXEC_TIME_DEBUG_ALERT_MS: getEnvVarNumber( - 'RULE_QUARANTINE_AVG_EXEC_TIME_DEBUG_ALERT_MS', - 400, - { - min: 400, - max: 3000, - }, - ), - QUARANTINE_TIME_MINS: getEnvVarNumber( - 'RULE_QUARANTINE_QUARANTINE_TIME_MINS', - 15, - { - min: 5, - max: 30, - }, - ), - }, - - BLOCK_CACHE: { - MAX: 100, - }, - AXIOS: { - TIMEOUT: 15000, // 15 seconds - }, -}; diff --git a/src/cosmos/CosmosClient.ts b/src/cosmos/CosmosClient.ts deleted file mode 100644 index 95111d95..00000000 --- a/src/cosmos/CosmosClient.ts +++ /dev/null @@ -1,105 +0,0 @@ -import { cosmos, cosmwasm, ibc, osmosis } from 'osmojs'; -import axios from 'axios'; -import { - QueryBalanceResponse, - QuerySupplyOfResponse, -} from 'osmojs/cosmos/bank/v1beta1/query'; -import { QueryValidatorResponse } from 'osmojs/cosmos/staking/v1beta1/query'; -import { QueryContractInfoResponse } from 'osmojs/cosmwasm/wasm/v1/query'; - -export class CosmosClient { - constructor( - readonly rpcEndpoint: string, - readonly lcd?: string, - ) { - if (!rpcEndpoint) { - throw new Error('rpcEndpoint cannot be empty'); - } - } - - async balance(address: string, denom: string): Promise { - const client = await this.getCosmosRpcClient(); - return client.cosmos.bank.v1beta1.balance({ - address, - denom, - }); - } - - async supply(denom: string): Promise { - const client = await this.getCosmosRpcClient(); - return client.cosmos.bank.v1beta1.supplyOf({ - denom, - }); - } - - async validator(validatorAddr: string): Promise { - const client = await this.getCosmosRpcClient(); - return client.cosmos.staking.v1beta1.validator({ - validatorAddr, - }); - } - - async contractInfo(address: string): Promise { - const client = await this.getCosmwasmRpcClient(); - return client.cosmwasm.wasm.v1.contractInfo({ - address, - }); - } - - async fetchContractQuery(address: string, queryData: object) { - const client = await this.getCosmwasmRpcClient(); - const res = await client.cosmwasm.wasm.v1.smartContractState({ - address, - queryData: Buffer.from(JSON.stringify(queryData)), - }); - - return JSON.parse(Buffer.from(res.data).toString('utf8')); - } - - async fetchLatestHeight() { - const res = await axios.get(`${this.rpcEndpoint}/status`); - return res.data?.result.sync_info.latest_block_height; - } - - getCosmosRpcClient() { - return cosmos.ClientFactory.createRPCQueryClient({ - rpcEndpoint: this.rpcEndpoint, - }); - } - - getOsmosisRpcClient() { - return osmosis.ClientFactory.createRPCQueryClient({ - rpcEndpoint: this.rpcEndpoint, - }); - } - - getIbcRpcClient() { - return ibc.ClientFactory.createRPCQueryClient({ - rpcEndpoint: this.rpcEndpoint, - }); - } - - getCosmwasmRpcClient() { - return cosmwasm.ClientFactory.createRPCQueryClient({ - rpcEndpoint: this.rpcEndpoint, - }); - } - - async getValidators(): Promise< - | { - address: string; - start_height: string; - index_offset: string; - jailed_until: string; - tombstoned: boolean; - missed_blocks_counter: string; - }[] - | null - > { - if (!this.lcd) return Promise.resolve(null); - const res = await axios.get( - `${this.lcd}/cosmos/slashing/v1beta1/signing_infos?pagination.limit=1000000`, - ); - return res.data.info; - } -} diff --git a/src/e2e/bench-decode.ts b/src/e2e/bench-decode.ts new file mode 100644 index 00000000..b4de5ecc --- /dev/null +++ b/src/e2e/bench-decode.ts @@ -0,0 +1,234 @@ +/** + * Benchmark: Solana block FlatBuffer encode/decode pipeline + * + * Compares JSON pipeline (parse + encode + decode) vs Binary pipeline (decode only). + * Processes all .json blocks in the given directory, repeating each block N times. + * + * Usage: + * yarn build + * npx ts-node src/e2e/bench-decode.ts [block-dir] [iterations-per-block] + * + * Examples: + * npx ts-node src/e2e/bench-decode.ts # default: src/test_data/solana/, 100 iterations + * npx ts-node src/e2e/bench-decode.ts /path/to/blocks/ # custom dir, 100 iterations + * npx ts-node src/e2e/bench-decode.ts /path/to/blocks/ 50 # custom dir, 50 iterations + * node dist/e2e/bench-decode.js /path/to/blocks/ # run from built dist + */ + +import { readFileSync, readdirSync, existsSync } from 'fs'; +import * as path from 'path'; +import { + createSolanaBlockFromJson, + SolanaBlockWrapper, +} from '../wrappers/solana-block-wrapper'; + +const DEFAULT_DIR = path.join(__dirname, '..', 'test_data', 'solana'); +const blockDir = process.argv[2] || DEFAULT_DIR; +const REPEAT = parseInt(process.argv[3] || '100', 10); + +function formatBytes(bytes: number): string { + if (bytes < 1024) return `${bytes} B`; + if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`; + return `${(bytes / (1024 * 1024)).toFixed(2)} MB`; +} + +function percentile(sorted: number[], p: number): number { + const idx = Math.ceil((p / 100) * sorted.length) - 1; + return sorted[Math.max(0, idx)]; +} + +function computeStats(times: number[]) { + const sorted = [...times].sort((a, b) => a - b); + const avg = sorted.reduce((a, b) => a + b, 0) / sorted.length; + return { + avg, + p50: percentile(sorted, 50), + p95: percentile(sorted, 95), + p99: percentile(sorted, 99), + min: sorted[0], + max: sorted[sorted.length - 1], + }; +} + +function printStats(s: ReturnType) { + console.log(` Avg: ${s.avg.toFixed(2)} ms`); + console.log(` P50: ${s.p50.toFixed(2)} ms`); + console.log(` P95: ${s.p95.toFixed(2)} ms`); + console.log(` P99: ${s.p99.toFixed(2)} ms`); + console.log(` Min: ${s.min.toFixed(2)} ms`); + console.log(` Max: ${s.max.toFixed(2)} ms`); +} + +function fullDecode(encoded: Uint8Array) { + const wrapper = new SolanaBlockWrapper(encoded); + void wrapper.height; + void wrapper.network; + void wrapper.timestamp; + void wrapper.block_data; + const txs = wrapper.transactions; + if (txs.length > 0) { + void txs[0].transaction.signatures; + void txs[txs.length - 1].meta.fee; + } +} + +async function main() { + if (!existsSync(blockDir)) { + console.error(`Directory not found: ${blockDir}`); + console.error( + `Usage: npx ts-node src/e2e/bench-decode.ts [block-dir] [iterations]` + ); + process.exit(1); + } + + const files = readdirSync(blockDir) + .filter((f) => f.endsWith('.json')) + .sort(); + + if (files.length === 0) { + console.error(`No .json files found in: ${blockDir}`); + process.exit(1); + } + + console.log(`Solana FlatBuffer Benchmark`); + console.log(`Directory: ${blockDir}`); + console.log(`Blocks: ${files.length}`); + console.log( + `Iterations: ${REPEAT} per block (${files.length * REPEAT} total samples)` + ); + console.log(`Date: ${new Date().toISOString().split('T')[0]}`); + console.log(`Node: ${process.version}`); + console.log(`Platform: ${process.platform} ${process.arch}`); + + // Collect per-block metadata (first iteration only) + const perBlock: { + name: string; + txCount: number; + jsonBytes: number; + fbBytes: number; + }[] = []; + + // All timing samples + const allParse: number[] = []; + const allEncode: number[] = []; + const allDecode: number[] = []; + const allDecodeBin: number[] = []; + let totalJsonBytes = 0; + let totalFbBytes = 0; + let totalTxCount = 0; + + for (const file of files) { + const filePath = path.join(blockDir, file); + const jsonStr = readFileSync(filePath, 'utf8'); + const jsonBytes = Buffer.byteLength(jsonStr, 'utf8'); + let firstTxCount = 0; + let firstFbBytes = 0; + + for (let r = 0; r < REPEAT; r++) { + const parseStart = performance.now(); + const blockData = JSON.parse(jsonStr); + const parseMs = performance.now() - parseStart; + + const encodeStart = performance.now(); + const encoded = createSolanaBlockFromJson(blockData); + const encodeMs = performance.now() - encodeStart; + + const decodeStart = performance.now(); + fullDecode(encoded); + const decodeMs = performance.now() - decodeStart; + + const decodeBinStart = performance.now(); + fullDecode(encoded); + const decodeBinMs = performance.now() - decodeBinStart; + + allParse.push(parseMs); + allEncode.push(encodeMs); + allDecode.push(decodeMs); + allDecodeBin.push(decodeBinMs); + + if (r === 0) { + firstTxCount = blockData.transactions?.length ?? 0; + firstFbBytes = encoded.length; + } + } + + perBlock.push({ + name: file.replace('.json', ''), + txCount: firstTxCount, + jsonBytes, + fbBytes: firstFbBytes, + }); + totalJsonBytes += jsonBytes; + totalFbBytes += firstFbBytes; + totalTxCount += firstTxCount; + } + + // --- Results --- + const n = allParse.length; + console.log(`\n${'='.repeat(60)}`); + console.log(` RESULTS (${n} samples across ${files.length} blocks)`); + console.log(`${'='.repeat(60)}`); + + console.log(`\nTotal transactions: ${totalTxCount.toLocaleString()}`); + console.log(`Avg tx/block: ${(totalTxCount / files.length).toFixed(0)}`); + console.log(`Total JSON size: ${formatBytes(totalJsonBytes)}`); + console.log(`Total FB size: ${formatBytes(totalFbBytes)}`); + console.log(`Avg JSON size: ${formatBytes(totalJsonBytes / files.length)}`); + console.log(`Avg FB size: ${formatBytes(totalFbBytes / files.length)}`); + console.log( + `Avg compression: ${((1 - totalFbBytes / totalJsonBytes) * 100).toFixed(1)}%` + ); + + const parseStats = computeStats(allParse); + console.log(`\n--- JSON.parse ---`); + printStats(parseStats); + + const encodeStats = computeStats(allEncode); + console.log(`\n--- Encode (obj -> FlatBuffer) ---`); + printStats(encodeStats); + + const decodeStats = computeStats(allDecode); + console.log(`\n--- Decode (FlatBuffer -> Wrapper) ---`); + printStats(decodeStats); + + const jsonTimes = allParse.map((p, i) => p + allEncode[i] + allDecode[i]); + const jsonStats = computeStats(jsonTimes); + console.log(`\n--- JSON Pipeline (parse + encode + decode) ---`); + printStats(jsonStats); + console.log(` Throughput: ~${(1000 / jsonStats.avg).toFixed(0)} blocks/sec`); + + const binStats = computeStats(allDecodeBin); + console.log(`\n--- Binary Pipeline (decode only) ---`); + printStats(binStats); + console.log(` Throughput: ~${(1000 / binStats.avg).toFixed(0)} blocks/sec`); + + // --- Comparison --- + console.log(`\n${'='.repeat(60)}`); + console.log(` COMPARISON`); + console.log(`${'='.repeat(60)}`); + const speedup = (jsonStats.avg / binStats.avg).toFixed(1); + const saved = (jsonStats.avg - binStats.avg).toFixed(2); + const pct = ((1 - binStats.avg / jsonStats.avg) * 100).toFixed(0); + console.log(`\n JSON pipeline: ${jsonStats.avg.toFixed(2)} ms/block`); + console.log(` Binary pipeline: ${binStats.avg.toFixed(2)} ms/block`); + console.log(` Speedup: ${speedup}x`); + console.log(` Time saved: ${saved} ms/block (${pct}%)`); + + const parsePct = ((parseStats.avg / jsonStats.avg) * 100).toFixed(0); + const encodePct = ((encodeStats.avg / jsonStats.avg) * 100).toFixed(0); + const decodePct = ((decodeStats.avg / jsonStats.avg) * 100).toFixed(0); + console.log(`\n Breakdown (JSON mode):`); + console.log( + ` JSON.parse: ${parseStats.avg.toFixed(2)} ms (${parsePct}%)` + ); + console.log( + ` Encode: ${encodeStats.avg.toFixed(2)} ms (${encodePct}%)` + ); + console.log( + ` Decode: ${decodeStats.avg.toFixed(2)} ms (${decodePct}%)` + ); + + console.log(`\n Peak RSS: ${formatBytes(process.memoryUsage().rss)}`); +} + +main().catch(console.error); diff --git a/src/e2e/generate-report.ts b/src/e2e/generate-report.ts new file mode 100644 index 00000000..b58a4599 --- /dev/null +++ b/src/e2e/generate-report.ts @@ -0,0 +1,359 @@ +/** + * Multi-chain FlatBuffer benchmark report. + * + * Benchmarks encode/decode for Solana, ETH, and Cosmos blocks, + * then writes a combined report to block_decoding_benchmark_results.txt. + * + * Usage: + * node dist/e2e/generate-report.js [-c cycles] + * + * Examples: + * node dist/e2e/generate-report.js # 1 cycle per block + * node dist/e2e/generate-report.js -c 10 # 10 cycles per block + */ + +import { readFileSync, readdirSync, writeFileSync, existsSync } from 'fs'; +import * as path from 'path'; +import { + createSolanaBlockFromJson, + SolanaBlockWrapper, +} from '../wrappers/solana-block-wrapper'; + +// ── Args ── + +function parseArgs() { + const args = process.argv.slice(2); + let cycles = 1; + for (let i = 0; i < args.length; i++) { + if (args[i] === '-c' && args[i + 1]) { + cycles = parseInt(args[++i], 10); + } + } + return { cycles }; +} + +const { cycles: REPEAT } = parseArgs(); +const BASE = path.join(process.cwd(), 'src', 'test_data'); +const OUTPUT_FILE = path.join( + process.cwd(), + 'block_decoding_benchmark_results.txt' +); + +// ── Chain configs ── + +interface ChainConfig { + name: string; + dir: string; + encode: (data: any) => Uint8Array; + fullDecode: (buf: Uint8Array) => void; + prepare: (raw: any) => any; + getTxCount: (data: any) => number; +} + +const CHAINS: ChainConfig[] = [ + { + name: 'Solana', + dir: path.join(BASE, 'solana'), + encode: createSolanaBlockFromJson, + fullDecode: (buf) => { + const w = new SolanaBlockWrapper(buf); + void w.height; + void w.network; + void w.timestamp; + void w.block_data; + const txs = w.transactions; + if (txs.length > 0) { + void txs[0].transaction.signatures; + void txs[txs.length - 1].meta.fee; + } + }, + prepare: (raw) => ({ + ...raw, + height: raw.blockHeight, + timestamp: raw.blockTime, + network: 'solana', + blockData: { + slot: String(raw.blockHeight), + parentSlot: String(raw.parentSlot), + previousBlockhash: raw.previousBlockhash || '', + }, + }), + getTxCount: (data) => data.transactions?.length ?? 0, + }, +]; + +// ── Helpers ── + +function formatBytes(bytes: number): string { + if (bytes < 1024) return `${bytes} B`; + if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`; + return `${(bytes / (1024 * 1024)).toFixed(2)} MB`; +} + +function percentile(sorted: number[], p: number): number { + const idx = Math.ceil((p / 100) * sorted.length) - 1; + return sorted[Math.max(0, idx)]; +} + +function computeStats(times: number[]) { + const sorted = [...times].sort((a, b) => a - b); + const avg = sorted.reduce((a, b) => a + b, 0) / sorted.length; + return { + avg, + p50: percentile(sorted, 50), + p95: percentile(sorted, 95), + }; +} + +function fmtStats(s: ReturnType): string { + return `Avg: ${s.avg.toFixed(2)} ms | P50: ${s.p50.toFixed(2)} ms | P95: ${s.p95.toFixed(2)} ms`; +} + +// ── Benchmark one chain ── + +interface ChainResult { + name: string; + blockCount: number; + totalTxCount: number; + totalJsonBytes: number; + totalFbBytes: number; + parseStats: ReturnType; + encodeStats: ReturnType; + decodeStats: ReturnType; + jsonStats: ReturnType; + binStats: ReturnType; + top5: { + name: string; + txCount: number; + jsonBytes: number; + avgTotal: number; + }[]; +} + +function benchmarkChain( + chain: ChainConfig, + repeat: number, + out: (s?: string) => void +): ChainResult | null { + if (!existsSync(chain.dir)) { + out(` Skipping ${chain.name} — directory not found: ${chain.dir}`); + out(); + return null; + } + + const files = readdirSync(chain.dir) + .filter((f) => f.endsWith('.json')) + .sort(); + + if (files.length === 0) { + out(` Skipping ${chain.name} — no .json files`); + out(); + return null; + } + + const allParse: number[] = []; + const allEncode: number[] = []; + const allDecode: number[] = []; + const allDecodeBin: number[] = []; + let totalJsonBytes = 0; + let totalFbBytes = 0; + let totalTxCount = 0; + + const perBlock: { + name: string; + txCount: number; + jsonBytes: number; + fbBytes: number; + avgTotal: number; + }[] = []; + + for (const file of files) { + const jsonStr = readFileSync(path.join(chain.dir, file), 'utf8'); + const jsonBytes = Buffer.byteLength(jsonStr, 'utf8'); + let firstTxCount = 0; + let firstFbBytes = 0; + const blockTotals: number[] = []; + + for (let r = 0; r < repeat; r++) { + const parseStart = performance.now(); + const raw = JSON.parse(jsonStr); + const parseMs = performance.now() - parseStart; + + const prepared = chain.prepare(raw); + + const encodeStart = performance.now(); + const encoded = chain.encode(prepared); + const encodeMs = performance.now() - encodeStart; + + const decodeStart = performance.now(); + chain.fullDecode(encoded); + const decodeMs = performance.now() - decodeStart; + + const decodeBinStart = performance.now(); + chain.fullDecode(encoded); + const decodeBinMs = performance.now() - decodeBinStart; + + allParse.push(parseMs); + allEncode.push(encodeMs); + allDecode.push(decodeMs); + allDecodeBin.push(decodeBinMs); + blockTotals.push(parseMs + encodeMs + decodeMs); + + if (r === 0) { + firstTxCount = chain.getTxCount(raw); + firstFbBytes = encoded.length; + } + } + + perBlock.push({ + name: file.replace('.json', ''), + txCount: firstTxCount, + jsonBytes, + fbBytes: firstFbBytes, + avgTotal: blockTotals.reduce((a, b) => a + b, 0) / blockTotals.length, + }); + totalJsonBytes += jsonBytes; + totalFbBytes += firstFbBytes; + totalTxCount += firstTxCount; + } + + const parseStats = computeStats(allParse); + const encodeStats = computeStats(allEncode); + const decodeStats = computeStats(allDecode); + const jsonTimes = allParse.map((p, i) => p + allEncode[i] + allDecode[i]); + const jsonStats = computeStats(jsonTimes); + const binStats = computeStats(allDecodeBin); + + const top5 = [...perBlock] + .sort((a, b) => b.avgTotal - a.avgTotal) + .slice(0, 5); + + // Print chain section + const speedup = (jsonStats.avg / binStats.avg).toFixed(1); + const pct = ((1 - binStats.avg / jsonStats.avg) * 100).toFixed(0); + const parsePct = ((parseStats.avg / jsonStats.avg) * 100).toFixed(0); + const encodePct = ((encodeStats.avg / jsonStats.avg) * 100).toFixed(0); + const decodePct = ((decodeStats.avg / jsonStats.avg) * 100).toFixed(0); + + out( + ` Blocks: ${files.length} | Txs: ${totalTxCount.toLocaleString()} | Avg tx/block: ${(totalTxCount / files.length).toFixed(0)}` + ); + out( + ` JSON: ${formatBytes(totalJsonBytes)} | FB: ${formatBytes(totalFbBytes)} | Compression: ${((1 - totalFbBytes / totalJsonBytes) * 100).toFixed(1)}%` + ); + out(); + out(` --- JSON.parse ---`); + out(` ${fmtStats(parseStats)}`); + out(` --- Encode (obj -> FlatBuffer) ---`); + out(` ${fmtStats(encodeStats)}`); + out(` --- Decode (FlatBuffer -> Wrapper) ---`); + out(` ${fmtStats(decodeStats)}`); + out(); + out( + ` JSON pipeline: ${jsonStats.avg.toFixed(2)} ms/block (~${(1000 / jsonStats.avg).toFixed(0)} blocks/sec)` + ); + out( + ` Binary pipeline: ${binStats.avg.toFixed(2)} ms/block (~${(1000 / binStats.avg).toFixed(0)} blocks/sec)` + ); + out(` Speedup: ${speedup}x (${pct}% faster)`); + out(); + out( + ` Breakdown: Parse ${parseStats.avg.toFixed(1)}ms (${parsePct}%) | Encode ${encodeStats.avg.toFixed(1)}ms (${encodePct}%) | Decode ${decodeStats.avg.toFixed(1)}ms (${decodePct}%)` + ); + out(); + + out(` Top 5 heaviest:`); + out( + ` ${'Block'.padEnd(18)}${'TXs'.padStart(6)}${'JSON'.padStart(10)}${'Total'.padStart(10)}` + ); + for (const b of top5) { + out( + ` ${b.name.padEnd(18)}${String(b.txCount).padStart(6)}${formatBytes(b.jsonBytes).padStart(10)}${(b.avgTotal.toFixed(1) + 'ms').padStart(10)}` + ); + } + out(); + + return { + name: chain.name, + blockCount: files.length, + totalTxCount, + totalJsonBytes, + totalFbBytes, + parseStats, + encodeStats, + decodeStats, + jsonStats, + binStats, + top5, + }; +} + +// ── Main ── + +async function main() { + const lines: string[] = []; + const out = (s = '') => { + lines.push(s); + console.log(s); + }; + + const sep = '='.repeat(64); + + out(`FlatBuffer Benchmark Report`); + out(`Date: ${new Date().toISOString().split('T')[0]}`); + out(`Cycles: ${REPEAT} per block`); + out(`Node: ${process.version}`); + out(`Platform: ${process.platform} ${process.arch}`); + out(); + + const results: ChainResult[] = []; + + for (const chain of CHAINS) { + out(sep); + out(` ${chain.name.toUpperCase()}`); + out(sep); + out(); + + const result = benchmarkChain(chain, REPEAT, out); + if (result) results.push(result); + } + + // ── Combined Summary ── + if (results.length > 1) { + out(sep); + out(` COMBINED SUMMARY`); + out(sep); + out(); + + const header = `${'Chain'.padEnd(10)}${'Blocks'.padStart(8)}${'Txs'.padStart(8)}${'JSON'.padStart(10)}${'FB'.padStart(10)}${'JSON ms'.padStart(10)}${'Bin ms'.padStart(10)}${'Speedup'.padStart(10)}`; + out(header); + + for (const r of results) { + out( + `${r.name.padEnd(10)}${String(r.blockCount).padStart(8)}${r.totalTxCount.toLocaleString().padStart(8)}${formatBytes(r.totalJsonBytes).padStart(10)}${formatBytes(r.totalFbBytes).padStart(10)}${(r.jsonStats.avg.toFixed(1) + 'ms').padStart(10)}${(r.binStats.avg.toFixed(1) + 'ms').padStart(10)}${((r.jsonStats.avg / r.binStats.avg).toFixed(1) + 'x').padStart(10)}` + ); + } + + out(); + + // Totals + const totalBlocks = results.reduce((s, r) => s + r.blockCount, 0); + const totalTxs = results.reduce((s, r) => s + r.totalTxCount, 0); + const totalJson = results.reduce((s, r) => s + r.totalJsonBytes, 0); + const totalFb = results.reduce((s, r) => s + r.totalFbBytes, 0); + + out(` Total: ${totalBlocks} blocks, ${totalTxs.toLocaleString()} txs`); + out( + ` Total JSON: ${formatBytes(totalJson)} | Total FB: ${formatBytes(totalFb)}` + ); + out(); + } + + out(` Peak RSS: ${formatBytes(process.memoryUsage().rss)}`); + out(); + + writeFileSync(OUTPUT_FILE, lines.join('\n') + '\n'); + console.log(`Report written to ${OUTPUT_FILE}`); +} + +main().catch(console.error); diff --git a/src/e2e/load-test.ts b/src/e2e/load-test.ts new file mode 100644 index 00000000..8d48fe53 --- /dev/null +++ b/src/e2e/load-test.ts @@ -0,0 +1,318 @@ +/** + * Load Test Orchestrator + * + * Forks N runner child processes, waits for them to connect to Redis, + * then pushes synthetic Solana blocks into the stream for them to consume. + * + * Usage: + * yarn load-test --blocks 100 --runners 10 --rules 100 --perc 10 + */ +import { fork, ChildProcess } from 'child_process'; +import { join } from 'path'; +import { Command } from 'commander'; +import { createClient } from 'redis'; + +// ── CLI ────────────────────────────────────────────────────────── + +const program = new Command(); +program + .option('--blocks ', 'Number of blocks to push', '100') + .option('--runners ', 'Number of runner processes', '10') + .option('--rules ', 'Rules per runner', '100') + .option('--perc ', 'PercBasedBenchmark fire rate %', '10') + .option('--redis ', 'Redis URL', '127.0.0.1:6379') + .parse(); + +const opts = program.opts(); +const BLOCK_COUNT = parseInt(opts.blocks); +const RUNNER_COUNT = parseInt(opts.runners); +const RULE_COUNT = parseInt(opts.rules); +const PERC = parseInt(opts.perc); +const REDIS_URL = opts.redis; + +const STREAM_NAME = `load-test-${Date.now()}`; +const CONSUMER_GROUP = 'load-test-group'; +const PROCESSORS_FILE = join(__dirname, '..', 'processors', 'processors'); + +// ── Helpers ────────────────────────────────────────────────────── + +function makeSolanaBlock(height: number) { + return { + height, + network: 'solana', + timestamp: Math.floor(Date.now() / 1000), + blockData: { + slot: String(height), + parentSlot: String(height - 1), + previousBlockhash: 'load-test-hash', + }, + transactions: [], + }; +} + +function percentile(sorted: number[], p: number): number { + if (sorted.length === 0) return 0; + const idx = Math.floor(sorted.length * p); + return sorted[Math.min(idx, sorted.length - 1)]; +} + +function avg(arr: number[]): number { + if (arr.length === 0) return 0; + return arr.reduce((a, b) => a + b, 0) / arr.length; +} + +function padRight(str: string, len: number): string { + return str.padEnd(len); +} + +// ── Main ───────────────────────────────────────────────────────── + +async function main() { + console.log('\n=== Load Test Configuration ==='); + console.log(` Blocks: ${BLOCK_COUNT}`); + console.log(` Runners: ${RUNNER_COUNT}`); + console.log(` Rules: ${RULE_COUNT} per runner`); + console.log(` Perc: ${PERC}%`); + console.log(` Redis: ${REDIS_URL}`); + console.log(` Stream: ${STREAM_NAME}`); + console.log( + ` Expected tasks: ~${BLOCK_COUNT} blocks / ${RUNNER_COUNT} runners * ${RULE_COUNT} rules = ~${Math.ceil(BLOCK_COUNT / RUNNER_COUNT) * RULE_COUNT} per runner` + ); + console.log(); + + // ── 1. Connect to Redis and create stream ── + const client = createClient({ url: `redis://${REDIS_URL}` }); + await client.connect(); + + // Create stream + consumer group (empty stream, runners will block-wait) + try { + await client.xGroupCreate(STREAM_NAME, CONSUMER_GROUP, '0', { + MKSTREAM: true, + }); + } catch (err: any) { + if (!err.message.includes('BUSYGROUP')) throw err; + } + + // ── 2. Fork runner processes and wait for them to be ready ── + console.log(`Forking ${RUNNER_COUNT} runners...`); + + const children: ChildProcess[] = []; + const readyPromises: Promise[] = []; + const statsPromises: Promise[] = []; + + for (let i = 0; i < RUNNER_COUNT; i++) { + const child = fork(join(__dirname, 'load-test-runner.js'), [], { + env: { + ...process.env, + LOG_LEVEL: 'error', + NODE_ENV: 'local', + }, + stdio: ['pipe', 'pipe', 'pipe', 'ipc'], + }); + + child.stderr?.on('data', (data: Buffer) => { + const msg = data.toString().trim(); + if (msg) console.error(` [runner-${i}] ${msg}`); + }); + + const readyPromise = new Promise((resolve) => { + const onMessage = (msg: any) => { + if (msg.type === 'ready') { + child.removeListener('message', onMessage); + resolve(); + } + }; + child.on('message', onMessage); + }); + + const statsPromise = new Promise((resolve, reject) => { + child.on('message', (msg: any) => { + if (msg.type === 'stats') resolve(msg.stats); + }); + child.on('exit', (code) => { + if (code !== 0 && code !== null) { + reject(new Error(`Runner ${i} exited with code ${code}`)); + } + }); + child.on('error', reject); + }); + + child.send({ + type: 'config', + config: { + runnerId: i, + ruleCount: RULE_COUNT, + perc: PERC, + streamName: STREAM_NAME, + consumerGroup: CONSUMER_GROUP, + redisUrl: REDIS_URL, + processorsFile: PROCESSORS_FILE, + }, + }); + + children.push(child); + readyPromises.push(readyPromise); + statsPromises.push(statsPromise); + } + + // Wait for all runners to init pool + connect to Redis + await Promise.all(readyPromises); + console.log(` All ${RUNNER_COUNT} runners ready\n`); + + // ── 3. Push blocks into the stream ── + console.log('Pushing blocks to Redis...'); + const pushStart = Date.now(); + for (let i = 1; i <= BLOCK_COUNT; i++) { + const block = makeSolanaBlock(i); + await client.xAdd(STREAM_NAME, '*', { + message: JSON.stringify(block), + }); + } + const pushTime = Date.now() - pushStart; + console.log( + ` Pushed ${BLOCK_COUNT} blocks in ${pushTime}ms (${((BLOCK_COUNT / pushTime) * 1000).toFixed(0)} blocks/sec)\n` + ); + + // ── 4. Wait for all runners to finish ── + console.log('Waiting for runners to finish...'); + const runStart = Date.now(); + + let allStats: any[]; + try { + allStats = await Promise.all(statsPromises); + } catch (err) { + console.error('Runner failed:', err); + children.forEach((c) => c.kill()); + await client.del(STREAM_NAME); + await client.disconnect(); + process.exit(1); + } + + const totalRunTime = Date.now() - runStart; + + // ── 5. Clean up Redis stream ── + await client.del(STREAM_NAME); + await client.disconnect(); + + // ── 6. Print results ── + console.log('\n' + '='.repeat(80)); + console.log(' LOAD TEST RESULTS'); + console.log('='.repeat(80)); + + console.log('\n--- Per-Runner Breakdown ---\n'); + console.log( + padRight('Runner', 10) + + padRight('Blocks', 8) + + padRight('Tasks', 8) + + padRight('Events', 8) + + padRight('Success', 9) + + padRight('Fail', 6) + + padRight('Timeout', 9) + + padRight('Time(ms)', 10) + + padRight('Tasks/s', 9) + + padRight('AvgThread', 11) + + padRight('P95', 8) + ); + console.log('-'.repeat(96)); + + const allThreadTimes: number[] = []; + const allWaitTimes: number[] = []; + let totalBlocks = 0; + let totalTasks = 0; + let totalEvents = 0; + let totalSuccess = 0; + let totalFailure = 0; + let totalTimeout = 0; + + for (const s of allStats) { + const tasksPerSec = + s.totalTasks > 0 + ? ((s.totalTasks / s.totalTimeMs) * 1000).toFixed(1) + : '0'; + const avgThread = avg(s.threadTimes).toFixed(1); + const p95 = percentile(s.threadTimes, 0.95).toFixed(1); + + console.log( + padRight(`#${s.runnerId}`, 10) + + padRight(String(s.blocksProcessed), 8) + + padRight(String(s.totalTasks), 8) + + padRight(String(s.totalEvents), 8) + + padRight(String(s.successCount), 9) + + padRight(String(s.failureCount), 6) + + padRight(String(s.timeoutCount), 9) + + padRight(String(s.totalTimeMs), 10) + + padRight(tasksPerSec, 9) + + padRight(avgThread, 11) + + padRight(p95, 8) + ); + + allThreadTimes.push(...s.threadTimes); + allWaitTimes.push(...s.waitTimes); + totalBlocks += s.blocksProcessed; + totalTasks += s.totalTasks; + totalEvents += s.totalEvents; + totalSuccess += s.successCount; + totalFailure += s.failureCount; + totalTimeout += s.timeoutCount; + } + + allThreadTimes.sort((a, b) => a - b); + allWaitTimes.sort((a, b) => a - b); + + console.log('\n--- Aggregate ---\n'); + console.log(` Total blocks processed: ${totalBlocks} / ${BLOCK_COUNT}`); + console.log(` Total tasks: ${totalTasks}`); + console.log(` Total events: ${totalEvents}`); + if (totalTasks > 0) { + console.log( + ` Event rate: ${((totalEvents / totalTasks) * 100).toFixed(1)}% (expected ~${PERC}%)` + ); + console.log(); + console.log( + ` Success: ${totalSuccess} (${((totalSuccess / totalTasks) * 100).toFixed(1)}%)` + ); + console.log( + ` Failure: ${totalFailure} (${((totalFailure / totalTasks) * 100).toFixed(1)}%)` + ); + console.log( + ` Timeout: ${totalTimeout} (${((totalTimeout / totalTasks) * 100).toFixed(1)}%)` + ); + } + console.log(); + console.log(` Wall time: ${totalRunTime}ms`); + if (totalTasks > 0) { + console.log( + ` Aggregate tasks/s: ${((totalTasks / totalRunTime) * 1000).toFixed(1)}` + ); + console.log(); + console.log(` Thread time avg: ${avg(allThreadTimes).toFixed(1)}ms`); + console.log( + ` Thread time P50: ${percentile(allThreadTimes, 0.5).toFixed(1)}ms` + ); + console.log( + ` Thread time P95: ${percentile(allThreadTimes, 0.95).toFixed(1)}ms` + ); + console.log( + ` Thread time P99: ${percentile(allThreadTimes, 0.99).toFixed(1)}ms` + ); + console.log(); + console.log(` Wait time avg: ${avg(allWaitTimes).toFixed(1)}ms`); + console.log( + ` Wait time P50: ${percentile(allWaitTimes, 0.5).toFixed(1)}ms` + ); + console.log( + ` Wait time P95: ${percentile(allWaitTimes, 0.95).toFixed(1)}ms` + ); + console.log( + ` Wait time P99: ${percentile(allWaitTimes, 0.99).toFixed(1)}ms` + ); + } + console.log('\n' + '='.repeat(80) + '\n'); + + process.exit(0); +} + +main().catch((err) => { + console.error('Load test failed:', err); + process.exit(1); +}); diff --git a/src/e2e/pipeline-eth.ts b/src/e2e/pipeline-eth.ts new file mode 100644 index 00000000..a03b0c98 --- /dev/null +++ b/src/e2e/pipeline-eth.ts @@ -0,0 +1,194 @@ +/** + * E2E ETH Pipeline Test (plain Node.js — no test framework) + * + * Run: yarn test:e2e:eth + * + * Validates that real EVM blocks from test_data/eth/ survive the full pipeline: + * JSON block → processPayload → JSON.stringify → SharedArrayBuffer → worker → TextDecoder → JSON.parse → processor callback + * + * The processor verifies the block object is fully intact (nested fields, arrays, hex values). + */ +import 'reflect-metadata'; +import assert from 'node:assert/strict'; +import { join } from 'path'; +import { readFileSync, readdirSync } from 'fs'; +import { initPool, closePool } from '../threadpool/pool'; +import { processPayload } from '../processors/taskProcessor'; +import { IAlertRule } from '../types/IAlertRule'; +import { IEvent } from '../types/IEvent'; + +const processorsFile = join(__dirname, 'test-processors-eth.js'); + +const CHAIN_ID_TO_NETWORK: Record = { + '1': 'eth', + '10': 'op', + '137': 'pol', + '42161': 'arb1', + '56': 'bsc', + '8453': 'base', +}; + +// ── Helpers ───────────────────────────────────────────────────── + +/** + * Normalize an EVM block to have top-level height, network, timestamp. + * Mirrors what runner.ts normalizeBlock() does in production. + */ +function normalizeEvmBlock(raw: any, chainId: string = '1'): any { + const block = { ...raw, chain_id: chainId }; + + if (block.result?.number) { + block.height = parseInt(block.result.number, 16); + block.timestamp = block.result.timestamp + ? new Date(parseInt(block.result.timestamp, 16) * 1000).toISOString() + : undefined; + } + + if (block.network === undefined && block.chain_id !== undefined) { + block.network = + CHAIN_ID_TO_NETWORK[String(block.chain_id)] || String(block.chain_id); + } + + return block; +} + +function makeEthBlockRule(): IAlertRule { + return { + id: 'eth-block-rule-1', + ruleType: 'e2e-eth-block', + network: 'eth', + parameters: {}, + createdAt: new Date().toISOString(), + triggerMode: 'BLOCK' as const, + severity: 'info', + }; +} + +let passed = 0; +let failed = 0; + +function check(label: string, fn: () => void) { + try { + fn(); + passed++; + console.log(` ✓ ${label}`); + } catch (err: any) { + failed++; + console.error(` ✗ ${label}`); + console.error(` ${err.message}`); + } +} + +// ── Main ──────────────────────────────────────────────────────── + +async function main() { + try { + // ── 1. Set minimal env vars ── + process.env.RANGE_SDK_TOKEN = 'e2e-test-runner.fake-token'; + + // ── 2. Load ETH test processors ── + console.log('⏳ Loading ETH test processors...'); + await import('./test-processors-eth'); + console.log('✓ ETH processor registered'); + + // ── 3. Init Piscina thread pool ── + console.log('⏳ Starting thread pool...'); + const workerFile = join(__dirname, '..', 'threadpool', 'worker.js'); + await initPool({ + filename: workerFile, + maxThreads: 2, + }); + console.log('✓ Thread pool ready (2 threads)'); + + // ── 4. Load real EVM blocks from test_data ── + const testDataDir = join(process.cwd(), 'src', 'test_data', 'eth'); + const blockFiles = readdirSync(testDataDir) + .filter((f) => f.endsWith('.json')) + .sort() + .slice(0, 5); // test with 5 blocks + + console.log( + `\n── Processing ${blockFiles.length} real ETH blocks (JSON pipeline) ──` + ); + + const rule = makeEthBlockRule(); + const allEvents: IEvent[] = []; + + for (const file of blockFiles) { + const raw = JSON.parse(readFileSync(join(testDataDir, file), 'utf8')); + const block = normalizeEvmBlock(raw); + const txCount = block.result?.transactions?.length ?? 0; + + const results = await processPayload({ + blockData: block, + ruleList: [rule], + processorsFile, + }); + + const events = results.flatMap((r) => r.events); + allEvents.push(...events); + console.log( + ` Block ${file.replace('.json', '')}: ${txCount} txs → ${events.length} event` + ); + } + + // ── 5. Assertions ── + console.log('\n── Assertions ──'); + + check(`Processed ${blockFiles.length} blocks`, () => { + assert.equal(allEvents.length, blockFiles.length); + }); + + check('All events report valid block structure', () => { + for (const event of allEvents) { + assert.equal( + event.details.valid, + true, + `Block validation failed: ${event.details.message}` + ); + } + }); + + check('All events have transaction counts', () => { + for (const event of allEvents) { + assert.ok( + event.details.txCount !== undefined, + 'missing txCount in event details' + ); + } + }); + + check('All events have required fields', () => { + for (const event of allEvents) { + assert.ok(event.id, 'missing id'); + assert.ok(event.alertRuleId, 'missing alertRuleId'); + assert.ok(event.caption, 'missing caption'); + assert.ok(event.time, 'missing time'); + } + }); + + check('All event IDs are unique', () => { + const ids = new Set(allEvents.map((e) => e.id)); + assert.equal(ids.size, allEvents.length); + }); + + // ── Summary ── + console.log(`\n${'─'.repeat(40)}`); + if (failed === 0) { + console.log(`✅ All ${passed} checks passed`); + } else { + console.log(`❌ ${failed} failed, ${passed} passed`); + } + } finally { + console.log('\n⏳ Cleaning up...'); + await closePool(); + console.log('✓ Done\n'); + } + + process.exit(failed > 0 ? 1 : 0); +} + +main().catch((err) => { + console.error('E2E ETH test crashed:', err); + process.exit(1); +}); diff --git a/src/e2e/pipeline-solana-json.ts b/src/e2e/pipeline-solana-json.ts new file mode 100644 index 00000000..ecf814fe --- /dev/null +++ b/src/e2e/pipeline-solana-json.ts @@ -0,0 +1,77 @@ +/** + * E2E Solana JSON Pipeline Test + * + * Run: yarn test:e2e:solana-json + * + * Configure BLOCKS and RULES below, then run. Fetches real blocks via + * getCachedBlock, processes them through the full pipeline, and logs results. + */ +import { join } from 'path'; + +import { + setupPipeline, + destroyPipeline, + processPayload, + getCachedBlock, + IAlertRule, +} from './../index'; + +// ── Configure your test ───────────────────────────────────────── + +const BLOCKS = [ + { network: 'solana', height: '327418425' }, + { network: 'solana', height: '327418426' }, + { network: 'solana', height: '327418427' }, + { network: 'solana', height: '327418428' }, + { network: 'solana', height: '327418429' }, +]; + +const RULES: IAlertRule[] = [ + { + id: 'rule-1', + ruleType: 'e2e-block-1', + network: 'solana', + parameters: {}, + createdAt: new Date().toISOString(), + triggerMode: 'BLOCK', + severity: 'info', + }, +]; + +const processorsFile = join(__dirname, 'test-processors.js'); + +// ── Main ──────────────────────────────────────────────────────── + +async function main() { + const ctx = await setupPipeline({ processorsFile, maxThreads: 1 }); + + let totalEvents = 0; + + for (const { network, height } of BLOCKS) { + const block = await getCachedBlock(network, height); + + const results = await processPayload({ + blockData: block, + ruleList: RULES, + processorsFile, + }); + + const events = results.flatMap((r) => r.events); + totalEvents += events.length; + + console.log(`${network}/${height}: ${events.length} events`); + for (const e of events) { + console.log(` [${e.alertRuleId}] ${e.caption}`); + } + } + + console.log( + `\n${BLOCKS.length} blocks × ${RULES.length} rules → ${totalEvents} events` + ); + await destroyPipeline(ctx); +} + +main().catch((err) => { + console.error(err); + process.exit(1); +}); diff --git a/src/e2e/pipeline-solana.ts b/src/e2e/pipeline-solana.ts new file mode 100644 index 00000000..37e400bf --- /dev/null +++ b/src/e2e/pipeline-solana.ts @@ -0,0 +1,319 @@ +/** + * E2E Solana Pipeline Test (plain Node.js — no test framework) + * + * Run: yarn test:e2e:solana + * + * Full pipeline: + * Solana blocks → Piscina thread pool → processors (FlatBuffer path) → events + * + * Tests both JSON and binary (FlatBuffer) block processing paths, + * plus Redis stream round-trips for JSON and binary payloads. + */ +import 'reflect-metadata'; +import assert from 'node:assert/strict'; +import { join } from 'path'; +import { GenericContainer, StartedTestContainer } from 'testcontainers'; +import { + createRedisClient, + publishToStream, + publishBinaryToStream, +} from '../services/consumer-redis'; +import { + convertSolanaBlockJsonToBuffer, + SolanaBlockWrapper, +} from '../wrappers/solana-block-wrapper'; +import { initPool, closePool } from '../threadpool/pool'; +import { processPayload } from '../processors/taskProcessor'; +import { IAlertRule } from '../types/IAlertRule'; +import { IEvent } from '../types/IEvent'; + +// ── Constants ─────────────────────────────────────────────────── + +const BLOCK_COUNT = 5; +const TICK_COUNT = 5; +const BLOCK_RULE_COUNT = 5; +const TICK_RULE_COUNT = 5; +const EXPECTED_EVENTS = + BLOCK_COUNT * BLOCK_RULE_COUNT + TICK_COUNT * TICK_RULE_COUNT; // 50 + +const processorsFile = join(__dirname, 'test-processors.js'); + +// ── Helpers ───────────────────────────────────────────────────── + +function makeBlockRules(): IAlertRule[] { + return Array.from({ length: BLOCK_RULE_COUNT }, (_, i) => ({ + id: `block-rule-${i + 1}`, + ruleType: `e2e-block-${i + 1}`, + network: 'solana', + parameters: {}, + createdAt: new Date().toISOString(), + triggerMode: 'BLOCK' as const, + severity: 'info', + })); +} + +function makeTickRules(): IAlertRule[] { + return Array.from({ length: TICK_RULE_COUNT }, (_, i) => ({ + id: `tick-rule-${i + 1}`, + ruleType: `e2e-tick-${i + 1}`, + network: 'solana', + parameters: {}, + createdAt: new Date().toISOString(), + triggerMode: 'TICK' as const, + severity: 'info', + })); +} + +function makeSolanaBlock(height: number) { + return { + height, + network: 'solana', + timestamp: Math.floor(Date.now() / 1000), + blockData: { + slot: String(height), + parentSlot: String(height - 1), + previousBlockhash: 'abc123', + }, + transactions: [], + }; +} + +let passed = 0; +let failed = 0; + +function check(label: string, fn: () => void) { + try { + fn(); + passed++; + console.log(` ✓ ${label}`); + } catch (err: any) { + failed++; + console.error(` ✗ ${label}`); + console.error(` ${err.message}`); + } +} + +// ── Main ──────────────────────────────────────────────────────── + +async function main() { + let container: StartedTestContainer | null = null; + + try { + // ── 1. Start Redis ── + console.log('\n⏳ Starting Redis container...'); + container = await new GenericContainer('redis:7-alpine') + .withExposedPorts(6379) + .start(); + + const host = container.getHost(); + const port = container.getMappedPort(6379); + const redisUrl = `${host}:${port}`; + console.log(`✓ Redis running on ${redisUrl}`); + + // Set env vars the SDK reads + process.env.BLOCK_REDIS_URL = redisUrl; + process.env.TICK_REDIS_URL = redisUrl; + process.env.NOTIFICATIONS_REDIS_URL = redisUrl; + process.env.RUNNER_CACHE_REDIS_URL = redisUrl; + process.env.RANGE_SDK_TOKEN = 'e2e-test-runner.fake-token'; + + // ── 2. Load test processors (triggers @Rule decorators) ── + console.log('⏳ Loading test processors...'); + await import('./test-processors'); + console.log('✓ 10 processors registered (5 block + 5 tick)'); + + // ── 3. Init Piscina thread pool ── + console.log('⏳ Starting thread pool...'); + const workerFile = join(__dirname, '..', 'threadpool', 'worker.js'); + await initPool({ + filename: workerFile, + maxThreads: 2, + }); + console.log('✓ Thread pool ready (2 threads)'); + + // ── 4. Process Solana blocks (JSON path → FlatBuffer encoding) ── + console.log('\n── Processing Solana blocks (JSON → FlatBuffer path) ──'); + const blockRules = makeBlockRules(); + const tickRules = makeTickRules(); + const allEvents: IEvent[] = []; + + for (let i = 1; i <= BLOCK_COUNT; i++) { + const block = makeSolanaBlock(i); + const results = await processPayload({ + blockData: block, + ruleList: blockRules, + processorsFile, + }); + const events = results.flatMap((r) => r.events); + allEvents.push(...events); + console.log(` Block ${i}: ${events.length} events`); + } + + // ── 5. Process ticks ── + console.log('\n── Processing ticks ──'); + for (let i = 1; i <= TICK_COUNT; i++) { + const timestamp = new Date(Date.now() + i * 1000).toISOString(); + const results = await processPayload({ + time: timestamp, + ruleList: tickRules, + processorsFile, + }); + const events = results.flatMap((r) => r.events); + allEvents.push(...events); + console.log(` Tick ${i}: ${events.length} events`); + } + + // ── 6. Assertions ── + console.log('\n── Assertions ──'); + + const blockEvents = allEvents.filter((e) => + e.caption.startsWith('e2e-block-') + ); + const tickEvents = allEvents.filter((e) => + e.caption.startsWith('e2e-tick-') + ); + + check(`Total events = ${EXPECTED_EVENTS}`, () => { + assert.equal(allEvents.length, EXPECTED_EVENTS); + }); + + check(`Block events = ${BLOCK_COUNT * BLOCK_RULE_COUNT}`, () => { + assert.equal(blockEvents.length, BLOCK_COUNT * BLOCK_RULE_COUNT); + }); + + check(`Tick events = ${TICK_COUNT * TICK_RULE_COUNT}`, () => { + assert.equal(tickEvents.length, TICK_COUNT * TICK_RULE_COUNT); + }); + + // Each block rule produced events for each block + for (let ruleIdx = 1; ruleIdx <= BLOCK_RULE_COUNT; ruleIdx++) { + const ruleEvents = blockEvents.filter( + (e) => e.alertRuleId === `block-rule-${ruleIdx}` + ); + check(`block-rule-${ruleIdx} fired ${BLOCK_COUNT} times`, () => { + assert.equal(ruleEvents.length, BLOCK_COUNT); + }); + } + + // Each tick rule produced events for each tick + for (let ruleIdx = 1; ruleIdx <= TICK_RULE_COUNT; ruleIdx++) { + const ruleEvents = tickEvents.filter( + (e) => e.alertRuleId === `tick-rule-${ruleIdx}` + ); + check(`tick-rule-${ruleIdx} fired ${TICK_COUNT} times`, () => { + assert.equal(ruleEvents.length, TICK_COUNT); + }); + } + + // Block numbers are correct + for (let height = 1; height <= BLOCK_COUNT; height++) { + const heightEvents = blockEvents.filter( + (e) => e.blockNumber === String(height) + ); + check(`block height ${height} has ${BLOCK_RULE_COUNT} events`, () => { + assert.equal(heightEvents.length, BLOCK_RULE_COUNT); + }); + } + + // Event shape + check('All events have required fields', () => { + for (const event of allEvents) { + assert.ok(event.id, 'missing id'); + assert.ok(event.alertRuleId, 'missing alertRuleId'); + assert.ok(event.caption, 'missing caption'); + assert.ok(event.details, 'missing details'); + assert.ok(event.details.message, 'missing details.message'); + assert.ok(event.time, 'missing time'); + assert.ok(event.severity, 'missing severity'); + } + }); + + // All IDs are unique + check('All event IDs are unique', () => { + const ids = new Set(allEvents.map((e) => e.id)); + assert.equal(ids.size, allEvents.length); + }); + + // ── 7. Redis stream JSON round-trip ── + console.log('\n── Redis stream JSON round-trip ──'); + const client = await createRedisClient(redisUrl); + const streamName = `e2e-test-${Date.now()}`; + + await publishToStream({ + client: client as any, + streamName, + payload: makeSolanaBlock(999), + }); + + const messages = await (client as any).xRange(streamName, '-', '+'); + check('Published and read back 1 message from Redis stream', () => { + assert.equal(messages.length, 1); + }); + + const payload = JSON.parse(messages[0].message.message); + check('Payload round-trips correctly', () => { + assert.equal(payload.height, 999); + assert.equal(payload.network, 'solana'); + }); + + // ── 8. Binary Redis stream round-trip (FlatBuffer) ── + console.log('\n── Binary Redis stream round-trip (FlatBuffer) ──'); + const binaryClient = await createRedisClient(redisUrl); + const binaryStreamName = `e2e-binary-test-${Date.now()}`; + + const solanaBlock = makeSolanaBlock(12345); + const binary = convertSolanaBlockJsonToBuffer(solanaBlock); + + await publishBinaryToStream({ + client: binaryClient as any, + streamName: binaryStreamName, + payload: binary, + }); + + const binaryMessages = await (binaryClient as any).xRange( + binaryStreamName, + '-', + '+' + ); + check('Published and read back 1 binary message from Redis stream', () => { + assert.equal(binaryMessages.length, 1); + }); + + check('Binary message has buffer field', () => { + assert.ok(binaryMessages[0].message.buffer); + }); + + const decoded = Buffer.from(binaryMessages[0].message.buffer, 'base64'); + const wrapper = new SolanaBlockWrapper( + new Uint8Array(decoded.buffer, decoded.byteOffset, decoded.byteLength) + ); + check('Binary payload round-trips correctly', () => { + assert.equal(wrapper.height, 12345); + assert.equal(wrapper.network, 'solana'); + }); + + await (binaryClient as any).disconnect(); + await (client as any).disconnect(); + + // ── Summary ── + console.log(`\n${'─'.repeat(40)}`); + if (failed === 0) { + console.log(`✅ All ${passed} checks passed`); + } else { + console.log(`❌ ${failed} failed, ${passed} passed`); + } + } finally { + // ── Cleanup ── + console.log('\n⏳ Cleaning up...'); + await closePool(); + if (container) await container.stop(); + console.log('✓ Done\n'); + } + + process.exit(failed > 0 ? 1 : 0); +} + +main().catch((err) => { + console.error('E2E test crashed:', err); + process.exit(1); +}); diff --git a/src/e2e/round-trip-test.ts b/src/e2e/round-trip-test.ts new file mode 100644 index 00000000..dee07635 --- /dev/null +++ b/src/e2e/round-trip-test.ts @@ -0,0 +1,278 @@ +/** + * Round-trip integrity test: JSON -> FlatBuffer encode -> decode -> field comparison + * + * For each Solana test block: + * 1. Read raw RPC JSON, augment with height/timestamp/network + * 2. Encode to FlatBuffer via createSolanaBlockFromJson + * 3. Decode via SolanaBlockWrapper + * 4. Compare decoded fields against original — report any mismatches + * + * Usage: + * npx ts-node src/e2e/round-trip-test.ts [block-dir] + */ + +import { readFileSync, readdirSync } from 'fs'; +import * as path from 'path'; +import { + createSolanaBlockFromJson, + SolanaBlockWrapper, +} from '../wrappers/solana-block-wrapper'; + +const DEFAULT_DIR = path.join(__dirname, '..', 'test_data', 'solana'); +const blockDir = process.argv[2] || DEFAULT_DIR; + +interface Mismatch { + field: string; + expected: unknown; + got: unknown; +} + +function compareFields(original: any, wrapper: SolanaBlockWrapper): Mismatch[] { + const mismatches: Mismatch[] = []; + + function check(field: string, expected: unknown, got: unknown) { + if (expected !== got) { + mismatches.push({ field, expected, got }); + } + } + + // Top-level fields + check('height', original.height, wrapper.height); + check('network', original.network, wrapper.network); + check('timestamp', original.timestamp, wrapper.timestamp); + + // Block data + const bd = wrapper.block_data; + if (original.blockData) { + check( + 'blockData.parentSlot', + original.blockData.parentSlot, + bd?.parentSlot + ); + check( + 'blockData.previousBlockhash', + original.blockData.previousBlockhash, + bd?.previousBlockhash + ); + } + + // Transaction count + const origTxs = original.transactions || []; + const decodedTxs = wrapper.transactions; + check('transactions.length', origTxs.length, decodedTxs.length); + + // Per-transaction field checks + const txCount = Math.min(origTxs.length, decodedTxs.length); + for (let i = 0; i < txCount; i++) { + const oTx = origTxs[i]; + const dTx = decodedTxs[i]; + const prefix = `tx[${i}]`; + + // Signatures + const oSigs = oTx.transaction?.signatures || []; + const dSigs = dTx.transaction?.signatures || []; + check(`${prefix}.signatures.length`, oSigs.length, dSigs.length); + for (let s = 0; s < Math.min(oSigs.length, dSigs.length); s++) { + check(`${prefix}.signatures[${s}]`, oSigs[s], dSigs[s]); + } + + // Account keys + const oKeys = oTx.transaction?.message?.accountKeys || []; + const dKeys = dTx.transaction?.message?.accountKeys || []; + check(`${prefix}.accountKeys.length`, oKeys.length, dKeys.length); + for (let k = 0; k < Math.min(oKeys.length, dKeys.length); k++) { + check( + `${prefix}.accountKeys[${k}].pubkey`, + oKeys[k].pubkey, + dKeys[k].pubkey + ); + check( + `${prefix}.accountKeys[${k}].signer`, + oKeys[k].signer, + dKeys[k].signer + ); + check( + `${prefix}.accountKeys[${k}].writable`, + oKeys[k].writable, + dKeys[k].writable + ); + check( + `${prefix}.accountKeys[${k}].source`, + oKeys[k].source, + dKeys[k].source + ); + } + + // Instructions + const oInsts = oTx.transaction?.message?.instructions || []; + const dInsts = dTx.transaction?.message?.instructions || []; + check(`${prefix}.instructions.length`, oInsts.length, dInsts.length); + for (let ix = 0; ix < Math.min(oInsts.length, dInsts.length); ix++) { + check( + `${prefix}.instructions[${ix}].programId`, + oInsts[ix].programId || '', + dInsts[ix].programId + ); + check( + `${prefix}.instructions[${ix}].data`, + oInsts[ix].data || '', + dInsts[ix].data + ); + const oAccs = oInsts[ix].accounts || []; + const dAccs = dInsts[ix].accounts || []; + check( + `${prefix}.instructions[${ix}].accounts.length`, + oAccs.length, + dAccs.length + ); + } + + // Meta + const oMeta = oTx.meta || {}; + const dMeta = dTx.meta || {}; + check(`${prefix}.meta.fee`, oMeta.fee, dMeta.fee); + check( + `${prefix}.meta.computeUnitsConsumed`, + oMeta.computeUnitsConsumed, + dMeta.computeUnitsConsumed + ); + + // Balances + const oPre = oMeta.preBalances || []; + const dPre = dMeta.preBalances || []; + check(`${prefix}.meta.preBalances.length`, oPre.length, dPre.length); + + const oPost = oMeta.postBalances || []; + const dPost = dMeta.postBalances || []; + check(`${prefix}.meta.postBalances.length`, oPost.length, dPost.length); + + // Token balances + const oPreTB = oMeta.preTokenBalances || []; + const dPreTB = dMeta.preTokenBalances || []; + check( + `${prefix}.meta.preTokenBalances.length`, + oPreTB.length, + dPreTB.length + ); + for (let tb = 0; tb < Math.min(oPreTB.length, dPreTB.length); tb++) { + check( + `${prefix}.meta.preTokenBalances[${tb}].mint`, + oPreTB[tb].mint, + dPreTB[tb].mint + ); + check( + `${prefix}.meta.preTokenBalances[${tb}].owner`, + oPreTB[tb].owner, + dPreTB[tb].owner + ); + } + + const oPostTB = oMeta.postTokenBalances || []; + const dPostTB = dMeta.postTokenBalances || []; + check( + `${prefix}.meta.postTokenBalances.length`, + oPostTB.length, + dPostTB.length + ); + for (let tb = 0; tb < Math.min(oPostTB.length, dPostTB.length); tb++) { + check( + `${prefix}.meta.postTokenBalances[${tb}].mint`, + oPostTB[tb].mint, + dPostTB[tb].mint + ); + check( + `${prefix}.meta.postTokenBalances[${tb}].owner`, + oPostTB[tb].owner, + dPostTB[tb].owner + ); + } + + // Log messages + const oLogs = oMeta.logMessages || []; + const dLogs = dMeta.logMessages || []; + check(`${prefix}.meta.logMessages.length`, oLogs.length, dLogs.length); + + // Inner instructions + const oInner = oMeta.innerInstructions || []; + const dInner = dMeta.innerInstructions || []; + check( + `${prefix}.meta.innerInstructions.length`, + oInner.length, + dInner.length + ); + } + + return mismatches; +} + +function augmentBlock(raw: any): any { + return { + ...raw, + height: raw.blockHeight, + timestamp: raw.blockTime, + network: 'solana', + blockData: { + slot: String(raw.blockHeight), + parentSlot: String(raw.parentSlot), + previousBlockhash: raw.previousBlockhash || '', + }, + }; +} + +const files = readdirSync(blockDir) + .filter((f) => f.endsWith('.json')) + .sort(); + +console.log( + `Round-trip integrity test: ${files.length} blocks from ${blockDir}\n` +); + +let passCount = 0; +let failCount = 0; +let totalFields = 0; +let totalMismatches = 0; + +for (const file of files) { + const raw = JSON.parse(readFileSync(path.join(blockDir, file), 'utf8')); + const augmented = augmentBlock(raw); + + const encoded = createSolanaBlockFromJson(augmented); + const wrapper = new SolanaBlockWrapper(encoded); + const mismatches = compareFields(augmented, wrapper); + + // Count checked fields (rough: mismatches + all the checks that passed) + const txCount = augmented.transactions?.length || 0; + const fieldsChecked = 3 + 2 + 1 + txCount * 10; // approximate + totalFields += fieldsChecked; + totalMismatches += mismatches.length; + + if (mismatches.length === 0) { + passCount++; + } else { + failCount++; + console.log(`FAIL: ${file} — ${mismatches.length} mismatches`); + for (const m of mismatches.slice(0, 10)) { + console.log( + ` ${m.field}: expected ${JSON.stringify(m.expected)} got ${JSON.stringify(m.got)}` + ); + } + if (mismatches.length > 10) { + console.log(` ... and ${mismatches.length - 10} more`); + } + } +} + +console.log(`\n${'='.repeat(60)}`); +console.log( + ` RESULTS: ${passCount} passed, ${failCount} failed out of ${files.length} blocks` +); +console.log( + ` Fields checked: ~${totalFields}, mismatches: ${totalMismatches}` +); +console.log(`${'='.repeat(60)}\n`); + +if (failCount === 0) { + console.log(`All ${files.length} blocks passed round-trip integrity check.`); +} else { + process.exit(1); +} diff --git a/src/e2e/test-processors-eth.ts b/src/e2e/test-processors-eth.ts new file mode 100644 index 00000000..8457638f --- /dev/null +++ b/src/e2e/test-processors-eth.ts @@ -0,0 +1,76 @@ +/** + * ETH test processor for e2e pipeline test. + * Validates that the EVM block JSON survives the SharedArrayBuffer round-trip + * and the worker receives a fully parsed object with all fields intact. + */ +import 'reflect-metadata'; +import { Rule, BlockProcessor, IBlockProcessor } from '../utils/processor'; +import { ISubEvent } from '../types/IEvent'; + +@Rule({ + type: 'e2e-eth-block', + label: 'E2E ETH Block', + description: 'Validates EVM block JSON integrity through worker pipeline', + parameters: [], + tags: ['evm'], + networks: ['eth'], +}) +class E2EEthBlock extends BlockProcessor { + async callback({ block }: IBlockProcessor): Promise { + const errors: string[] = []; + + // Verify the block is a real parsed object (not a string) + if (typeof block !== 'object' || block === null) { + errors.push(`block is ${typeof block}, expected object`); + } + + // Check top-level fields exist (set by normalizeBlock or pre-normalized) + if (block.height === undefined) errors.push('missing block.height'); + if (block.network === undefined) errors.push('missing block.network'); + + // Check the nested RPC result structure survived JSON round-trip + const result = block.result; + if (!result) { + errors.push('missing block.result'); + } else { + if (!result.number) errors.push('missing result.number'); + if (!result.hash) errors.push('missing result.hash'); + if (!result.miner) errors.push('missing result.miner'); + if (!result.gasUsed) errors.push('missing result.gasUsed'); + if (!Array.isArray(result.transactions)) { + errors.push('result.transactions is not an array'); + } else if (result.transactions.length > 0) { + const tx = result.transactions[0]; + if (!tx.hash) errors.push('missing tx.hash'); + if (!tx.from) errors.push('missing tx.from'); + } + } + + if (errors.length > 0) { + return [ + { + caption: 'e2e-eth-block', + details: { + message: `FAIL: ${errors.join('; ')}`, + valid: false, + errorCount: errors.length, + }, + }, + ]; + } + + return [ + { + caption: 'e2e-eth-block', + details: { + message: `OK: height=${block.height}, txs=${result.transactions.length}, hash=${result.hash?.slice(0, 10)}...`, + valid: true, + txCount: result.transactions.length, + height: block.height, + }, + }, + ]; + } +} + +export const E2E_ETH_PROCESSORS = [E2EEthBlock]; diff --git a/src/e2e/test-processors.ts b/src/e2e/test-processors.ts new file mode 100644 index 00000000..320d98b1 --- /dev/null +++ b/src/e2e/test-processors.ts @@ -0,0 +1,191 @@ +/** + * 5 block + 5 tick test processors for e2e pipeline test. + * Each processor emits exactly 1 event so we can verify 50 total + * (5 blocks × 5 block rules + 5 ticks × 5 tick rules). + */ +import 'reflect-metadata'; +import { + Rule, + BlockProcessor, + TickProcessor, + IBlockProcessor, + ITickProcessor, +} from '../utils/processor'; +import { ISubEvent } from '../types/IEvent'; + +// ── Block Processors (5) ──────────────────────────────────────── + +@Rule({ + type: 'e2e-block-1', + label: 'E2E Block 1', + description: 'Test', + parameters: [], + tags: ['security'], + networks: ['solana'], +}) +class E2EBlock1 extends BlockProcessor { + async callback({ block }: IBlockProcessor): Promise { + return [ + { caption: 'e2e-block-1', details: { message: `block ${block.height}` } }, + ]; + } +} + +@Rule({ + type: 'e2e-block-2', + label: 'E2E Block 2', + description: 'Test', + parameters: [], + tags: ['security'], + networks: ['solana'], +}) +class E2EBlock2 extends BlockProcessor { + async callback({ block }: IBlockProcessor): Promise { + return [ + { caption: 'e2e-block-2', details: { message: `block ${block.height}` } }, + ]; + } +} + +@Rule({ + type: 'e2e-block-3', + label: 'E2E Block 3', + description: 'Test', + parameters: [], + tags: ['security'], + networks: ['solana'], +}) +class E2EBlock3 extends BlockProcessor { + async callback({ block }: IBlockProcessor): Promise { + return [ + { caption: 'e2e-block-3', details: { message: `block ${block.height}` } }, + ]; + } +} + +@Rule({ + type: 'e2e-block-4', + label: 'E2E Block 4', + description: 'Test', + parameters: [], + tags: ['security'], + networks: ['solana'], +}) +class E2EBlock4 extends BlockProcessor { + async callback({ block }: IBlockProcessor): Promise { + return [ + { caption: 'e2e-block-4', details: { message: `block ${block.height}` } }, + ]; + } +} + +@Rule({ + type: 'e2e-block-5', + label: 'E2E Block 5', + description: 'Test', + parameters: [], + tags: ['security'], + networks: ['solana'], +}) +class E2EBlock5 extends BlockProcessor { + async callback({ block }: IBlockProcessor): Promise { + return [ + { caption: 'e2e-block-5', details: { message: `block ${block.height}` } }, + ]; + } +} + +// ── Tick Processors (5) ───────────────────────────────────────── + +@Rule({ + type: 'e2e-tick-1', + label: 'E2E Tick 1', + description: 'Test', + parameters: [], + tags: ['security'], + networks: ['solana'], +}) +class E2ETick1 extends TickProcessor { + async callback({ timestamp }: ITickProcessor): Promise { + return [ + { caption: 'e2e-tick-1', details: { message: `tick ${timestamp}` } }, + ]; + } +} + +@Rule({ + type: 'e2e-tick-2', + label: 'E2E Tick 2', + description: 'Test', + parameters: [], + tags: ['security'], + networks: ['solana'], +}) +class E2ETick2 extends TickProcessor { + async callback({ timestamp }: ITickProcessor): Promise { + return [ + { caption: 'e2e-tick-2', details: { message: `tick ${timestamp}` } }, + ]; + } +} + +@Rule({ + type: 'e2e-tick-3', + label: 'E2E Tick 3', + description: 'Test', + parameters: [], + tags: ['security'], + networks: ['solana'], +}) +class E2ETick3 extends TickProcessor { + async callback({ timestamp }: ITickProcessor): Promise { + return [ + { caption: 'e2e-tick-3', details: { message: `tick ${timestamp}` } }, + ]; + } +} + +@Rule({ + type: 'e2e-tick-4', + label: 'E2E Tick 4', + description: 'Test', + parameters: [], + tags: ['security'], + networks: ['solana'], +}) +class E2ETick4 extends TickProcessor { + async callback({ timestamp }: ITickProcessor): Promise { + return [ + { caption: 'e2e-tick-4', details: { message: `tick ${timestamp}` } }, + ]; + } +} + +@Rule({ + type: 'e2e-tick-5', + label: 'E2E Tick 5', + description: 'Test', + parameters: [], + tags: ['security'], + networks: ['solana'], +}) +class E2ETick5 extends TickProcessor { + async callback({ timestamp }: ITickProcessor): Promise { + return [ + { caption: 'e2e-tick-5', details: { message: `tick ${timestamp}` } }, + ]; + } +} + +export const E2E_PROCESSORS = [ + E2EBlock1, + E2EBlock2, + E2EBlock3, + E2EBlock4, + E2EBlock5, + E2ETick1, + E2ETick2, + E2ETick3, + E2ETick4, + E2ETick5, +]; diff --git a/src/e2e/validate-blocks.ts b/src/e2e/validate-blocks.ts new file mode 100644 index 00000000..c257e52c --- /dev/null +++ b/src/e2e/validate-blocks.ts @@ -0,0 +1,125 @@ +/** + * Strict Zod validation for Solana block JSON files (Range-wrapped format). + * + * Usage: + * node dist/e2e/validate-blocks.js [block-dir] + */ + +import { readFileSync, readdirSync } from 'fs'; +import * as path from 'path'; +import { SolanaBlockVal } from '../types/ISolanaBlock'; + +// ── Run validation ── + +const DEFAULT_DIR = path.join(process.cwd(), 'src', 'test_data', 'solana'); +const blockDir = process.argv[2] || DEFAULT_DIR; + +const files = readdirSync(blockDir) + .filter((f) => f.endsWith('.json')) + .sort(); + +console.log(`Validating ${files.length} Solana blocks from ${blockDir}\n`); + +interface Issue { + file: string; + path: string; + message: string; + received: unknown; +} + +const allIssues: Issue[] = []; +let passCount = 0; +let failCount = 0; + +for (const file of files) { + const filePath = path.join(blockDir, file); + const raw = readFileSync(filePath, 'utf8'); + + let json: unknown; + try { + json = JSON.parse(raw); + } catch (e) { + allIssues.push({ + file, + path: '(root)', + message: `Invalid JSON: ${e}`, + received: null, + }); + failCount++; + continue; + } + + const result = SolanaBlockVal.strict().safeParse(json); + + if (result.success) { + passCount++; + } else { + failCount++; + for (const issue of result.error.issues) { + allIssues.push({ + file, + path: issue.path.join('.'), + message: issue.message, + received: (issue as any).received, + }); + } + } +} + +// ── Summary ── + +console.log(`${'='.repeat(60)}`); +console.log( + ` RESULTS: ${passCount} passed, ${failCount} failed out of ${files.length}` +); +console.log(`${'='.repeat(60)}\n`); + +if (allIssues.length === 0) { + console.log(`All ${files.length} Solana blocks passed strict validation.`); + process.exit(0); +} + +// Group issues by path+message +const grouped = new Map< + string, + { count: number; files: string[]; received: Set } +>(); + +for (const issue of allIssues) { + const key = `${issue.path} → ${issue.message}`; + const entry = grouped.get(key) || { + count: 0, + files: [], + received: new Set(), + }; + entry.count++; + if (entry.files.length < 3) entry.files.push(issue.file); + if (issue.received !== undefined) { + const recv = + typeof issue.received === 'object' + ? JSON.stringify(issue.received)?.substring(0, 80) + : String(issue.received); + entry.received.add(recv); + } + grouped.set(key, entry); +} + +console.log( + `Found ${allIssues.length} total issues across ${failCount} blocks.\n` +); +console.log(`Unique issue types: ${grouped.size}\n`); + +const sorted = [...grouped.entries()].sort((a, b) => b[1].count - a[1].count); + +for (const [key, val] of sorted) { + console.log(`--- ${key}`); + console.log(` Count: ${val.count}`); + console.log(` Examples: ${val.files.join(', ')}`); + if (val.received.size > 0) { + const samples = [...val.received].slice(0, 3); + console.log(` Received: ${samples.join(' | ')}`); + } + console.log(); +} + +process.exit(1); diff --git a/src/e2e/validate-cosmos-blocks.ts b/src/e2e/validate-cosmos-blocks.ts new file mode 100644 index 00000000..e7f92ff0 --- /dev/null +++ b/src/e2e/validate-cosmos-blocks.ts @@ -0,0 +1,125 @@ +/** + * Strict Zod validation for Cosmos block JSON files (Range-wrapped format). + * + * Usage: + * node dist/e2e/validate-cosmos-blocks.js [block-dir] + */ + +import { readFileSync, readdirSync } from 'fs'; +import * as path from 'path'; +import { CosmosBlockVal } from '../types/ICosmosBlock'; + +// ── Run validation ── + +const DEFAULT_DIR = path.join(process.cwd(), 'src', 'test_data', 'osmosis-1'); +const blockDir = process.argv[2] || DEFAULT_DIR; + +const files = readdirSync(blockDir) + .filter((f) => f.endsWith('.json')) + .sort(); + +console.log(`Validating ${files.length} Cosmos blocks from ${blockDir}\n`); + +interface Issue { + file: string; + path: string; + message: string; + received: unknown; +} + +const allIssues: Issue[] = []; +let passCount = 0; +let failCount = 0; + +for (const file of files) { + const filePath = path.join(blockDir, file); + const raw = readFileSync(filePath, 'utf8'); + + let json: unknown; + try { + json = JSON.parse(raw); + } catch (e) { + allIssues.push({ + file, + path: '(root)', + message: `Invalid JSON: ${e}`, + received: null, + }); + failCount++; + continue; + } + + const result = CosmosBlockVal.strict().safeParse(json); + + if (result.success) { + passCount++; + } else { + failCount++; + for (const issue of result.error.issues) { + allIssues.push({ + file, + path: issue.path.join('.'), + message: issue.message, + received: (issue as any).received, + }); + } + } +} + +// ── Summary ── + +console.log(`${'='.repeat(60)}`); +console.log( + ` RESULTS: ${passCount} passed, ${failCount} failed out of ${files.length}` +); +console.log(`${'='.repeat(60)}\n`); + +if (allIssues.length === 0) { + console.log(`All ${files.length} Cosmos blocks passed strict validation.`); + process.exit(0); +} + +// Group issues by path+message +const grouped = new Map< + string, + { count: number; files: string[]; received: Set } +>(); + +for (const issue of allIssues) { + const key = `${issue.path} → ${issue.message}`; + const entry = grouped.get(key) || { + count: 0, + files: [], + received: new Set(), + }; + entry.count++; + if (entry.files.length < 3) entry.files.push(issue.file); + if (issue.received !== undefined) { + const recv = + typeof issue.received === 'object' + ? JSON.stringify(issue.received)?.substring(0, 80) + : String(issue.received); + entry.received.add(recv); + } + grouped.set(key, entry); +} + +console.log( + `Found ${allIssues.length} total issues across ${failCount} blocks.\n` +); +console.log(`Unique issue types: ${grouped.size}\n`); + +const sorted = [...grouped.entries()].sort((a, b) => b[1].count - a[1].count); + +for (const [key, val] of sorted) { + console.log(`--- ${key}`); + console.log(` Count: ${val.count}`); + console.log(` Examples: ${val.files.join(', ')}`); + if (val.received.size > 0) { + const samples = [...val.received].slice(0, 3); + console.log(` Received: ${samples.join(' | ')}`); + } + console.log(); +} + +process.exit(1); diff --git a/src/e2e/validate-eth-blocks.ts b/src/e2e/validate-eth-blocks.ts new file mode 100644 index 00000000..95d64594 --- /dev/null +++ b/src/e2e/validate-eth-blocks.ts @@ -0,0 +1,125 @@ +/** + * Strict Zod validation for EVM block JSON files (Range-wrapped format). + * + * Usage: + * node dist/e2e/validate-eth-blocks.js [block-dir] + */ + +import { readFileSync, readdirSync } from 'fs'; +import * as path from 'path'; +import { EVMBlockVal } from '../types/IEVMBlock'; + +// ── Run validation ── + +const DEFAULT_DIR = path.join(process.cwd(), 'src', 'test_data', 'eth'); +const blockDir = process.argv[2] || DEFAULT_DIR; + +const files = readdirSync(blockDir) + .filter((f) => f.endsWith('.json')) + .sort(); + +console.log(`Validating ${files.length} ETH blocks from ${blockDir}\n`); + +interface Issue { + file: string; + path: string; + message: string; + received: unknown; +} + +const allIssues: Issue[] = []; +let passCount = 0; +let failCount = 0; + +for (const file of files) { + const filePath = path.join(blockDir, file); + const raw = readFileSync(filePath, 'utf8'); + + let json: unknown; + try { + json = JSON.parse(raw); + } catch (e) { + allIssues.push({ + file, + path: '(root)', + message: `Invalid JSON: ${e}`, + received: null, + }); + failCount++; + continue; + } + + const result = EVMBlockVal.strict().safeParse(json); + + if (result.success) { + passCount++; + } else { + failCount++; + for (const issue of result.error.issues) { + allIssues.push({ + file, + path: issue.path.join('.'), + message: issue.message, + received: (issue as any).received, + }); + } + } +} + +// ── Summary ── + +console.log(`${'='.repeat(60)}`); +console.log( + ` RESULTS: ${passCount} passed, ${failCount} failed out of ${files.length}` +); +console.log(`${'='.repeat(60)}\n`); + +if (allIssues.length === 0) { + console.log(`All ${files.length} ETH blocks passed strict validation.`); + process.exit(0); +} + +// Group issues by path+message +const grouped = new Map< + string, + { count: number; files: string[]; received: Set } +>(); + +for (const issue of allIssues) { + const key = `${issue.path} → ${issue.message}`; + const entry = grouped.get(key) || { + count: 0, + files: [], + received: new Set(), + }; + entry.count++; + if (entry.files.length < 3) entry.files.push(issue.file); + if (issue.received !== undefined) { + const recv = + typeof issue.received === 'object' + ? JSON.stringify(issue.received)?.substring(0, 80) + : String(issue.received); + entry.received.add(recv); + } + grouped.set(key, entry); +} + +console.log( + `Found ${allIssues.length} total issues across ${failCount} blocks.\n` +); +console.log(`Unique issue types: ${grouped.size}\n`); + +const sorted = [...grouped.entries()].sort((a, b) => b[1].count - a[1].count); + +for (const [key, val] of sorted) { + console.log(`--- ${key}`); + console.log(` Count: ${val.count}`); + console.log(` Examples: ${val.files.join(', ')}`); + if (val.received.size > 0) { + const samples = [...val.received].slice(0, 3); + console.log(` Received: ${samples.join(' | ')}`); + } + console.log(); +} + +process.exit(1); diff --git a/src/env.ts b/src/env.ts new file mode 100644 index 00000000..a46cd149 --- /dev/null +++ b/src/env.ts @@ -0,0 +1,175 @@ +import { config } from 'dotenv'; +import { ISDKConfig } from './types/IRunnerConfig'; +config({ quiet: true }); + +function getEnvVar(name: string, defaultValue?: string) { + const value = process.env[name] || defaultValue; + if (!value) { + throw new Error(`Environment variable ${name} is not set`); + } + return value; +} + +export const env = { + get PORT() { + return Number(getEnvVar('PORT', '3000')); + }, + get NODE_ENV() { + return getEnvVar('NODE_ENV', 'local'); + }, + get LOG_LEVEL() { + return getEnvVar('LOG_LEVEL', 'info'); + }, + + get RUNNER_CACHE_REDIS_URL() { + return getEnvVar('RUNNER_CACHE_REDIS_URL', this.BLOCK_REDIS_URL); + }, + get BLOCK_REDIS_URL() { + return getEnvVar('BLOCK_REDIS_URL', '127.0.0.1:6379'); + }, + get TICK_REDIS_URL() { + return getEnvVar('TICK_REDIS_URL', this.BLOCK_REDIS_URL); + }, + + get RPC_PROXY_HOST() { + return getEnvVar('RPC_PROXY_HOST'); + }, + get RPC_PROXY_TOKEN() { + return getEnvVar('RPC_PROXY_TOKEN'); + }, + get RANGE_API_HOST() { + return getEnvVar('RANGE_API_HOST'); + }, + get RANGE_API_KEY() { + return getEnvVar('RANGE_API_KEY'); + }, + get SOL_DECODER_HOST() { + return getEnvVar('SOL_DECODER_HOST'); + }, + get SOL_DECODER_TOKEN() { + return getEnvVar('SOL_DECODER_TOKEN'); + }, + get BLOCK_DECODER_HOST() { + return getEnvVar('BLOCK_DECODER_HOST'); + }, + get BLOCK_DECODER_TOKEN() { + return getEnvVar('BLOCK_DECODER_TOKEN'); + }, + get REGISTER_RULE_TYPES() { + return ( + getEnvVar('REGISTER_RULE_TYPES', 'false') === 'true' || + getEnvVar('REGISTER_TEMPLATES', 'false') === 'true' + ); + }, + get REGISTER_EXTERNAL_RULE_TYPES_ENDPOINT() { + return getEnvVar('REGISTER_EXTERNAL_RULE_TYPES_ENDPOINT', '123'); + }, + get RANGE_SDK_TOKEN() { + return getEnvVar('RANGE_SDK_TOKEN'); + }, + get RUNNER_ID() { + return getEnvVar('RANGE_SDK_TOKEN').split('.')[0]; + }, + get RUNNER_NETWORK() { + // piscina-runner-eth → eth, piscina-runner-pol → pol + return this.RUNNER_ID.replace('piscina-runner-', ''); + }, + get FETCH_RULE_ENDPOINT() { + return getEnvVar( + 'FETCH_RULE_ENDPOINT', + 'https://api-app.range.org/api/runners/rules' + ); + }, + + get NOTIFICATIONS_REDIS_URL() { + return getEnvVar('NOTIFICATIONS_REDIS_URL', this.BLOCK_REDIS_URL); + }, + get NOTIFICATIONS_REDIS_STREAM_NAME() { + return getEnvVar('NOTIFICATIONS_REDIS_STREAM_NAME', 'test-events-stream'); + }, + + get RECORD_STATS() { + return getEnvVar('RECORD_STATS', 'false') === 'true'; + }, + + get BLOCK_REDIS_STREAM_NAME() { + return getEnvVar('BLOCK_REDIS_STREAM_NAME', 'test-blocks-stream'); + }, + get BLOCK_REDIS_CONSUMER_GROUP() { + return getEnvVar('BLOCK_REDIS_CONSUMER_GROUP', 'default-group'); + }, + get BLOCK_REDIS_CONSUMER_NAME() { + return getEnvVar('BLOCK_REDIS_CONSUMER_NAME', 'default-consumer-0'); + }, + + get TICK_REDIS_STREAM_NAME() { + return getEnvVar('TICK_REDIS_STREAM_NAME', 'test-ticks-stream'); + }, + get TICK_REDIS_CONSUMER_GROUP() { + return getEnvVar('TICK_REDIS_CONSUMER_GROUP', 'default-group'); + }, + get TICK_REDIS_CONSUMER_NAME() { + return getEnvVar('TICK_REDIS_CONSUMER_NAME', 'default-consumer-0'); + }, + + get MONITORING_ENABLED() { + return getEnvVar('MONITORING_ENABLED', 'false') === 'true'; + }, + get MONITORING_SERVER_URL() { + return getEnvVar('MONITORING_SERVER_URL', 'test'); + }, + get MONITORING_SERVER_TOKEN() { + return getEnvVar('MONITORING_SERVER_TOKEN', 'test'); + }, + + get STAT_RETENTION_DAYS() { + return Number(getEnvVar('STAT_RETENTION_DAYS', '7')); + }, + get STATS_LOG_DIR() { + return getEnvVar('STATS_LOG_DIR', '/tmp/.range-logs'); + }, + + get SLACK_WEBHOOK_URL() { + return process.env.SLACK_WEBHOOK_URL || ''; + }, + get SLACK_ALERT_INTERVAL_HR() { + return Number(process.env.SLACK_ALERT_INTERVAL_HR || '1'); + }, +}; + +export function applyConfig(config: ISDKConfig) { + const map: [any, string][] = [ + [config.rangeSdkToken, 'RANGE_SDK_TOKEN'], + [config.redisUrl, 'BLOCK_REDIS_URL'], + [config.redis?.alertingUrl || config.redisUrl, 'RUNNER_CACHE_REDIS_URL'], + [ + config.redis?.notificationsUrl || config.redisUrl, + 'NOTIFICATIONS_REDIS_URL', + ], + [config.redis?.tickUrl || config.redisUrl, 'TICK_REDIS_URL'], + [config.blockStream?.name, 'BLOCK_REDIS_STREAM_NAME'], + [config.blockStream?.consumerGroup, 'BLOCK_REDIS_CONSUMER_GROUP'], + [config.blockStream?.consumerName, 'BLOCK_REDIS_CONSUMER_NAME'], + [config.tickStream?.name, 'TICK_REDIS_STREAM_NAME'], + [config.tickStream?.consumerGroup, 'TICK_REDIS_CONSUMER_GROUP'], + [config.tickStream?.consumerName, 'TICK_REDIS_CONSUMER_NAME'], + [config.notificationsStreamName, 'NOTIFICATIONS_REDIS_STREAM_NAME'], + [config.port, 'PORT'], + [config.logLevel, 'LOG_LEVEL'], + [config.rpcProxy?.host, 'RPC_PROXY_HOST'], + [config.rpcProxy?.token, 'RPC_PROXY_TOKEN'], + [config.rangeApi?.host, 'RANGE_API_HOST'], + [config.rangeApi?.key, 'RANGE_API_KEY'], + [config.slack?.webhookUrl, 'SLACK_WEBHOOK_URL'], + [config.slack?.intervalHr, 'SLACK_ALERT_INTERVAL_HR'], + [config.monitoring?.enabled, 'MONITORING_ENABLED'], + [config.monitoring?.serverUrl, 'MONITORING_SERVER_URL'], + [config.monitoring?.serverToken, 'MONITORING_SERVER_TOKEN'], + ]; + + for (const [value, key] of map) { + if (value !== undefined && value !== null) { + process.env[key] = String(value); + } + } +} diff --git a/src/flatbuffers/solana/block.fbs b/src/flatbuffers/solana/block.fbs new file mode 100644 index 00000000..d7647a47 --- /dev/null +++ b/src/flatbuffers/solana/block.fbs @@ -0,0 +1,89 @@ +// block.fbs - FlatBuffers schema for Solana blockchain block data +namespace Block; + +table UiTokenAmount { + amount: string; + decimals: uint32; + uiAmount: double; + uiAmountString: string; +} + +table TokenBalance { + accountIndex: uint32; + mint: string; + owner: string; + programId: string; + uiTokenAmount: UiTokenAmount; +} + +table Instruction { + parsed: string; // Store parsed data as JSON string + programId: string; + program: string; + accounts: [string]; + data: string; + stackHeight: int32; +} + +table InnerInstruction { + index: uint32; + instructions: [Instruction]; +} + +table AccountKey { + pubkey: string; + signer: bool; + source: string; + writable: bool; +} + +table Message { + accountKeys: [AccountKey]; + instructions: [Instruction]; +} + +table Transaction { + message: Message; + signatures: [string]; +} + +table TransactionMeta { + computeUnitsConsumed: uint64; + err: string; + fee: uint64; + innerInstructions: [InnerInstruction]; + logMessages: [string]; + preBalances: [uint64]; + postBalances: [uint64]; + preTokenBalances: [TokenBalance]; + postTokenBalances: [TokenBalance]; +} + +table SolanaTransaction { + transaction: Transaction; + meta: TransactionMeta; +} + +table SanctionedEntity { + entity: string; +} + +table BlockData { + slot: string; + parent_slot: string; + previous_blockhash: string; + malicious_addresses: [string]; + sanctioned_addresses: [string]; + blacklisted_addresses: [string]; +} + +table SolanaBlock { + hash: string; + height: string; + network: string; + timestamp: string; + block_data: BlockData; + transactions: [SolanaTransaction]; +} + +root_type SolanaBlock; \ No newline at end of file diff --git a/src/flatbuffers/solana/block.ts b/src/flatbuffers/solana/block.ts new file mode 100644 index 00000000..ca83be01 --- /dev/null +++ b/src/flatbuffers/solana/block.ts @@ -0,0 +1,25 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */ + +export { AccountKey, AccountKeyT } from './block/account-key.js'; +export { BlockData, BlockDataT } from './block/block-data.js'; +export { + InnerInstruction, + InnerInstructionT, +} from './block/inner-instruction.js'; +export { Instruction, InstructionT } from './block/instruction.js'; +export { Message, MessageT } from './block/message.js'; +export { + SanctionedEntity, + SanctionedEntityT, +} from './block/sanctioned-entity.js'; +export { SolanaBlock, SolanaBlockT } from './block/solana-block.js'; +export { + SolanaTransaction, + SolanaTransactionT, +} from './block/solana-transaction.js'; +export { TokenBalance, TokenBalanceT } from './block/token-balance.js'; +export { Transaction, TransactionT } from './block/transaction.js'; +export { TransactionMeta, TransactionMetaT } from './block/transaction-meta.js'; +export { UiTokenAmount, UiTokenAmountT } from './block/ui-token-amount.js'; diff --git a/src/flatbuffers/solana/block/account-key.ts b/src/flatbuffers/solana/block/account-key.ts new file mode 100644 index 00000000..bc5d1b1f --- /dev/null +++ b/src/flatbuffers/solana/block/account-key.ts @@ -0,0 +1,150 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */ + +import * as flatbuffers from 'flatbuffers'; + +export class AccountKey implements flatbuffers.IUnpackableObject { + bb: flatbuffers.ByteBuffer | null = null; + bb_pos = 0; + __init(i: number, bb: flatbuffers.ByteBuffer): AccountKey { + this.bb_pos = i; + this.bb = bb; + return this; + } + + static getRootAsAccountKey( + bb: flatbuffers.ByteBuffer, + obj?: AccountKey + ): AccountKey { + return (obj || new AccountKey()).__init( + bb.readInt32(bb.position()) + bb.position(), + bb + ); + } + + static getSizePrefixedRootAsAccountKey( + bb: flatbuffers.ByteBuffer, + obj?: AccountKey + ): AccountKey { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new AccountKey()).__init( + bb.readInt32(bb.position()) + bb.position(), + bb + ); + } + + pubkey(): string | null; + pubkey(optionalEncoding: flatbuffers.Encoding): string | Uint8Array | null; + pubkey(optionalEncoding?: any): string | Uint8Array | null { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset + ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) + : null; + } + + signer(): boolean { + const offset = this.bb!.__offset(this.bb_pos, 6); + return offset ? !!this.bb!.readInt8(this.bb_pos + offset) : false; + } + + source(): string | null; + source(optionalEncoding: flatbuffers.Encoding): string | Uint8Array | null; + source(optionalEncoding?: any): string | Uint8Array | null { + const offset = this.bb!.__offset(this.bb_pos, 8); + return offset + ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) + : null; + } + + writable(): boolean { + const offset = this.bb!.__offset(this.bb_pos, 10); + return offset ? !!this.bb!.readInt8(this.bb_pos + offset) : false; + } + + static startAccountKey(builder: flatbuffers.Builder) { + builder.startObject(4); + } + + static addPubkey( + builder: flatbuffers.Builder, + pubkeyOffset: flatbuffers.Offset + ) { + builder.addFieldOffset(0, pubkeyOffset, 0); + } + + static addSigner(builder: flatbuffers.Builder, signer: boolean) { + builder.addFieldInt8(1, +signer, +false); + } + + static addSource( + builder: flatbuffers.Builder, + sourceOffset: flatbuffers.Offset + ) { + builder.addFieldOffset(2, sourceOffset, 0); + } + + static addWritable(builder: flatbuffers.Builder, writable: boolean) { + builder.addFieldInt8(3, +writable, +false); + } + + static endAccountKey(builder: flatbuffers.Builder): flatbuffers.Offset { + const offset = builder.endObject(); + return offset; + } + + static createAccountKey( + builder: flatbuffers.Builder, + pubkeyOffset: flatbuffers.Offset, + signer: boolean, + sourceOffset: flatbuffers.Offset, + writable: boolean + ): flatbuffers.Offset { + AccountKey.startAccountKey(builder); + AccountKey.addPubkey(builder, pubkeyOffset); + AccountKey.addSigner(builder, signer); + AccountKey.addSource(builder, sourceOffset); + AccountKey.addWritable(builder, writable); + return AccountKey.endAccountKey(builder); + } + + unpack(): AccountKeyT { + return new AccountKeyT( + this.pubkey(), + this.signer(), + this.source(), + this.writable() + ); + } + + unpackTo(_o: AccountKeyT): void { + _o.pubkey = this.pubkey(); + _o.signer = this.signer(); + _o.source = this.source(); + _o.writable = this.writable(); + } +} + +export class AccountKeyT implements flatbuffers.IGeneratedObject { + constructor( + public pubkey: string | Uint8Array | null = null, + public signer: boolean = false, + public source: string | Uint8Array | null = null, + public writable: boolean = false + ) {} + + pack(builder: flatbuffers.Builder): flatbuffers.Offset { + const pubkey = + this.pubkey !== null ? builder.createString(this.pubkey!) : 0; + const source = + this.source !== null ? builder.createString(this.source!) : 0; + + return AccountKey.createAccountKey( + builder, + pubkey, + this.signer, + source, + this.writable + ); + } +} diff --git a/src/flatbuffers/solana/block/block-data.ts b/src/flatbuffers/solana/block/block-data.ts new file mode 100644 index 00000000..0e811778 --- /dev/null +++ b/src/flatbuffers/solana/block/block-data.ts @@ -0,0 +1,338 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */ + +import * as flatbuffers from 'flatbuffers'; + +export class BlockData implements flatbuffers.IUnpackableObject { + bb: flatbuffers.ByteBuffer | null = null; + bb_pos = 0; + __init(i: number, bb: flatbuffers.ByteBuffer): BlockData { + this.bb_pos = i; + this.bb = bb; + return this; + } + + static getRootAsBlockData( + bb: flatbuffers.ByteBuffer, + obj?: BlockData + ): BlockData { + return (obj || new BlockData()).__init( + bb.readInt32(bb.position()) + bb.position(), + bb + ); + } + + static getSizePrefixedRootAsBlockData( + bb: flatbuffers.ByteBuffer, + obj?: BlockData + ): BlockData { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new BlockData()).__init( + bb.readInt32(bb.position()) + bb.position(), + bb + ); + } + + slot(): string | null; + slot(optionalEncoding: flatbuffers.Encoding): string | Uint8Array | null; + slot(optionalEncoding?: any): string | Uint8Array | null { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset + ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) + : null; + } + + parentSlot(): string | null; + parentSlot( + optionalEncoding: flatbuffers.Encoding + ): string | Uint8Array | null; + parentSlot(optionalEncoding?: any): string | Uint8Array | null { + const offset = this.bb!.__offset(this.bb_pos, 6); + return offset + ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) + : null; + } + + previousBlockhash(): string | null; + previousBlockhash( + optionalEncoding: flatbuffers.Encoding + ): string | Uint8Array | null; + previousBlockhash(optionalEncoding?: any): string | Uint8Array | null { + const offset = this.bb!.__offset(this.bb_pos, 8); + return offset + ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) + : null; + } + + maliciousAddresses(index: number): string; + maliciousAddresses( + index: number, + optionalEncoding: flatbuffers.Encoding + ): string | Uint8Array; + maliciousAddresses( + index: number, + optionalEncoding?: any + ): string | Uint8Array | null { + const offset = this.bb!.__offset(this.bb_pos, 10); + return offset + ? this.bb!.__string( + this.bb!.__vector(this.bb_pos + offset) + index * 4, + optionalEncoding + ) + : null; + } + + maliciousAddressesLength(): number { + const offset = this.bb!.__offset(this.bb_pos, 10); + return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0; + } + + sanctionedAddresses(index: number): string; + sanctionedAddresses( + index: number, + optionalEncoding: flatbuffers.Encoding + ): string | Uint8Array; + sanctionedAddresses( + index: number, + optionalEncoding?: any + ): string | Uint8Array | null { + const offset = this.bb!.__offset(this.bb_pos, 12); + return offset + ? this.bb!.__string( + this.bb!.__vector(this.bb_pos + offset) + index * 4, + optionalEncoding + ) + : null; + } + + sanctionedAddressesLength(): number { + const offset = this.bb!.__offset(this.bb_pos, 12); + return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0; + } + + blacklistedAddresses(index: number): string; + blacklistedAddresses( + index: number, + optionalEncoding: flatbuffers.Encoding + ): string | Uint8Array; + blacklistedAddresses( + index: number, + optionalEncoding?: any + ): string | Uint8Array | null { + const offset = this.bb!.__offset(this.bb_pos, 14); + return offset + ? this.bb!.__string( + this.bb!.__vector(this.bb_pos + offset) + index * 4, + optionalEncoding + ) + : null; + } + + blacklistedAddressesLength(): number { + const offset = this.bb!.__offset(this.bb_pos, 14); + return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0; + } + + static startBlockData(builder: flatbuffers.Builder) { + builder.startObject(6); + } + + static addSlot(builder: flatbuffers.Builder, slotOffset: flatbuffers.Offset) { + builder.addFieldOffset(0, slotOffset, 0); + } + + static addParentSlot( + builder: flatbuffers.Builder, + parentSlotOffset: flatbuffers.Offset + ) { + builder.addFieldOffset(1, parentSlotOffset, 0); + } + + static addPreviousBlockhash( + builder: flatbuffers.Builder, + previousBlockhashOffset: flatbuffers.Offset + ) { + builder.addFieldOffset(2, previousBlockhashOffset, 0); + } + + static addMaliciousAddresses( + builder: flatbuffers.Builder, + maliciousAddressesOffset: flatbuffers.Offset + ) { + builder.addFieldOffset(3, maliciousAddressesOffset, 0); + } + + static createMaliciousAddressesVector( + builder: flatbuffers.Builder, + data: flatbuffers.Offset[] + ): flatbuffers.Offset { + builder.startVector(4, data.length, 4); + for (let i = data.length - 1; i >= 0; i--) { + builder.addOffset(data[i]!); + } + return builder.endVector(); + } + + static startMaliciousAddressesVector( + builder: flatbuffers.Builder, + numElems: number + ) { + builder.startVector(4, numElems, 4); + } + + static addSanctionedAddresses( + builder: flatbuffers.Builder, + sanctionedAddressesOffset: flatbuffers.Offset + ) { + builder.addFieldOffset(4, sanctionedAddressesOffset, 0); + } + + static createSanctionedAddressesVector( + builder: flatbuffers.Builder, + data: flatbuffers.Offset[] + ): flatbuffers.Offset { + builder.startVector(4, data.length, 4); + for (let i = data.length - 1; i >= 0; i--) { + builder.addOffset(data[i]!); + } + return builder.endVector(); + } + + static startSanctionedAddressesVector( + builder: flatbuffers.Builder, + numElems: number + ) { + builder.startVector(4, numElems, 4); + } + + static addBlacklistedAddresses( + builder: flatbuffers.Builder, + blacklistedAddressesOffset: flatbuffers.Offset + ) { + builder.addFieldOffset(5, blacklistedAddressesOffset, 0); + } + + static createBlacklistedAddressesVector( + builder: flatbuffers.Builder, + data: flatbuffers.Offset[] + ): flatbuffers.Offset { + builder.startVector(4, data.length, 4); + for (let i = data.length - 1; i >= 0; i--) { + builder.addOffset(data[i]!); + } + return builder.endVector(); + } + + static startBlacklistedAddressesVector( + builder: flatbuffers.Builder, + numElems: number + ) { + builder.startVector(4, numElems, 4); + } + + static endBlockData(builder: flatbuffers.Builder): flatbuffers.Offset { + const offset = builder.endObject(); + return offset; + } + + static createBlockData( + builder: flatbuffers.Builder, + slotOffset: flatbuffers.Offset, + parentSlotOffset: flatbuffers.Offset, + previousBlockhashOffset: flatbuffers.Offset, + maliciousAddressesOffset: flatbuffers.Offset, + sanctionedAddressesOffset: flatbuffers.Offset, + blacklistedAddressesOffset: flatbuffers.Offset + ): flatbuffers.Offset { + BlockData.startBlockData(builder); + BlockData.addSlot(builder, slotOffset); + BlockData.addParentSlot(builder, parentSlotOffset); + BlockData.addPreviousBlockhash(builder, previousBlockhashOffset); + BlockData.addMaliciousAddresses(builder, maliciousAddressesOffset); + BlockData.addSanctionedAddresses(builder, sanctionedAddressesOffset); + BlockData.addBlacklistedAddresses(builder, blacklistedAddressesOffset); + return BlockData.endBlockData(builder); + } + + unpack(): BlockDataT { + return new BlockDataT( + this.slot(), + this.parentSlot(), + this.previousBlockhash(), + this.bb!.createScalarList( + this.maliciousAddresses.bind(this), + this.maliciousAddressesLength() + ), + this.bb!.createScalarList( + this.sanctionedAddresses.bind(this), + this.sanctionedAddressesLength() + ), + this.bb!.createScalarList( + this.blacklistedAddresses.bind(this), + this.blacklistedAddressesLength() + ) + ); + } + + unpackTo(_o: BlockDataT): void { + _o.slot = this.slot(); + _o.parentSlot = this.parentSlot(); + _o.previousBlockhash = this.previousBlockhash(); + _o.maliciousAddresses = this.bb!.createScalarList( + this.maliciousAddresses.bind(this), + this.maliciousAddressesLength() + ); + _o.sanctionedAddresses = this.bb!.createScalarList( + this.sanctionedAddresses.bind(this), + this.sanctionedAddressesLength() + ); + _o.blacklistedAddresses = this.bb!.createScalarList( + this.blacklistedAddresses.bind(this), + this.blacklistedAddressesLength() + ); + } +} + +export class BlockDataT implements flatbuffers.IGeneratedObject { + constructor( + public slot: string | Uint8Array | null = null, + public parentSlot: string | Uint8Array | null = null, + public previousBlockhash: string | Uint8Array | null = null, + public maliciousAddresses: string[] = [], + public sanctionedAddresses: string[] = [], + public blacklistedAddresses: string[] = [] + ) {} + + pack(builder: flatbuffers.Builder): flatbuffers.Offset { + const slot = this.slot !== null ? builder.createString(this.slot!) : 0; + const parentSlot = + this.parentSlot !== null ? builder.createString(this.parentSlot!) : 0; + const previousBlockhash = + this.previousBlockhash !== null + ? builder.createString(this.previousBlockhash!) + : 0; + const maliciousAddresses = BlockData.createMaliciousAddressesVector( + builder, + builder.createObjectOffsetList(this.maliciousAddresses) + ); + const sanctionedAddresses = BlockData.createSanctionedAddressesVector( + builder, + builder.createObjectOffsetList(this.sanctionedAddresses) + ); + const blacklistedAddresses = BlockData.createBlacklistedAddressesVector( + builder, + builder.createObjectOffsetList(this.blacklistedAddresses) + ); + + return BlockData.createBlockData( + builder, + slot, + parentSlot, + previousBlockhash, + maliciousAddresses, + sanctionedAddresses, + blacklistedAddresses + ); + } +} diff --git a/src/flatbuffers/solana/block/inner-instruction.ts b/src/flatbuffers/solana/block/inner-instruction.ts new file mode 100644 index 00000000..b0bf9580 --- /dev/null +++ b/src/flatbuffers/solana/block/inner-instruction.ts @@ -0,0 +1,147 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */ + +import * as flatbuffers from 'flatbuffers'; + +import { Instruction, InstructionT } from '../block/instruction.js'; + +export class InnerInstruction implements flatbuffers.IUnpackableObject { + bb: flatbuffers.ByteBuffer | null = null; + bb_pos = 0; + __init(i: number, bb: flatbuffers.ByteBuffer): InnerInstruction { + this.bb_pos = i; + this.bb = bb; + return this; + } + + static getRootAsInnerInstruction( + bb: flatbuffers.ByteBuffer, + obj?: InnerInstruction + ): InnerInstruction { + return (obj || new InnerInstruction()).__init( + bb.readInt32(bb.position()) + bb.position(), + bb + ); + } + + static getSizePrefixedRootAsInnerInstruction( + bb: flatbuffers.ByteBuffer, + obj?: InnerInstruction + ): InnerInstruction { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new InnerInstruction()).__init( + bb.readInt32(bb.position()) + bb.position(), + bb + ); + } + + index(): number { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? this.bb!.readUint32(this.bb_pos + offset) : 0; + } + + instructions(index: number, obj?: Instruction): Instruction | null { + const offset = this.bb!.__offset(this.bb_pos, 6); + return offset + ? (obj || new Instruction()).__init( + this.bb!.__indirect( + this.bb!.__vector(this.bb_pos + offset) + index * 4 + ), + this.bb! + ) + : null; + } + + instructionsLength(): number { + const offset = this.bb!.__offset(this.bb_pos, 6); + return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0; + } + + static startInnerInstruction(builder: flatbuffers.Builder) { + builder.startObject(2); + } + + static addIndex(builder: flatbuffers.Builder, index: number) { + builder.addFieldInt32(0, index, 0); + } + + static addInstructions( + builder: flatbuffers.Builder, + instructionsOffset: flatbuffers.Offset + ) { + builder.addFieldOffset(1, instructionsOffset, 0); + } + + static createInstructionsVector( + builder: flatbuffers.Builder, + data: flatbuffers.Offset[] + ): flatbuffers.Offset { + builder.startVector(4, data.length, 4); + for (let i = data.length - 1; i >= 0; i--) { + builder.addOffset(data[i]!); + } + return builder.endVector(); + } + + static startInstructionsVector( + builder: flatbuffers.Builder, + numElems: number + ) { + builder.startVector(4, numElems, 4); + } + + static endInnerInstruction(builder: flatbuffers.Builder): flatbuffers.Offset { + const offset = builder.endObject(); + return offset; + } + + static createInnerInstruction( + builder: flatbuffers.Builder, + index: number, + instructionsOffset: flatbuffers.Offset + ): flatbuffers.Offset { + InnerInstruction.startInnerInstruction(builder); + InnerInstruction.addIndex(builder, index); + InnerInstruction.addInstructions(builder, instructionsOffset); + return InnerInstruction.endInnerInstruction(builder); + } + + unpack(): InnerInstructionT { + return new InnerInstructionT( + this.index(), + this.bb!.createObjList( + this.instructions.bind(this), + this.instructionsLength() + ) + ); + } + + unpackTo(_o: InnerInstructionT): void { + _o.index = this.index(); + _o.instructions = this.bb!.createObjList( + this.instructions.bind(this), + this.instructionsLength() + ); + } +} + +export class InnerInstructionT implements flatbuffers.IGeneratedObject { + constructor( + public index: number = 0, + public instructions: InstructionT[] = [] + ) {} + + pack(builder: flatbuffers.Builder): flatbuffers.Offset { + const instructions = InnerInstruction.createInstructionsVector( + builder, + builder.createObjectOffsetList(this.instructions) + ); + + return InnerInstruction.createInnerInstruction( + builder, + this.index, + instructions + ); + } +} diff --git a/src/flatbuffers/solana/block/instruction.ts b/src/flatbuffers/solana/block/instruction.ts new file mode 100644 index 00000000..093c6991 --- /dev/null +++ b/src/flatbuffers/solana/block/instruction.ts @@ -0,0 +1,237 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */ + +import * as flatbuffers from 'flatbuffers'; + +export class Instruction implements flatbuffers.IUnpackableObject { + bb: flatbuffers.ByteBuffer | null = null; + bb_pos = 0; + __init(i: number, bb: flatbuffers.ByteBuffer): Instruction { + this.bb_pos = i; + this.bb = bb; + return this; + } + + static getRootAsInstruction( + bb: flatbuffers.ByteBuffer, + obj?: Instruction + ): Instruction { + return (obj || new Instruction()).__init( + bb.readInt32(bb.position()) + bb.position(), + bb + ); + } + + static getSizePrefixedRootAsInstruction( + bb: flatbuffers.ByteBuffer, + obj?: Instruction + ): Instruction { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new Instruction()).__init( + bb.readInt32(bb.position()) + bb.position(), + bb + ); + } + + parsed(): string | null; + parsed(optionalEncoding: flatbuffers.Encoding): string | Uint8Array | null; + parsed(optionalEncoding?: any): string | Uint8Array | null { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset + ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) + : null; + } + + programId(): string | null; + programId(optionalEncoding: flatbuffers.Encoding): string | Uint8Array | null; + programId(optionalEncoding?: any): string | Uint8Array | null { + const offset = this.bb!.__offset(this.bb_pos, 6); + return offset + ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) + : null; + } + + program(): string | null; + program(optionalEncoding: flatbuffers.Encoding): string | Uint8Array | null; + program(optionalEncoding?: any): string | Uint8Array | null { + const offset = this.bb!.__offset(this.bb_pos, 8); + return offset + ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) + : null; + } + + accounts(index: number): string; + accounts( + index: number, + optionalEncoding: flatbuffers.Encoding + ): string | Uint8Array; + accounts(index: number, optionalEncoding?: any): string | Uint8Array | null { + const offset = this.bb!.__offset(this.bb_pos, 10); + return offset + ? this.bb!.__string( + this.bb!.__vector(this.bb_pos + offset) + index * 4, + optionalEncoding + ) + : null; + } + + accountsLength(): number { + const offset = this.bb!.__offset(this.bb_pos, 10); + return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0; + } + + data(): string | null; + data(optionalEncoding: flatbuffers.Encoding): string | Uint8Array | null; + data(optionalEncoding?: any): string | Uint8Array | null { + const offset = this.bb!.__offset(this.bb_pos, 12); + return offset + ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) + : null; + } + + stackHeight(): number { + const offset = this.bb!.__offset(this.bb_pos, 14); + return offset ? this.bb!.readInt32(this.bb_pos + offset) : 0; + } + + static startInstruction(builder: flatbuffers.Builder) { + builder.startObject(6); + } + + static addParsed( + builder: flatbuffers.Builder, + parsedOffset: flatbuffers.Offset + ) { + builder.addFieldOffset(0, parsedOffset, 0); + } + + static addProgramId( + builder: flatbuffers.Builder, + programIdOffset: flatbuffers.Offset + ) { + builder.addFieldOffset(1, programIdOffset, 0); + } + + static addProgram( + builder: flatbuffers.Builder, + programOffset: flatbuffers.Offset + ) { + builder.addFieldOffset(2, programOffset, 0); + } + + static addAccounts( + builder: flatbuffers.Builder, + accountsOffset: flatbuffers.Offset + ) { + builder.addFieldOffset(3, accountsOffset, 0); + } + + static createAccountsVector( + builder: flatbuffers.Builder, + data: flatbuffers.Offset[] + ): flatbuffers.Offset { + builder.startVector(4, data.length, 4); + for (let i = data.length - 1; i >= 0; i--) { + builder.addOffset(data[i]!); + } + return builder.endVector(); + } + + static startAccountsVector(builder: flatbuffers.Builder, numElems: number) { + builder.startVector(4, numElems, 4); + } + + static addData(builder: flatbuffers.Builder, dataOffset: flatbuffers.Offset) { + builder.addFieldOffset(4, dataOffset, 0); + } + + static addStackHeight(builder: flatbuffers.Builder, stackHeight: number) { + builder.addFieldInt32(5, stackHeight, 0); + } + + static endInstruction(builder: flatbuffers.Builder): flatbuffers.Offset { + const offset = builder.endObject(); + return offset; + } + + static createInstruction( + builder: flatbuffers.Builder, + parsedOffset: flatbuffers.Offset, + programIdOffset: flatbuffers.Offset, + programOffset: flatbuffers.Offset, + accountsOffset: flatbuffers.Offset, + dataOffset: flatbuffers.Offset, + stackHeight: number + ): flatbuffers.Offset { + Instruction.startInstruction(builder); + Instruction.addParsed(builder, parsedOffset); + Instruction.addProgramId(builder, programIdOffset); + Instruction.addProgram(builder, programOffset); + Instruction.addAccounts(builder, accountsOffset); + Instruction.addData(builder, dataOffset); + Instruction.addStackHeight(builder, stackHeight); + return Instruction.endInstruction(builder); + } + + unpack(): InstructionT { + return new InstructionT( + this.parsed(), + this.programId(), + this.program(), + this.bb!.createScalarList( + this.accounts.bind(this), + this.accountsLength() + ), + this.data(), + this.stackHeight() + ); + } + + unpackTo(_o: InstructionT): void { + _o.parsed = this.parsed(); + _o.programId = this.programId(); + _o.program = this.program(); + _o.accounts = this.bb!.createScalarList( + this.accounts.bind(this), + this.accountsLength() + ); + _o.data = this.data(); + _o.stackHeight = this.stackHeight(); + } +} + +export class InstructionT implements flatbuffers.IGeneratedObject { + constructor( + public parsed: string | Uint8Array | null = null, + public programId: string | Uint8Array | null = null, + public program: string | Uint8Array | null = null, + public accounts: string[] = [], + public data: string | Uint8Array | null = null, + public stackHeight: number = 0 + ) {} + + pack(builder: flatbuffers.Builder): flatbuffers.Offset { + const parsed = + this.parsed !== null ? builder.createString(this.parsed!) : 0; + const programId = + this.programId !== null ? builder.createString(this.programId!) : 0; + const program = + this.program !== null ? builder.createString(this.program!) : 0; + const accounts = Instruction.createAccountsVector( + builder, + builder.createObjectOffsetList(this.accounts) + ); + const data = this.data !== null ? builder.createString(this.data!) : 0; + + return Instruction.createInstruction( + builder, + parsed, + programId, + program, + accounts, + data, + this.stackHeight + ); + } +} diff --git a/src/flatbuffers/solana/block/message.ts b/src/flatbuffers/solana/block/message.ts new file mode 100644 index 00000000..dfe83610 --- /dev/null +++ b/src/flatbuffers/solana/block/message.ts @@ -0,0 +1,184 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */ + +import * as flatbuffers from 'flatbuffers'; + +import { AccountKey, AccountKeyT } from '../block/account-key.js'; +import { Instruction, InstructionT } from '../block/instruction.js'; + +export class Message implements flatbuffers.IUnpackableObject { + bb: flatbuffers.ByteBuffer | null = null; + bb_pos = 0; + __init(i: number, bb: flatbuffers.ByteBuffer): Message { + this.bb_pos = i; + this.bb = bb; + return this; + } + + static getRootAsMessage(bb: flatbuffers.ByteBuffer, obj?: Message): Message { + return (obj || new Message()).__init( + bb.readInt32(bb.position()) + bb.position(), + bb + ); + } + + static getSizePrefixedRootAsMessage( + bb: flatbuffers.ByteBuffer, + obj?: Message + ): Message { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new Message()).__init( + bb.readInt32(bb.position()) + bb.position(), + bb + ); + } + + accountKeys(index: number, obj?: AccountKey): AccountKey | null { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset + ? (obj || new AccountKey()).__init( + this.bb!.__indirect( + this.bb!.__vector(this.bb_pos + offset) + index * 4 + ), + this.bb! + ) + : null; + } + + accountKeysLength(): number { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0; + } + + instructions(index: number, obj?: Instruction): Instruction | null { + const offset = this.bb!.__offset(this.bb_pos, 6); + return offset + ? (obj || new Instruction()).__init( + this.bb!.__indirect( + this.bb!.__vector(this.bb_pos + offset) + index * 4 + ), + this.bb! + ) + : null; + } + + instructionsLength(): number { + const offset = this.bb!.__offset(this.bb_pos, 6); + return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0; + } + + static startMessage(builder: flatbuffers.Builder) { + builder.startObject(2); + } + + static addAccountKeys( + builder: flatbuffers.Builder, + accountKeysOffset: flatbuffers.Offset + ) { + builder.addFieldOffset(0, accountKeysOffset, 0); + } + + static createAccountKeysVector( + builder: flatbuffers.Builder, + data: flatbuffers.Offset[] + ): flatbuffers.Offset { + builder.startVector(4, data.length, 4); + for (let i = data.length - 1; i >= 0; i--) { + builder.addOffset(data[i]!); + } + return builder.endVector(); + } + + static startAccountKeysVector( + builder: flatbuffers.Builder, + numElems: number + ) { + builder.startVector(4, numElems, 4); + } + + static addInstructions( + builder: flatbuffers.Builder, + instructionsOffset: flatbuffers.Offset + ) { + builder.addFieldOffset(1, instructionsOffset, 0); + } + + static createInstructionsVector( + builder: flatbuffers.Builder, + data: flatbuffers.Offset[] + ): flatbuffers.Offset { + builder.startVector(4, data.length, 4); + for (let i = data.length - 1; i >= 0; i--) { + builder.addOffset(data[i]!); + } + return builder.endVector(); + } + + static startInstructionsVector( + builder: flatbuffers.Builder, + numElems: number + ) { + builder.startVector(4, numElems, 4); + } + + static endMessage(builder: flatbuffers.Builder): flatbuffers.Offset { + const offset = builder.endObject(); + return offset; + } + + static createMessage( + builder: flatbuffers.Builder, + accountKeysOffset: flatbuffers.Offset, + instructionsOffset: flatbuffers.Offset + ): flatbuffers.Offset { + Message.startMessage(builder); + Message.addAccountKeys(builder, accountKeysOffset); + Message.addInstructions(builder, instructionsOffset); + return Message.endMessage(builder); + } + + unpack(): MessageT { + return new MessageT( + this.bb!.createObjList( + this.accountKeys.bind(this), + this.accountKeysLength() + ), + this.bb!.createObjList( + this.instructions.bind(this), + this.instructionsLength() + ) + ); + } + + unpackTo(_o: MessageT): void { + _o.accountKeys = this.bb!.createObjList( + this.accountKeys.bind(this), + this.accountKeysLength() + ); + _o.instructions = this.bb!.createObjList( + this.instructions.bind(this), + this.instructionsLength() + ); + } +} + +export class MessageT implements flatbuffers.IGeneratedObject { + constructor( + public accountKeys: AccountKeyT[] = [], + public instructions: InstructionT[] = [] + ) {} + + pack(builder: flatbuffers.Builder): flatbuffers.Offset { + const accountKeys = Message.createAccountKeysVector( + builder, + builder.createObjectOffsetList(this.accountKeys) + ); + const instructions = Message.createInstructionsVector( + builder, + builder.createObjectOffsetList(this.instructions) + ); + + return Message.createMessage(builder, accountKeys, instructions); + } +} diff --git a/src/flatbuffers/solana/block/sanctioned-entity.ts b/src/flatbuffers/solana/block/sanctioned-entity.ts new file mode 100644 index 00000000..9dcd3b76 --- /dev/null +++ b/src/flatbuffers/solana/block/sanctioned-entity.ts @@ -0,0 +1,89 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */ + +import * as flatbuffers from 'flatbuffers'; + +export class SanctionedEntity implements flatbuffers.IUnpackableObject { + bb: flatbuffers.ByteBuffer | null = null; + bb_pos = 0; + __init(i: number, bb: flatbuffers.ByteBuffer): SanctionedEntity { + this.bb_pos = i; + this.bb = bb; + return this; + } + + static getRootAsSanctionedEntity( + bb: flatbuffers.ByteBuffer, + obj?: SanctionedEntity + ): SanctionedEntity { + return (obj || new SanctionedEntity()).__init( + bb.readInt32(bb.position()) + bb.position(), + bb + ); + } + + static getSizePrefixedRootAsSanctionedEntity( + bb: flatbuffers.ByteBuffer, + obj?: SanctionedEntity + ): SanctionedEntity { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new SanctionedEntity()).__init( + bb.readInt32(bb.position()) + bb.position(), + bb + ); + } + + entity(): string | null; + entity(optionalEncoding: flatbuffers.Encoding): string | Uint8Array | null; + entity(optionalEncoding?: any): string | Uint8Array | null { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset + ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) + : null; + } + + static startSanctionedEntity(builder: flatbuffers.Builder) { + builder.startObject(1); + } + + static addEntity( + builder: flatbuffers.Builder, + entityOffset: flatbuffers.Offset + ) { + builder.addFieldOffset(0, entityOffset, 0); + } + + static endSanctionedEntity(builder: flatbuffers.Builder): flatbuffers.Offset { + const offset = builder.endObject(); + return offset; + } + + static createSanctionedEntity( + builder: flatbuffers.Builder, + entityOffset: flatbuffers.Offset + ): flatbuffers.Offset { + SanctionedEntity.startSanctionedEntity(builder); + SanctionedEntity.addEntity(builder, entityOffset); + return SanctionedEntity.endSanctionedEntity(builder); + } + + unpack(): SanctionedEntityT { + return new SanctionedEntityT(this.entity()); + } + + unpackTo(_o: SanctionedEntityT): void { + _o.entity = this.entity(); + } +} + +export class SanctionedEntityT implements flatbuffers.IGeneratedObject { + constructor(public entity: string | Uint8Array | null = null) {} + + pack(builder: flatbuffers.Builder): flatbuffers.Offset { + const entity = + this.entity !== null ? builder.createString(this.entity!) : 0; + + return SanctionedEntity.createSanctionedEntity(builder, entity); + } +} diff --git a/src/flatbuffers/solana/block/solana-block.ts b/src/flatbuffers/solana/block/solana-block.ts new file mode 100644 index 00000000..c9a40b5f --- /dev/null +++ b/src/flatbuffers/solana/block/solana-block.ts @@ -0,0 +1,252 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */ + +import * as flatbuffers from 'flatbuffers'; + +import { BlockData, BlockDataT } from '../block/block-data.js'; +import { + SolanaTransaction, + SolanaTransactionT, +} from '../block/solana-transaction.js'; + +export class SolanaBlock implements flatbuffers.IUnpackableObject { + bb: flatbuffers.ByteBuffer | null = null; + bb_pos = 0; + __init(i: number, bb: flatbuffers.ByteBuffer): SolanaBlock { + this.bb_pos = i; + this.bb = bb; + return this; + } + + static getRootAsSolanaBlock( + bb: flatbuffers.ByteBuffer, + obj?: SolanaBlock + ): SolanaBlock { + return (obj || new SolanaBlock()).__init( + bb.readInt32(bb.position()) + bb.position(), + bb + ); + } + + static getSizePrefixedRootAsSolanaBlock( + bb: flatbuffers.ByteBuffer, + obj?: SolanaBlock + ): SolanaBlock { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new SolanaBlock()).__init( + bb.readInt32(bb.position()) + bb.position(), + bb + ); + } + + hash(): string | null; + hash(optionalEncoding: flatbuffers.Encoding): string | Uint8Array | null; + hash(optionalEncoding?: any): string | Uint8Array | null { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset + ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) + : null; + } + + height(): string | null; + height(optionalEncoding: flatbuffers.Encoding): string | Uint8Array | null; + height(optionalEncoding?: any): string | Uint8Array | null { + const offset = this.bb!.__offset(this.bb_pos, 6); + return offset + ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) + : null; + } + + network(): string | null; + network(optionalEncoding: flatbuffers.Encoding): string | Uint8Array | null; + network(optionalEncoding?: any): string | Uint8Array | null { + const offset = this.bb!.__offset(this.bb_pos, 8); + return offset + ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) + : null; + } + + timestamp(): string | null; + timestamp(optionalEncoding: flatbuffers.Encoding): string | Uint8Array | null; + timestamp(optionalEncoding?: any): string | Uint8Array | null { + const offset = this.bb!.__offset(this.bb_pos, 10); + return offset + ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) + : null; + } + + blockData(obj?: BlockData): BlockData | null { + const offset = this.bb!.__offset(this.bb_pos, 12); + return offset + ? (obj || new BlockData()).__init( + this.bb!.__indirect(this.bb_pos + offset), + this.bb! + ) + : null; + } + + transactions( + index: number, + obj?: SolanaTransaction + ): SolanaTransaction | null { + const offset = this.bb!.__offset(this.bb_pos, 14); + return offset + ? (obj || new SolanaTransaction()).__init( + this.bb!.__indirect( + this.bb!.__vector(this.bb_pos + offset) + index * 4 + ), + this.bb! + ) + : null; + } + + transactionsLength(): number { + const offset = this.bb!.__offset(this.bb_pos, 14); + return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0; + } + + static startSolanaBlock(builder: flatbuffers.Builder) { + builder.startObject(6); + } + + static addHash(builder: flatbuffers.Builder, hashOffset: flatbuffers.Offset) { + builder.addFieldOffset(0, hashOffset, 0); + } + + static addHeight( + builder: flatbuffers.Builder, + heightOffset: flatbuffers.Offset + ) { + builder.addFieldOffset(1, heightOffset, 0); + } + + static addNetwork( + builder: flatbuffers.Builder, + networkOffset: flatbuffers.Offset + ) { + builder.addFieldOffset(2, networkOffset, 0); + } + + static addTimestamp( + builder: flatbuffers.Builder, + timestampOffset: flatbuffers.Offset + ) { + builder.addFieldOffset(3, timestampOffset, 0); + } + + static addBlockData( + builder: flatbuffers.Builder, + blockDataOffset: flatbuffers.Offset + ) { + builder.addFieldOffset(4, blockDataOffset, 0); + } + + static addTransactions( + builder: flatbuffers.Builder, + transactionsOffset: flatbuffers.Offset + ) { + builder.addFieldOffset(5, transactionsOffset, 0); + } + + static createTransactionsVector( + builder: flatbuffers.Builder, + data: flatbuffers.Offset[] + ): flatbuffers.Offset { + builder.startVector(4, data.length, 4); + for (let i = data.length - 1; i >= 0; i--) { + builder.addOffset(data[i]!); + } + return builder.endVector(); + } + + static startTransactionsVector( + builder: flatbuffers.Builder, + numElems: number + ) { + builder.startVector(4, numElems, 4); + } + + static endSolanaBlock(builder: flatbuffers.Builder): flatbuffers.Offset { + const offset = builder.endObject(); + return offset; + } + + static finishSolanaBlockBuffer( + builder: flatbuffers.Builder, + offset: flatbuffers.Offset + ) { + builder.finish(offset); + } + + static finishSizePrefixedSolanaBlockBuffer( + builder: flatbuffers.Builder, + offset: flatbuffers.Offset + ) { + builder.finish(offset, undefined, true); + } + + unpack(): SolanaBlockT { + return new SolanaBlockT( + this.hash(), + this.height(), + this.network(), + this.timestamp(), + this.blockData() !== null ? this.blockData()!.unpack() : null, + this.bb!.createObjList( + this.transactions.bind(this), + this.transactionsLength() + ) + ); + } + + unpackTo(_o: SolanaBlockT): void { + _o.hash = this.hash(); + _o.height = this.height(); + _o.network = this.network(); + _o.timestamp = this.timestamp(); + _o.blockData = + this.blockData() !== null ? this.blockData()!.unpack() : null; + _o.transactions = this.bb!.createObjList< + SolanaTransaction, + SolanaTransactionT + >(this.transactions.bind(this), this.transactionsLength()); + } +} + +export class SolanaBlockT implements flatbuffers.IGeneratedObject { + constructor( + public hash: string | Uint8Array | null = null, + public height: string | Uint8Array | null = null, + public network: string | Uint8Array | null = null, + public timestamp: string | Uint8Array | null = null, + public blockData: BlockDataT | null = null, + public transactions: SolanaTransactionT[] = [] + ) {} + + pack(builder: flatbuffers.Builder): flatbuffers.Offset { + const hash = this.hash !== null ? builder.createString(this.hash!) : 0; + const height = + this.height !== null ? builder.createString(this.height!) : 0; + const network = + this.network !== null ? builder.createString(this.network!) : 0; + const timestamp = + this.timestamp !== null ? builder.createString(this.timestamp!) : 0; + const blockData = + this.blockData !== null ? this.blockData!.pack(builder) : 0; + const transactions = SolanaBlock.createTransactionsVector( + builder, + builder.createObjectOffsetList(this.transactions) + ); + + SolanaBlock.startSolanaBlock(builder); + SolanaBlock.addHash(builder, hash); + SolanaBlock.addHeight(builder, height); + SolanaBlock.addNetwork(builder, network); + SolanaBlock.addTimestamp(builder, timestamp); + SolanaBlock.addBlockData(builder, blockData); + SolanaBlock.addTransactions(builder, transactions); + + return SolanaBlock.endSolanaBlock(builder); + } +} diff --git a/src/flatbuffers/solana/block/solana-transaction.ts b/src/flatbuffers/solana/block/solana-transaction.ts new file mode 100644 index 00000000..acb571b4 --- /dev/null +++ b/src/flatbuffers/solana/block/solana-transaction.ts @@ -0,0 +1,116 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */ + +import * as flatbuffers from 'flatbuffers'; + +import { Transaction, TransactionT } from '../block/transaction.js'; +import { + TransactionMeta, + TransactionMetaT, +} from '../block/transaction-meta.js'; + +export class SolanaTransaction implements flatbuffers.IUnpackableObject { + bb: flatbuffers.ByteBuffer | null = null; + bb_pos = 0; + __init(i: number, bb: flatbuffers.ByteBuffer): SolanaTransaction { + this.bb_pos = i; + this.bb = bb; + return this; + } + + static getRootAsSolanaTransaction( + bb: flatbuffers.ByteBuffer, + obj?: SolanaTransaction + ): SolanaTransaction { + return (obj || new SolanaTransaction()).__init( + bb.readInt32(bb.position()) + bb.position(), + bb + ); + } + + static getSizePrefixedRootAsSolanaTransaction( + bb: flatbuffers.ByteBuffer, + obj?: SolanaTransaction + ): SolanaTransaction { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new SolanaTransaction()).__init( + bb.readInt32(bb.position()) + bb.position(), + bb + ); + } + + transaction(obj?: Transaction): Transaction | null { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset + ? (obj || new Transaction()).__init( + this.bb!.__indirect(this.bb_pos + offset), + this.bb! + ) + : null; + } + + meta(obj?: TransactionMeta): TransactionMeta | null { + const offset = this.bb!.__offset(this.bb_pos, 6); + return offset + ? (obj || new TransactionMeta()).__init( + this.bb!.__indirect(this.bb_pos + offset), + this.bb! + ) + : null; + } + + static startSolanaTransaction(builder: flatbuffers.Builder) { + builder.startObject(2); + } + + static addTransaction( + builder: flatbuffers.Builder, + transactionOffset: flatbuffers.Offset + ) { + builder.addFieldOffset(0, transactionOffset, 0); + } + + static addMeta(builder: flatbuffers.Builder, metaOffset: flatbuffers.Offset) { + builder.addFieldOffset(1, metaOffset, 0); + } + + static endSolanaTransaction( + builder: flatbuffers.Builder + ): flatbuffers.Offset { + const offset = builder.endObject(); + return offset; + } + + unpack(): SolanaTransactionT { + return new SolanaTransactionT( + this.transaction() !== null ? this.transaction()!.unpack() : null, + this.meta() !== null ? this.meta()!.unpack() : null + ); + } + + unpackTo(_o: SolanaTransactionT): void { + _o.transaction = + this.transaction() !== null ? this.transaction()!.unpack() : null; + _o.meta = this.meta() !== null ? this.meta()!.unpack() : null; + } +} + +export class SolanaTransactionT implements flatbuffers.IGeneratedObject { + constructor( + public transaction: TransactionT | null = null, + public meta: TransactionMetaT | null = null + ) {} + + pack(builder: flatbuffers.Builder): flatbuffers.Offset { + const transaction = + this.transaction !== null ? this.transaction!.pack(builder) : 0; + const meta = this.meta !== null ? this.meta!.pack(builder) : 0; + + SolanaTransaction.startSolanaTransaction(builder); + SolanaTransaction.addTransaction(builder, transaction); + SolanaTransaction.addMeta(builder, meta); + + return SolanaTransaction.endSolanaTransaction(builder); + } +} diff --git a/src/flatbuffers/solana/block/token-balance.ts b/src/flatbuffers/solana/block/token-balance.ts new file mode 100644 index 00000000..8fd54b7f --- /dev/null +++ b/src/flatbuffers/solana/block/token-balance.ts @@ -0,0 +1,165 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */ + +import * as flatbuffers from 'flatbuffers'; + +import { UiTokenAmount, UiTokenAmountT } from '../block/ui-token-amount.js'; + +export class TokenBalance implements flatbuffers.IUnpackableObject { + bb: flatbuffers.ByteBuffer | null = null; + bb_pos = 0; + __init(i: number, bb: flatbuffers.ByteBuffer): TokenBalance { + this.bb_pos = i; + this.bb = bb; + return this; + } + + static getRootAsTokenBalance( + bb: flatbuffers.ByteBuffer, + obj?: TokenBalance + ): TokenBalance { + return (obj || new TokenBalance()).__init( + bb.readInt32(bb.position()) + bb.position(), + bb + ); + } + + static getSizePrefixedRootAsTokenBalance( + bb: flatbuffers.ByteBuffer, + obj?: TokenBalance + ): TokenBalance { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new TokenBalance()).__init( + bb.readInt32(bb.position()) + bb.position(), + bb + ); + } + + accountIndex(): number { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? this.bb!.readUint32(this.bb_pos + offset) : 0; + } + + mint(): string | null; + mint(optionalEncoding: flatbuffers.Encoding): string | Uint8Array | null; + mint(optionalEncoding?: any): string | Uint8Array | null { + const offset = this.bb!.__offset(this.bb_pos, 6); + return offset + ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) + : null; + } + + owner(): string | null; + owner(optionalEncoding: flatbuffers.Encoding): string | Uint8Array | null; + owner(optionalEncoding?: any): string | Uint8Array | null { + const offset = this.bb!.__offset(this.bb_pos, 8); + return offset + ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) + : null; + } + + programId(): string | null; + programId(optionalEncoding: flatbuffers.Encoding): string | Uint8Array | null; + programId(optionalEncoding?: any): string | Uint8Array | null { + const offset = this.bb!.__offset(this.bb_pos, 10); + return offset + ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) + : null; + } + + uiTokenAmount(obj?: UiTokenAmount): UiTokenAmount | null { + const offset = this.bb!.__offset(this.bb_pos, 12); + return offset + ? (obj || new UiTokenAmount()).__init( + this.bb!.__indirect(this.bb_pos + offset), + this.bb! + ) + : null; + } + + static startTokenBalance(builder: flatbuffers.Builder) { + builder.startObject(5); + } + + static addAccountIndex(builder: flatbuffers.Builder, accountIndex: number) { + builder.addFieldInt32(0, accountIndex, 0); + } + + static addMint(builder: flatbuffers.Builder, mintOffset: flatbuffers.Offset) { + builder.addFieldOffset(1, mintOffset, 0); + } + + static addOwner( + builder: flatbuffers.Builder, + ownerOffset: flatbuffers.Offset + ) { + builder.addFieldOffset(2, ownerOffset, 0); + } + + static addProgramId( + builder: flatbuffers.Builder, + programIdOffset: flatbuffers.Offset + ) { + builder.addFieldOffset(3, programIdOffset, 0); + } + + static addUiTokenAmount( + builder: flatbuffers.Builder, + uiTokenAmountOffset: flatbuffers.Offset + ) { + builder.addFieldOffset(4, uiTokenAmountOffset, 0); + } + + static endTokenBalance(builder: flatbuffers.Builder): flatbuffers.Offset { + const offset = builder.endObject(); + return offset; + } + + unpack(): TokenBalanceT { + return new TokenBalanceT( + this.accountIndex(), + this.mint(), + this.owner(), + this.programId(), + this.uiTokenAmount() !== null ? this.uiTokenAmount()!.unpack() : null + ); + } + + unpackTo(_o: TokenBalanceT): void { + _o.accountIndex = this.accountIndex(); + _o.mint = this.mint(); + _o.owner = this.owner(); + _o.programId = this.programId(); + _o.uiTokenAmount = + this.uiTokenAmount() !== null ? this.uiTokenAmount()!.unpack() : null; + } +} + +export class TokenBalanceT implements flatbuffers.IGeneratedObject { + constructor( + public accountIndex: number = 0, + public mint: string | Uint8Array | null = null, + public owner: string | Uint8Array | null = null, + public programId: string | Uint8Array | null = null, + public uiTokenAmount: UiTokenAmountT | null = null + ) {} + + pack(builder: flatbuffers.Builder): flatbuffers.Offset { + const mint = this.mint !== null ? builder.createString(this.mint!) : 0; + const owner = this.owner !== null ? builder.createString(this.owner!) : 0; + const programId = + this.programId !== null ? builder.createString(this.programId!) : 0; + const uiTokenAmount = + this.uiTokenAmount !== null ? this.uiTokenAmount!.pack(builder) : 0; + + TokenBalance.startTokenBalance(builder); + TokenBalance.addAccountIndex(builder, this.accountIndex); + TokenBalance.addMint(builder, mint); + TokenBalance.addOwner(builder, owner); + TokenBalance.addProgramId(builder, programId); + TokenBalance.addUiTokenAmount(builder, uiTokenAmount); + + return TokenBalance.endTokenBalance(builder); + } +} diff --git a/src/flatbuffers/solana/block/transaction-meta.ts b/src/flatbuffers/solana/block/transaction-meta.ts new file mode 100644 index 00000000..f3f88b3d --- /dev/null +++ b/src/flatbuffers/solana/block/transaction-meta.ts @@ -0,0 +1,478 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */ + +import * as flatbuffers from 'flatbuffers'; + +import { + InnerInstruction, + InnerInstructionT, +} from '../block/inner-instruction.js'; +import { TokenBalance, TokenBalanceT } from '../block/token-balance.js'; + +export class TransactionMeta implements flatbuffers.IUnpackableObject { + bb: flatbuffers.ByteBuffer | null = null; + bb_pos = 0; + __init(i: number, bb: flatbuffers.ByteBuffer): TransactionMeta { + this.bb_pos = i; + this.bb = bb; + return this; + } + + static getRootAsTransactionMeta( + bb: flatbuffers.ByteBuffer, + obj?: TransactionMeta + ): TransactionMeta { + return (obj || new TransactionMeta()).__init( + bb.readInt32(bb.position()) + bb.position(), + bb + ); + } + + static getSizePrefixedRootAsTransactionMeta( + bb: flatbuffers.ByteBuffer, + obj?: TransactionMeta + ): TransactionMeta { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new TransactionMeta()).__init( + bb.readInt32(bb.position()) + bb.position(), + bb + ); + } + + computeUnitsConsumed(): bigint { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? this.bb!.readUint64(this.bb_pos + offset) : BigInt('0'); + } + + err(): string | null; + err(optionalEncoding: flatbuffers.Encoding): string | Uint8Array | null; + err(optionalEncoding?: any): string | Uint8Array | null { + const offset = this.bb!.__offset(this.bb_pos, 6); + return offset + ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) + : null; + } + + fee(): bigint { + const offset = this.bb!.__offset(this.bb_pos, 8); + return offset ? this.bb!.readUint64(this.bb_pos + offset) : BigInt('0'); + } + + innerInstructions( + index: number, + obj?: InnerInstruction + ): InnerInstruction | null { + const offset = this.bb!.__offset(this.bb_pos, 10); + return offset + ? (obj || new InnerInstruction()).__init( + this.bb!.__indirect( + this.bb!.__vector(this.bb_pos + offset) + index * 4 + ), + this.bb! + ) + : null; + } + + innerInstructionsLength(): number { + const offset = this.bb!.__offset(this.bb_pos, 10); + return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0; + } + + logMessages(index: number): string; + logMessages( + index: number, + optionalEncoding: flatbuffers.Encoding + ): string | Uint8Array; + logMessages( + index: number, + optionalEncoding?: any + ): string | Uint8Array | null { + const offset = this.bb!.__offset(this.bb_pos, 12); + return offset + ? this.bb!.__string( + this.bb!.__vector(this.bb_pos + offset) + index * 4, + optionalEncoding + ) + : null; + } + + logMessagesLength(): number { + const offset = this.bb!.__offset(this.bb_pos, 12); + return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0; + } + + preBalances(index: number): bigint | null { + const offset = this.bb!.__offset(this.bb_pos, 14); + return offset + ? this.bb!.readUint64(this.bb!.__vector(this.bb_pos + offset) + index * 8) + : BigInt(0); + } + + preBalancesLength(): number { + const offset = this.bb!.__offset(this.bb_pos, 14); + return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0; + } + + postBalances(index: number): bigint | null { + const offset = this.bb!.__offset(this.bb_pos, 16); + return offset + ? this.bb!.readUint64(this.bb!.__vector(this.bb_pos + offset) + index * 8) + : BigInt(0); + } + + postBalancesLength(): number { + const offset = this.bb!.__offset(this.bb_pos, 16); + return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0; + } + + preTokenBalances(index: number, obj?: TokenBalance): TokenBalance | null { + const offset = this.bb!.__offset(this.bb_pos, 18); + return offset + ? (obj || new TokenBalance()).__init( + this.bb!.__indirect( + this.bb!.__vector(this.bb_pos + offset) + index * 4 + ), + this.bb! + ) + : null; + } + + preTokenBalancesLength(): number { + const offset = this.bb!.__offset(this.bb_pos, 18); + return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0; + } + + postTokenBalances(index: number, obj?: TokenBalance): TokenBalance | null { + const offset = this.bb!.__offset(this.bb_pos, 20); + return offset + ? (obj || new TokenBalance()).__init( + this.bb!.__indirect( + this.bb!.__vector(this.bb_pos + offset) + index * 4 + ), + this.bb! + ) + : null; + } + + postTokenBalancesLength(): number { + const offset = this.bb!.__offset(this.bb_pos, 20); + return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0; + } + + static startTransactionMeta(builder: flatbuffers.Builder) { + builder.startObject(9); + } + + static addComputeUnitsConsumed( + builder: flatbuffers.Builder, + computeUnitsConsumed: bigint + ) { + builder.addFieldInt64(0, computeUnitsConsumed, BigInt('0')); + } + + static addErr(builder: flatbuffers.Builder, errOffset: flatbuffers.Offset) { + builder.addFieldOffset(1, errOffset, 0); + } + + static addFee(builder: flatbuffers.Builder, fee: bigint) { + builder.addFieldInt64(2, fee, BigInt('0')); + } + + static addInnerInstructions( + builder: flatbuffers.Builder, + innerInstructionsOffset: flatbuffers.Offset + ) { + builder.addFieldOffset(3, innerInstructionsOffset, 0); + } + + static createInnerInstructionsVector( + builder: flatbuffers.Builder, + data: flatbuffers.Offset[] + ): flatbuffers.Offset { + builder.startVector(4, data.length, 4); + for (let i = data.length - 1; i >= 0; i--) { + builder.addOffset(data[i]!); + } + return builder.endVector(); + } + + static startInnerInstructionsVector( + builder: flatbuffers.Builder, + numElems: number + ) { + builder.startVector(4, numElems, 4); + } + + static addLogMessages( + builder: flatbuffers.Builder, + logMessagesOffset: flatbuffers.Offset + ) { + builder.addFieldOffset(4, logMessagesOffset, 0); + } + + static createLogMessagesVector( + builder: flatbuffers.Builder, + data: flatbuffers.Offset[] + ): flatbuffers.Offset { + builder.startVector(4, data.length, 4); + for (let i = data.length - 1; i >= 0; i--) { + builder.addOffset(data[i]!); + } + return builder.endVector(); + } + + static startLogMessagesVector( + builder: flatbuffers.Builder, + numElems: number + ) { + builder.startVector(4, numElems, 4); + } + + static addPreBalances( + builder: flatbuffers.Builder, + preBalancesOffset: flatbuffers.Offset + ) { + builder.addFieldOffset(5, preBalancesOffset, 0); + } + + static createPreBalancesVector( + builder: flatbuffers.Builder, + data: bigint[] + ): flatbuffers.Offset { + builder.startVector(8, data.length, 8); + for (let i = data.length - 1; i >= 0; i--) { + builder.addInt64(data[i]!); + } + return builder.endVector(); + } + + static startPreBalancesVector( + builder: flatbuffers.Builder, + numElems: number + ) { + builder.startVector(8, numElems, 8); + } + + static addPostBalances( + builder: flatbuffers.Builder, + postBalancesOffset: flatbuffers.Offset + ) { + builder.addFieldOffset(6, postBalancesOffset, 0); + } + + static createPostBalancesVector( + builder: flatbuffers.Builder, + data: bigint[] + ): flatbuffers.Offset { + builder.startVector(8, data.length, 8); + for (let i = data.length - 1; i >= 0; i--) { + builder.addInt64(data[i]!); + } + return builder.endVector(); + } + + static startPostBalancesVector( + builder: flatbuffers.Builder, + numElems: number + ) { + builder.startVector(8, numElems, 8); + } + + static addPreTokenBalances( + builder: flatbuffers.Builder, + preTokenBalancesOffset: flatbuffers.Offset + ) { + builder.addFieldOffset(7, preTokenBalancesOffset, 0); + } + + static createPreTokenBalancesVector( + builder: flatbuffers.Builder, + data: flatbuffers.Offset[] + ): flatbuffers.Offset { + builder.startVector(4, data.length, 4); + for (let i = data.length - 1; i >= 0; i--) { + builder.addOffset(data[i]!); + } + return builder.endVector(); + } + + static startPreTokenBalancesVector( + builder: flatbuffers.Builder, + numElems: number + ) { + builder.startVector(4, numElems, 4); + } + + static addPostTokenBalances( + builder: flatbuffers.Builder, + postTokenBalancesOffset: flatbuffers.Offset + ) { + builder.addFieldOffset(8, postTokenBalancesOffset, 0); + } + + static createPostTokenBalancesVector( + builder: flatbuffers.Builder, + data: flatbuffers.Offset[] + ): flatbuffers.Offset { + builder.startVector(4, data.length, 4); + for (let i = data.length - 1; i >= 0; i--) { + builder.addOffset(data[i]!); + } + return builder.endVector(); + } + + static startPostTokenBalancesVector( + builder: flatbuffers.Builder, + numElems: number + ) { + builder.startVector(4, numElems, 4); + } + + static endTransactionMeta(builder: flatbuffers.Builder): flatbuffers.Offset { + const offset = builder.endObject(); + return offset; + } + + static createTransactionMeta( + builder: flatbuffers.Builder, + computeUnitsConsumed: bigint, + errOffset: flatbuffers.Offset, + fee: bigint, + innerInstructionsOffset: flatbuffers.Offset, + logMessagesOffset: flatbuffers.Offset, + preBalancesOffset: flatbuffers.Offset, + postBalancesOffset: flatbuffers.Offset, + preTokenBalancesOffset: flatbuffers.Offset, + postTokenBalancesOffset: flatbuffers.Offset + ): flatbuffers.Offset { + TransactionMeta.startTransactionMeta(builder); + TransactionMeta.addComputeUnitsConsumed(builder, computeUnitsConsumed); + TransactionMeta.addErr(builder, errOffset); + TransactionMeta.addFee(builder, fee); + TransactionMeta.addInnerInstructions(builder, innerInstructionsOffset); + TransactionMeta.addLogMessages(builder, logMessagesOffset); + TransactionMeta.addPreBalances(builder, preBalancesOffset); + TransactionMeta.addPostBalances(builder, postBalancesOffset); + TransactionMeta.addPreTokenBalances(builder, preTokenBalancesOffset); + TransactionMeta.addPostTokenBalances(builder, postTokenBalancesOffset); + return TransactionMeta.endTransactionMeta(builder); + } + + unpack(): TransactionMetaT { + return new TransactionMetaT( + this.computeUnitsConsumed(), + this.err(), + this.fee(), + this.bb!.createObjList( + this.innerInstructions.bind(this), + this.innerInstructionsLength() + ), + this.bb!.createScalarList( + this.logMessages.bind(this), + this.logMessagesLength() + ), + this.bb!.createScalarList( + this.preBalances.bind(this), + this.preBalancesLength() + ), + this.bb!.createScalarList( + this.postBalances.bind(this), + this.postBalancesLength() + ), + this.bb!.createObjList( + this.preTokenBalances.bind(this), + this.preTokenBalancesLength() + ), + this.bb!.createObjList( + this.postTokenBalances.bind(this), + this.postTokenBalancesLength() + ) + ); + } + + unpackTo(_o: TransactionMetaT): void { + _o.computeUnitsConsumed = this.computeUnitsConsumed(); + _o.err = this.err(); + _o.fee = this.fee(); + _o.innerInstructions = this.bb!.createObjList< + InnerInstruction, + InnerInstructionT + >(this.innerInstructions.bind(this), this.innerInstructionsLength()); + _o.logMessages = this.bb!.createScalarList( + this.logMessages.bind(this), + this.logMessagesLength() + ); + _o.preBalances = this.bb!.createScalarList( + this.preBalances.bind(this), + this.preBalancesLength() + ); + _o.postBalances = this.bb!.createScalarList( + this.postBalances.bind(this), + this.postBalancesLength() + ); + _o.preTokenBalances = this.bb!.createObjList( + this.preTokenBalances.bind(this), + this.preTokenBalancesLength() + ); + _o.postTokenBalances = this.bb!.createObjList( + this.postTokenBalances.bind(this), + this.postTokenBalancesLength() + ); + } +} + +export class TransactionMetaT implements flatbuffers.IGeneratedObject { + constructor( + public computeUnitsConsumed: bigint = BigInt('0'), + public err: string | Uint8Array | null = null, + public fee: bigint = BigInt('0'), + public innerInstructions: InnerInstructionT[] = [], + public logMessages: string[] = [], + public preBalances: bigint[] = [], + public postBalances: bigint[] = [], + public preTokenBalances: TokenBalanceT[] = [], + public postTokenBalances: TokenBalanceT[] = [] + ) {} + + pack(builder: flatbuffers.Builder): flatbuffers.Offset { + const err = this.err !== null ? builder.createString(this.err!) : 0; + const innerInstructions = TransactionMeta.createInnerInstructionsVector( + builder, + builder.createObjectOffsetList(this.innerInstructions) + ); + const logMessages = TransactionMeta.createLogMessagesVector( + builder, + builder.createObjectOffsetList(this.logMessages) + ); + const preBalances = TransactionMeta.createPreBalancesVector( + builder, + this.preBalances + ); + const postBalances = TransactionMeta.createPostBalancesVector( + builder, + this.postBalances + ); + const preTokenBalances = TransactionMeta.createPreTokenBalancesVector( + builder, + builder.createObjectOffsetList(this.preTokenBalances) + ); + const postTokenBalances = TransactionMeta.createPostTokenBalancesVector( + builder, + builder.createObjectOffsetList(this.postTokenBalances) + ); + + return TransactionMeta.createTransactionMeta( + builder, + this.computeUnitsConsumed, + err, + this.fee, + innerInstructions, + logMessages, + preBalances, + postBalances, + preTokenBalances, + postTokenBalances + ); + } +} diff --git a/src/flatbuffers/solana/block/transaction.ts b/src/flatbuffers/solana/block/transaction.ts new file mode 100644 index 00000000..f40c34e3 --- /dev/null +++ b/src/flatbuffers/solana/block/transaction.ts @@ -0,0 +1,155 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */ + +import * as flatbuffers from 'flatbuffers'; + +import { Message, MessageT } from '../block/message.js'; + +export class Transaction implements flatbuffers.IUnpackableObject { + bb: flatbuffers.ByteBuffer | null = null; + bb_pos = 0; + __init(i: number, bb: flatbuffers.ByteBuffer): Transaction { + this.bb_pos = i; + this.bb = bb; + return this; + } + + static getRootAsTransaction( + bb: flatbuffers.ByteBuffer, + obj?: Transaction + ): Transaction { + return (obj || new Transaction()).__init( + bb.readInt32(bb.position()) + bb.position(), + bb + ); + } + + static getSizePrefixedRootAsTransaction( + bb: flatbuffers.ByteBuffer, + obj?: Transaction + ): Transaction { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new Transaction()).__init( + bb.readInt32(bb.position()) + bb.position(), + bb + ); + } + + message(obj?: Message): Message | null { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset + ? (obj || new Message()).__init( + this.bb!.__indirect(this.bb_pos + offset), + this.bb! + ) + : null; + } + + signatures(index: number): string; + signatures( + index: number, + optionalEncoding: flatbuffers.Encoding + ): string | Uint8Array; + signatures( + index: number, + optionalEncoding?: any + ): string | Uint8Array | null { + const offset = this.bb!.__offset(this.bb_pos, 6); + return offset + ? this.bb!.__string( + this.bb!.__vector(this.bb_pos + offset) + index * 4, + optionalEncoding + ) + : null; + } + + signaturesLength(): number { + const offset = this.bb!.__offset(this.bb_pos, 6); + return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0; + } + + static startTransaction(builder: flatbuffers.Builder) { + builder.startObject(2); + } + + static addMessage( + builder: flatbuffers.Builder, + messageOffset: flatbuffers.Offset + ) { + builder.addFieldOffset(0, messageOffset, 0); + } + + static addSignatures( + builder: flatbuffers.Builder, + signaturesOffset: flatbuffers.Offset + ) { + builder.addFieldOffset(1, signaturesOffset, 0); + } + + static createSignaturesVector( + builder: flatbuffers.Builder, + data: flatbuffers.Offset[] + ): flatbuffers.Offset { + builder.startVector(4, data.length, 4); + for (let i = data.length - 1; i >= 0; i--) { + builder.addOffset(data[i]!); + } + return builder.endVector(); + } + + static startSignaturesVector(builder: flatbuffers.Builder, numElems: number) { + builder.startVector(4, numElems, 4); + } + + static endTransaction(builder: flatbuffers.Builder): flatbuffers.Offset { + const offset = builder.endObject(); + return offset; + } + + static createTransaction( + builder: flatbuffers.Builder, + messageOffset: flatbuffers.Offset, + signaturesOffset: flatbuffers.Offset + ): flatbuffers.Offset { + Transaction.startTransaction(builder); + Transaction.addMessage(builder, messageOffset); + Transaction.addSignatures(builder, signaturesOffset); + return Transaction.endTransaction(builder); + } + + unpack(): TransactionT { + return new TransactionT( + this.message() !== null ? this.message()!.unpack() : null, + this.bb!.createScalarList( + this.signatures.bind(this), + this.signaturesLength() + ) + ); + } + + unpackTo(_o: TransactionT): void { + _o.message = this.message() !== null ? this.message()!.unpack() : null; + _o.signatures = this.bb!.createScalarList( + this.signatures.bind(this), + this.signaturesLength() + ); + } +} + +export class TransactionT implements flatbuffers.IGeneratedObject { + constructor( + public message: MessageT | null = null, + public signatures: string[] = [] + ) {} + + pack(builder: flatbuffers.Builder): flatbuffers.Offset { + const message = this.message !== null ? this.message!.pack(builder) : 0; + const signatures = Transaction.createSignaturesVector( + builder, + builder.createObjectOffsetList(this.signatures) + ); + + return Transaction.createTransaction(builder, message, signatures); + } +} diff --git a/src/flatbuffers/solana/block/ui-token-amount.ts b/src/flatbuffers/solana/block/ui-token-amount.ts new file mode 100644 index 00000000..d487a85c --- /dev/null +++ b/src/flatbuffers/solana/block/ui-token-amount.ts @@ -0,0 +1,154 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */ + +import * as flatbuffers from 'flatbuffers'; + +export class UiTokenAmount implements flatbuffers.IUnpackableObject { + bb: flatbuffers.ByteBuffer | null = null; + bb_pos = 0; + __init(i: number, bb: flatbuffers.ByteBuffer): UiTokenAmount { + this.bb_pos = i; + this.bb = bb; + return this; + } + + static getRootAsUiTokenAmount( + bb: flatbuffers.ByteBuffer, + obj?: UiTokenAmount + ): UiTokenAmount { + return (obj || new UiTokenAmount()).__init( + bb.readInt32(bb.position()) + bb.position(), + bb + ); + } + + static getSizePrefixedRootAsUiTokenAmount( + bb: flatbuffers.ByteBuffer, + obj?: UiTokenAmount + ): UiTokenAmount { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new UiTokenAmount()).__init( + bb.readInt32(bb.position()) + bb.position(), + bb + ); + } + + amount(): string | null; + amount(optionalEncoding: flatbuffers.Encoding): string | Uint8Array | null; + amount(optionalEncoding?: any): string | Uint8Array | null { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset + ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) + : null; + } + + decimals(): number { + const offset = this.bb!.__offset(this.bb_pos, 6); + return offset ? this.bb!.readUint32(this.bb_pos + offset) : 0; + } + + uiAmount(): number { + const offset = this.bb!.__offset(this.bb_pos, 8); + return offset ? this.bb!.readFloat64(this.bb_pos + offset) : 0.0; + } + + uiAmountString(): string | null; + uiAmountString( + optionalEncoding: flatbuffers.Encoding + ): string | Uint8Array | null; + uiAmountString(optionalEncoding?: any): string | Uint8Array | null { + const offset = this.bb!.__offset(this.bb_pos, 10); + return offset + ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) + : null; + } + + static startUiTokenAmount(builder: flatbuffers.Builder) { + builder.startObject(4); + } + + static addAmount( + builder: flatbuffers.Builder, + amountOffset: flatbuffers.Offset + ) { + builder.addFieldOffset(0, amountOffset, 0); + } + + static addDecimals(builder: flatbuffers.Builder, decimals: number) { + builder.addFieldInt32(1, decimals, 0); + } + + static addUiAmount(builder: flatbuffers.Builder, uiAmount: number) { + builder.addFieldFloat64(2, uiAmount, 0.0); + } + + static addUiAmountString( + builder: flatbuffers.Builder, + uiAmountStringOffset: flatbuffers.Offset + ) { + builder.addFieldOffset(3, uiAmountStringOffset, 0); + } + + static endUiTokenAmount(builder: flatbuffers.Builder): flatbuffers.Offset { + const offset = builder.endObject(); + return offset; + } + + static createUiTokenAmount( + builder: flatbuffers.Builder, + amountOffset: flatbuffers.Offset, + decimals: number, + uiAmount: number, + uiAmountStringOffset: flatbuffers.Offset + ): flatbuffers.Offset { + UiTokenAmount.startUiTokenAmount(builder); + UiTokenAmount.addAmount(builder, amountOffset); + UiTokenAmount.addDecimals(builder, decimals); + UiTokenAmount.addUiAmount(builder, uiAmount); + UiTokenAmount.addUiAmountString(builder, uiAmountStringOffset); + return UiTokenAmount.endUiTokenAmount(builder); + } + + unpack(): UiTokenAmountT { + return new UiTokenAmountT( + this.amount(), + this.decimals(), + this.uiAmount(), + this.uiAmountString() + ); + } + + unpackTo(_o: UiTokenAmountT): void { + _o.amount = this.amount(); + _o.decimals = this.decimals(); + _o.uiAmount = this.uiAmount(); + _o.uiAmountString = this.uiAmountString(); + } +} + +export class UiTokenAmountT implements flatbuffers.IGeneratedObject { + constructor( + public amount: string | Uint8Array | null = null, + public decimals: number = 0, + public uiAmount: number = 0.0, + public uiAmountString: string | Uint8Array | null = null + ) {} + + pack(builder: flatbuffers.Builder): flatbuffers.Offset { + const amount = + this.amount !== null ? builder.createString(this.amount!) : 0; + const uiAmountString = + this.uiAmountString !== null + ? builder.createString(this.uiAmountString!) + : 0; + + return UiTokenAmount.createUiTokenAmount( + builder, + amount, + this.decimals, + this.uiAmount, + uiAmountString + ); + } +} diff --git a/src/index.ts b/src/index.ts index e0e5e9fc..8f862d4d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,30 +1,47 @@ -export * from './sdk'; -export * from './test-sdk'; -export * from './types/IRangeNetwork'; -export * from './types/chain/IRangeBlock'; -export * from './types/chain/cosmoshub-4/IRangeBlockCosmosHub4Trx'; -export * from './types/chain/cosmoshub-4/IRangeBlockCosmosHub4TrxMsg'; -export * from './types/chain/grand-1/IRangeBlockGrand1Trx'; -export * from './types/chain/grand-1/IRangeBlockGrand1TrxMsg'; -export * from './types/chain/mocha-4/IRangeBlockMocha4Trx'; -export * from './types/chain/mocha-4/IRangeBlockMocha4TrxMsg'; -export * from './types/chain/neutron-1/IRangeBlockNeutron1Trx'; -export * from './types/chain/neutron-1/IRangeBlockNeutron1TrxMsg'; -export * from './types/chain/noble-1/IRangeBlockNoble1Trx'; -export * from './types/chain/noble-1/IRangeBlockNoble1TrxMsg'; -export * from './types/chain/osmosis-1/IRangeBlockOsmosis1Trx'; -export * from './types/chain/osmosis-1/IRangeBlockOsmosis1TrxMsg'; -export * from './types/chain/osmo-test-5/IRangeBlockOsmoTest5Trx'; -export * from './types/chain/osmo-test-5/IRangeBlockOsmoTest5TrxMsg'; -export * from './types/chain/stride-1/IRangeBlockStride1Trx'; -export * from './types/chain/stride-1/IRangeBlockStride1TrxMsg'; -export * from './types/chain/celestia/IRangeBlockCelestiaTrx'; -export * from './types/chain/celestia/IRangeBlockCelestiaTrxMsg'; -export * from './types/chain/dydx-mainnet-1/IRangeBlockDydxMainnet1Trx'; -export * from './types/chain/dydx-mainnet-1/IRangeBlockDydxMainnet1TrxMsg'; -export * from './types/IRangeEvent'; -export * from './types/IRangeAlertRule'; -export * from './cosmos/CosmosClient'; -export * from './services/fetchBlock'; -export * from './services/getCosmosClient'; -export * from './services/fetchBlocksByRange'; +export * from './wrappers/solana-block-wrapper'; +export * from './threadpool/pool'; +export * from './threadpool/runner'; +export * from './types/IAlertRule'; +export * from './types/IEvent'; +export * from './types/INetwork'; +export * from './types/IRule'; +export * from './types/ITask'; +export * from './types/IRunnerConfig'; +export * from './types/IEVMBlock'; +export * from './types/ISolanaBlock'; +export * from './types/ICosmosBlock'; +export * from './utils/processor'; +export * from './utils/basic'; +export * from './utils/dayjs'; +export * from './utils/doc-helper'; +export * from './utils/explorer-api'; +export * from './utils/fill-findings'; +export * from './utils/logger'; +export * from './utils/number-fmt'; +export * from './utils/redis-keys'; +export * from './utils/redis'; +export * from './utils/risk-score'; +export * from './utils/safe-fetch'; +export * from './utils/skip-tick'; +export * from './utils/testing-helpers'; +export * from './utils/updateRuleParamsInterface'; +export * from './utils/validParam'; +export * from './utils/validateParameters'; +export * from './services/AssetManager'; +export * from './services/event-service'; +export * from './services/stats-service'; +export * from './services/alerting-redis'; +export * from './services/axios'; +export * from './services/rpc'; +export * from './utils/slack'; +export * from './services/slack-monitor'; +export * from './utils/solana/balance-change'; +export * from './utils/solana/programs'; +export * from './utils/solana/spl-actions'; +export * from './utils/solana/tx-actions'; +export * from './services/cached-requests'; +export * from './services/range-api'; +export { prometheusRegistry } from './services/prometheus-registry'; +export * from './utils/summary-helpers'; +export { processPayload } from './processors/taskProcessor'; +export * from './utils/pipeline-setup'; diff --git a/src/logger.ts b/src/logger.ts deleted file mode 100644 index c1352960..00000000 --- a/src/logger.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { pino, stdTimeFunctions } from 'pino'; - -export function getLogger(args: { name: string }) { - const logger = pino({ - name: args.name, - timestamp: stdTimeFunctions.isoTime, - formatters: { - level: (label: string) => { - return { level: label }; - }, - bindings: () => { - return {}; - }, - }, - }); - - return logger; -} diff --git a/src/network.ts b/src/network.ts deleted file mode 100644 index 592a5b5b..00000000 --- a/src/network.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { ZodLiteral, z } from 'zod'; - -export enum NetworkEnum { - CosmosHub4 = 'cosmoshub-4', - Grand1 = 'grand-1', - Mocha4 = 'mocha-4', - Neutron1 = 'neutron-1', - Noble1 = 'noble-1', - Osmosis1 = 'osmosis-1', - OsmoTest5 = 'osmo-test-5', - Stride1 = 'stride-1', - Celestia = 'celestia', - DydxMainnet1 = 'dydx-mainnet-1', - Dymension = 'dymension_1100-1', - Solana = 'solana', -} - -export const NetworkValidator = z.union( - Object.values(NetworkEnum).map((networkId) => z.literal(networkId)) as [ - ZodLiteral<'cosmoshub-4'>, - ZodLiteral<'grand-1'>, - ZodLiteral<'mocha-4'>, - ZodLiteral<'neutron-1'>, - ZodLiteral<'noble-1'>, - ZodLiteral<'osmosis-1'>, - ZodLiteral<'osmo-test-5'>, - ZodLiteral<'stride-1'>, - ZodLiteral<'celestia'>, - ZodLiteral<'dydx-mainnet-1'>, - ZodLiteral<'dymension_1100-1'>, - ], -); - -export type Network = z.infer; - -export const networkArray = Object.values(NetworkEnum) as Network[]; - -export const validateNetwork = (network: Network) => { - if (!networkArray.includes(network)) { - throw new Error( - `The network ${network} is not supported. Supporter networks are: ${Object.values( - NetworkEnum, - ).join(', ')}`, - ); - } -}; diff --git a/src/processors/benchmark/AsyncCall.ts b/src/processors/benchmark/AsyncCall.ts new file mode 100644 index 00000000..74c224e8 --- /dev/null +++ b/src/processors/benchmark/AsyncCall.ts @@ -0,0 +1,19 @@ +import { sleep } from '../../utils/basic'; +import { ISubEvent } from '../../types/IEvent'; +import { BlockProcessor, IBlockProcessor, Rule } from '../../utils/processor'; + +@Rule({ + type: 'AsyncCall', + label: 'Async Call', + description: 'Benchmark processor for async calls', + parameters: [], + networks: ['solana', 'osmosis-1'], + tags: ['account'], + severity: 'low', +}) +export class AsyncCallProcessor extends BlockProcessor { + async callback({ rule, block }: IBlockProcessor): Promise { + await sleep(1000); + return []; + } +} diff --git a/src/processors/benchmark/BlockLiveness.ts b/src/processors/benchmark/BlockLiveness.ts new file mode 100644 index 00000000..794b0c27 --- /dev/null +++ b/src/processors/benchmark/BlockLiveness.ts @@ -0,0 +1,47 @@ +import { ISubEvent } from '../../types/IEvent'; +import { BlockProcessor, IBlockProcessor, Rule } from '../../utils/processor'; +import { IAlertRule } from '../../types/IAlertRule'; + +interface IParameters { + blockInterval: number; +} + +@Rule({ + type: 'BlockLiveness', + label: 'Block Liveness', + description: 'Triggers an event notification for Solana', + parameters: [ + { + label: 'Block Interval', + description: 'Block Interval', + field: 'blockInterval', + fieldType: 'Number', + }, + ], + networks: ['solana'], + tags: ['security'], + severity: 'low', +}) +export class BlockLivenessProcessor extends BlockProcessor { + async callback({ + rule, + block, + }: IBlockProcessor): Promise { + const interval = rule.parameters.blockInterval; + const height = block.height; + const txCount = block.transactions?.length || 0; + + if (height % interval === 0) { + return [ + { + caption: `Triggered event notification for rule ${rule.id} at block ${height}`, + details: { + message: `Triggered event notification for rule ${rule.id} at block ${height} with ${txCount} transactions`, + }, + }, + ]; + } + + return []; + } +} diff --git a/src/processors/benchmark/EmptyRule.ts b/src/processors/benchmark/EmptyRule.ts new file mode 100644 index 00000000..ae673985 --- /dev/null +++ b/src/processors/benchmark/EmptyRule.ts @@ -0,0 +1,17 @@ +import { ISubEvent } from '../../types/IEvent'; +import { BlockProcessor, IBlockProcessor, Rule } from '../../utils/processor'; + +@Rule({ + type: 'EmptyRule', + label: 'Empty Rule', + description: 'Empty rule for benchmarking', + parameters: [], + networks: ['solana'], + tags: ['account'], + severity: 'low', +}) +export class EmptyRuleProcessor extends BlockProcessor { + async callback({ rule, block }: IBlockProcessor): Promise { + return []; + } +} diff --git a/src/processors/benchmark/EmptyRuleTick.ts b/src/processors/benchmark/EmptyRuleTick.ts new file mode 100644 index 00000000..539dabaf --- /dev/null +++ b/src/processors/benchmark/EmptyRuleTick.ts @@ -0,0 +1,17 @@ +import { ISubEvent } from '../../types/IEvent'; +import { TickProcessor, ITickProcessor, Rule } from '../../utils/processor'; + +@Rule({ + type: 'EmptyRuleTick', + label: 'Empty Rule Tick', + description: 'Empty tick rule for benchmarking', + parameters: [], + networks: ['solana'], + tags: ['account'], + severity: 'low', +}) +export class EmptyRuleTickProcessor extends TickProcessor { + async callback({ rule, timestamp }: ITickProcessor): Promise { + return []; + } +} diff --git a/src/processors/benchmark/Hang.ts b/src/processors/benchmark/Hang.ts new file mode 100644 index 00000000..e9adedde --- /dev/null +++ b/src/processors/benchmark/Hang.ts @@ -0,0 +1,19 @@ +import { sleep } from '../../utils/basic'; +import { ISubEvent } from '../../types/IEvent'; +import { BlockProcessor, IBlockProcessor, Rule } from '../../utils/processor'; + +@Rule({ + type: 'Hang', + label: 'Hang', + description: 'Hang rule for benchmarking', + parameters: [], + networks: ['solana', 'osmosis-1'], + tags: ['account'], + severity: 'low', +}) +export class HangProcessor extends BlockProcessor { + async callback({ rule, block }: IBlockProcessor): Promise { + await sleep(999999999); + return []; + } +} diff --git a/src/processors/benchmark/HangTick.ts b/src/processors/benchmark/HangTick.ts new file mode 100644 index 00000000..586e6c3d --- /dev/null +++ b/src/processors/benchmark/HangTick.ts @@ -0,0 +1,19 @@ +import { sleep } from '../../utils/basic'; +import { ISubEvent } from '../../types/IEvent'; +import { TickProcessor, ITickProcessor, Rule } from '../../utils/processor'; + +@Rule({ + type: 'HangTick', + label: 'Hang Tick', + description: 'Hang tick rule for benchmarking - will timeout', + parameters: [], + networks: ['solana'], + tags: ['account'], + severity: 'low', +}) +export class HangTickProcessor extends TickProcessor { + async callback({ rule, timestamp }: ITickProcessor): Promise { + await sleep(999999999); + return []; + } +} diff --git a/src/processors/benchmark/PercBasedBenchmark.ts b/src/processors/benchmark/PercBasedBenchmark.ts new file mode 100644 index 00000000..c556938f --- /dev/null +++ b/src/processors/benchmark/PercBasedBenchmark.ts @@ -0,0 +1,41 @@ +import { sleep } from '../../utils/basic'; +import { ISubEvent } from '../../types/IEvent'; +import { BlockProcessor, IBlockProcessor, Rule } from '../../utils/processor'; + +@Rule({ + type: 'PercBasedBenchmark', + label: 'Percentage Based Benchmark', + description: + 'This rule is used to test the performance of the system. It will return a random event with a percentage chance of being triggered.', + parameters: [ + { + field: 'perc', + label: 'Percentage', + fieldType: 'Number', + description: 'Percentage chance of triggering an event', + }, + ], + networks: ['solana', 'osmosis-1'], + tags: ['account'], + severity: 'low', +}) +export class PercBasedBenchmarkProcessor extends BlockProcessor { + async callback({ rule, block }: IBlockProcessor): Promise { + const perc = rule.parameters.perc; + const randomValue = Math.random() * 100; + await sleep(randomValue / 10); + + if (randomValue < perc) { + return [ + { + caption: 'Benchmark Event', + details: { + message: `Random event triggered (${perc}% chance)`, + }, + }, + ]; + } + + return []; + } +} diff --git a/src/processors/benchmark/ThrowError.ts b/src/processors/benchmark/ThrowError.ts new file mode 100644 index 00000000..5eb92763 --- /dev/null +++ b/src/processors/benchmark/ThrowError.ts @@ -0,0 +1,17 @@ +import { ISubEvent } from '../../types/IEvent'; +import { BlockProcessor, IBlockProcessor, Rule } from '../../utils/processor'; + +@Rule({ + type: 'ThrowError', + label: 'Throw Error', + description: 'Throw error rule for benchmarking', + parameters: [], + networks: ['solana'], + tags: ['account'], + severity: 'low', +}) +export class ThrowErrorProcessor extends BlockProcessor { + async callback({ rule, block }: IBlockProcessor): Promise { + throw new Error('Throw error rule'); + } +} diff --git a/src/processors/benchmark/ThrowErrorTick.ts b/src/processors/benchmark/ThrowErrorTick.ts new file mode 100644 index 00000000..dc28e32f --- /dev/null +++ b/src/processors/benchmark/ThrowErrorTick.ts @@ -0,0 +1,17 @@ +import { ISubEvent } from '../../types/IEvent'; +import { TickProcessor, ITickProcessor, Rule } from '../../utils/processor'; + +@Rule({ + type: 'ThrowErrorTick', + label: 'Throw Error Tick', + description: 'Throw error tick rule for benchmarking', + parameters: [], + networks: ['solana'], + tags: ['account'], + severity: 'low', +}) +export class ThrowErrorTickProcessor extends TickProcessor { + async callback({ rule, timestamp }: ITickProcessor): Promise { + throw new Error('Throw error tick rule'); + } +} diff --git a/src/processors/benchmark/TickLiveness.ts b/src/processors/benchmark/TickLiveness.ts new file mode 100644 index 00000000..26f6b847 --- /dev/null +++ b/src/processors/benchmark/TickLiveness.ts @@ -0,0 +1,46 @@ +import { sleep } from '../../utils/basic'; +import { ISubEvent } from '../../types/IEvent'; +import { + IBlockProcessor, + ITickProcessor, + Rule, + TickProcessor, +} from '../../utils/processor'; + +@Rule({ + type: 'TickLiveness', + label: 'Tick Liveness', + description: 'Tick liveness rule for testing', + parameters: [ + { + field: 'perc', + label: 'Percentage', + fieldType: 'Number', + description: 'Percentage chance of triggering an event', + }, + ], + networks: ['solana', 'osmosis-1'], + tags: ['account'], + severity: 'low', +}) +export class TickLivenessProcessor extends TickProcessor { + async callback({ rule, timestamp }: ITickProcessor): Promise { + const perc = rule.parameters.perc; + const randomValue = Math.random() * 100; + await sleep(randomValue); + + if (randomValue < perc) { + throw new Error('catch me if you can: 1902'); + } + + await sleep(randomValue / 10); + return [ + { + caption: `Tick Event`, + details: { + message: 'Hello', + }, + }, + ]; + } +} diff --git a/src/processors/index.ts b/src/processors/index.ts new file mode 100644 index 00000000..74d9ffff --- /dev/null +++ b/src/processors/index.ts @@ -0,0 +1,71 @@ +import 'reflect-metadata'; +import { ITask } from '../types/ITask'; +import { IEvent, ISubEvent } from '../types/IEvent'; +import { ProcessorRegistry } from '../utils/processor'; +import { createHash } from 'crypto'; +import { initAssetService } from '../services/AssetManager'; +import { SolanaBlockWrapper } from '../wrappers/solana-block-wrapper'; + +function createUniqueUuidFromEvent(event: any) { + const hash = createHash('md5').update(JSON.stringify(event)).digest('hex'); + const uuid = `${hash.slice(0, 8)}-${hash.slice(8, 12)}-${hash.slice(12, 16)}-${hash.slice(16, 20)}-${hash.slice(20, 32)}`; + return uuid; +} + +function mapToEvent(subEvent: ISubEvent, task: ITask): IEvent { + const rule = task.alertRule; + const event = { + ...subEvent, + workspaceId: rule.workspaceId || null, + alertRuleId: rule.id, + time: (task.blockInfo?.time || task.tickInfo?.time)!, + blockNumber: String(task.blockInfo?.height || 0), + network: rule.network, + txHash: subEvent.txHash || '', + addressesInvolved: subEvent.addressesInvolved || [], + severity: subEvent.severity || rule.severity || 'medium', + resolved: false, + }; + return { + id: createUniqueUuidFromEvent(event), + ...event, + }; +} + +export async function processTask(task: ITask): Promise { + await initAssetService(); + const rule = task.alertRule; + const processorInfo = ProcessorRegistry.get(rule.ruleType); + + if (!processorInfo) { + throw new Error(`Unknown rule type: ${rule.ruleType}`); + } + + if (task.blockInfo) { + const sharedArray = new Uint8Array( + task.sharedBuffer!, + 0, + task.sharedBufferLength + ); + const block = task.flatBuffer + ? new SolanaBlockWrapper(sharedArray) + : JSON.parse(new TextDecoder().decode(sharedArray)); + const subEvents = await processorInfo.instance.callback({ + rule, + block, + timestamp: null as any, + }); + return subEvents.map((subEvent) => mapToEvent(subEvent, task)); + } + + if (task.tickInfo) { + const subEvents = await processorInfo.instance.callback({ + rule, + timestamp: task.tickInfo.time, + block: null, + }); + return subEvents.map((subEvent) => mapToEvent(subEvent, task)); + } + + throw new Error('Invalid task type'); +} diff --git a/src/processors/processors.ts b/src/processors/processors.ts new file mode 100644 index 00000000..98d8fd13 --- /dev/null +++ b/src/processors/processors.ts @@ -0,0 +1,7 @@ +export { BlockLivenessProcessor } from './benchmark/BlockLiveness'; +export { AsyncCallProcessor } from './benchmark/AsyncCall'; +export { PercBasedBenchmarkProcessor } from './benchmark/PercBasedBenchmark'; +export { TickLivenessProcessor } from './benchmark/TickLiveness'; +export { EmptyRuleProcessor } from './benchmark/EmptyRule'; +export { ThrowErrorProcessor } from './benchmark/ThrowError'; +export { HangProcessor } from './benchmark/Hang'; diff --git a/src/processors/taskProcessor.ts b/src/processors/taskProcessor.ts new file mode 100644 index 00000000..9809fee5 --- /dev/null +++ b/src/processors/taskProcessor.ts @@ -0,0 +1,279 @@ +import { runTask } from '../threadpool/pool'; +import { IStat, ITask } from '../types/ITask'; +import { IAlertRule } from '../types/IAlertRule'; +import { + createSolanaBlockFromJson, + SolanaBlockWrapper, +} from '../wrappers/solana-block-wrapper'; + +/** + * Size-bucketed buffer pool for improved reuse rate. + * Uses pre-defined size buckets to avoid O(n) searches and reduce GC pressure. + */ +class BufferPool { + private pools = new Map(); + private readonly BUCKET_SIZES = [ + 1 * 1024 * 1024, // 1MB + 5 * 1024 * 1024, // 5MB + 10 * 1024 * 1024, // 10MB + 50 * 1024 * 1024, // 50MB + ]; + private readonly MAX_PER_BUCKET = 20; + + // Stats for monitoring reuse rate + private hits = 0; + private misses = 0; + + private getBucketSize(size: number): number { + for (const bucketSize of this.BUCKET_SIZES) { + if (size <= bucketSize) return bucketSize; + } + // For very large buffers, return exact size (won't be pooled) + return size; + } + + getBuffer(size: number): SharedArrayBuffer { + const bucketSize = this.getBucketSize(size); + + // Get or create pool for this bucket + if (!this.pools.has(bucketSize)) { + this.pools.set(bucketSize, []); + } + + const pool = this.pools.get(bucketSize)!; + + if (pool.length > 0) { + this.hits++; + return pool.pop()!; + } + + this.misses++; + return new SharedArrayBuffer(bucketSize); + } + + returnBuffer(buffer: SharedArrayBuffer): void { + const bucketSize = this.getBucketSize(buffer.byteLength); + + // Don't pool oversized buffers + if (bucketSize > this.BUCKET_SIZES[this.BUCKET_SIZES.length - 1]) { + return; + } + + if (!this.pools.has(bucketSize)) { + this.pools.set(bucketSize, []); + } + + const pool = this.pools.get(bucketSize)!; + if (pool.length < this.MAX_PER_BUCKET) { + pool.push(buffer); + } + // Excess buffers are allowed to be garbage collected + } + + // Get reuse rate for monitoring + getReuseRate(): number { + const total = this.hits + this.misses; + return total > 0 ? this.hits / total : 0; + } + + // Get full stats for monitoring + getStats(): IBufferPoolStats { + let totalPooled = 0; + const bucketStats: { size_mb: number; count: number }[] = []; + + for (const [size, pool] of this.pools.entries()) { + totalPooled += pool.length; + bucketStats.push({ + size_mb: Math.round(size / 1024 / 1024), + count: pool.length, + }); + } + + return { + hits: this.hits, + misses: this.misses, + reuse_rate: Math.round(this.getReuseRate() * 100), + total_pooled: totalPooled, + buckets: bucketStats, + }; + } + + // Clean up pool periodically (trim to half capacity) + cleanup(): void { + for (const pool of this.pools.values()) { + const targetSize = Math.floor(this.MAX_PER_BUCKET / 2); + if (pool.length > targetSize) { + pool.splice(0, pool.length - targetSize); + } + } + } +} + +export interface IBufferPoolStats { + hits: number; + misses: number; + reuse_rate: number; + total_pooled: number; + buckets: { size_mb: number; count: number }[]; +} + +const bufferPool = new BufferPool(); + +// Export function to get buffer pool stats +export function getBufferPoolStats(): IBufferPoolStats { + return bufferPool.getStats(); +} + +// Cleanup interval to prevent pool growth — started by initBufferPoolCleanup() +let bufferPoolCleanupHandle: ReturnType | null = null; + +export function initBufferPoolCleanup() { + if (!bufferPoolCleanupHandle) { + bufferPoolCleanupHandle = setInterval(() => { + bufferPool.cleanup(); + }, 30000); + } +} + +export function stopBufferPoolCleanup() { + if (bufferPoolCleanupHandle) { + clearInterval(bufferPoolCleanupHandle); + bufferPoolCleanupHandle = null; + } +} + +/** + * Extract block metadata (height, timestamp, network) from any block format. + * Solana blocks have top-level height/timestamp. + * EVM blocks store them as hex inside block.block.result. + * Cosmos blocks have top-level height/timestamp. + */ +export function extractBlockMeta(blockData: any): { + height: string; + timestamp: string; + network: string; +} { + // Normalized blocks (Solana, Cosmos, or pre-normalized EVM) + if (blockData.height !== undefined && blockData.network !== undefined) { + return { + height: String(blockData.height), + timestamp: String(blockData.timestamp || ''), + network: String(blockData.network), + }; + } + + // Fallback: un-normalized EVM (outside runner context, e.g. tests/benchmarks) + if (blockData.block?.result?.number) { + const result = blockData.block.result; + return { + height: String(parseInt(result.number, 16)), + timestamp: result.timestamp + ? new Date(parseInt(result.timestamp, 16) * 1000).toISOString() + : 'undefined', + network: String(blockData.network || blockData.chain_id || ''), + }; + } + + return { + height: String(blockData.height || 0), + timestamp: String(blockData.timestamp), + network: String(blockData.network || ''), + }; +} + +export async function processPayload( + taskData: + | { + blockData: any; + ruleList: IAlertRule[]; + processorsFile?: string; + } + | { + time: string; + ruleList: IAlertRule[]; + processorsFile?: string; + } +): Promise { + const tasks: ITask[] = []; + + if ('blockData' in taskData) { + // Process block + const { blockData, ruleList } = taskData; + if (!taskData.processorsFile) { + throw new Error( + 'processorsFile is required — pass the path to your processors barrel file via startRunner({ processors: "..." })' + ); + } + const resolvedProcessorsFile = taskData.processorsFile; + + // Pre-encoded binary: use directly (already FlatBuffer bytes) + const isPreEncoded = blockData instanceof Uint8Array; + const meta = isPreEncoded + ? (() => { + const w = new SolanaBlockWrapper(blockData); + return { + height: String(w.height), + network: w.network, + timestamp: String(w.timestamp), + }; + })() + : extractBlockMeta(blockData); + + // Solana: encode as FlatBuffer for zero-copy worker reads + // Others: fall back to JSON encoding until migrated + const isSolana = isPreEncoded || meta.network === 'solana'; + const encoded = isPreEncoded + ? blockData + : isSolana + ? createSolanaBlockFromJson(blockData) + : new TextEncoder().encode(JSON.stringify(blockData)); + + const sharedBuffer = bufferPool.getBuffer(encoded.length); + new Uint8Array(sharedBuffer, 0, encoded.length).set(encoded); + + tasks.push( + ...ruleList.map((rule) => ({ + alertRule: rule, + blockInfo: { + height: meta.height, + network: meta.network, + time: meta.timestamp, + }, + sharedBuffer, + sharedBufferLength: encoded.length, + flatBuffer: isSolana, + processorsFile: resolvedProcessorsFile, + })) + ); + } else { + // Process tick + const { time, ruleList } = taskData; + if (!taskData.processorsFile) { + throw new Error( + 'processorsFile is required — pass the path to your processors barrel file via startRunner({ processors: "..." })' + ); + } + const resolvedProcessorsFile = taskData.processorsFile; + + tasks.push( + ...ruleList.map((rule) => ({ + alertRule: rule, + tickInfo: { + time, + }, + processorsFile: resolvedProcessorsFile, + })) + ); + } + + const results = await Promise.allSettled(tasks.map((task) => runTask(task))); + + // Return buffer to pool after processing (only for block processing) + if ('blockData' in taskData && tasks.length > 0 && tasks[0].sharedBuffer) { + bufferPool.returnBuffer(tasks[0].sharedBuffer); + } + + return results + .filter((result) => result.status === 'fulfilled') + .map((result) => result.value); +} diff --git a/src/scripts/benchmark-runtime.ts b/src/scripts/benchmark-runtime.ts new file mode 100644 index 00000000..9571355e --- /dev/null +++ b/src/scripts/benchmark-runtime.ts @@ -0,0 +1,338 @@ +/** + * Runtime Benchmark: Node.js vs Bun + * + * Compares processing 1000 blocks with 50 rules (45 healthy, 5 unhealthy) + * Skips tick processing. + * + * Usage: + * Node.js: node dist/scripts/benchmark-runtime.js + * Bun: bun dist/scripts/benchmark-runtime.js + */ + +import { config } from 'dotenv'; +config({ quiet: true }); + +import { join } from 'path'; +import { readFileSync } from 'fs'; +import { + processPayload, + getBufferPoolStats, +} from '../processors/taskProcessor'; +import { initPool, closePool, getPoolStats } from '../threadpool/pool'; +import { registerTaskResult, getStatsSummary } from '../services/stats-service'; +import { IAlertRule } from '../types/IAlertRule'; + +// Detect runtime (avoid TypeScript errors for Bun global) +const globalAny = globalThis as any; +const runtime = globalAny.Bun ? 'bun' : 'node'; +const runtimeVersion = globalAny.Bun?.version || process.version; + +interface BenchmarkResult { + runtime: string; + version: string; + total_blocks: number; + total_rules: number; + healthy_rules: number; + unhealthy_rules: number; + total_tasks: number; + total_time_ms: number; + avg_block_time_ms: number; + blocks_per_second: number; + tasks_per_second: number; + peak_memory_mb: number; + final_memory_mb: number; + gc_runs: number; + events_emitted: number; +} + +// Generate rules: 90% healthy + 10% unhealthy +function generateRules(totalRules: number = 50): IAlertRule[] { + const rules: IAlertRule[] = []; + + const healthyCount = Math.floor(totalRules * 0.9); + const unhealthyCount = totalRules - healthyCount; + + // 80% of healthy rules are EmptyRule (fast, no events) + const emptyRuleCount = Math.floor(healthyCount * 0.89); + // 10% of healthy rules emit events (PercBasedBenchmark) + const percRuleCount = healthyCount - emptyRuleCount; + + // Use 'benchmark' network to load processors-benchmark.js (no external deps) + const network: any = 'solana'; + + // Healthy rules (EmptyRule - fast, no events) + for (let i = 0; i < emptyRuleCount; i++) { + rules.push({ + id: `healthy-empty-${i}`, + ruleType: 'EmptyRule', + ruleGroupId: 'benchmark', + workspaceId: 'benchmark', + network, + parameters: {}, + triggerMode: 'BLOCK', + createdAt: new Date().toISOString(), + } as IAlertRule); + } + + // Healthy rules that emit events (PercBasedBenchmark with 100% event rate) + for (let i = 0; i < percRuleCount; i++) { + rules.push({ + id: `healthy-perc-${i}`, + ruleType: 'PercBasedBenchmark', + ruleGroupId: 'benchmark', + workspaceId: 'benchmark', + network, + parameters: { perc: 100 }, + triggerMode: 'BLOCK', + createdAt: new Date().toISOString(), + } as IAlertRule); + } + + // Unhealthy rules (60% Hang - will timeout, 40% ThrowError - will fail) + const hangCount = Math.floor(unhealthyCount * 0.6); + const errorCount = unhealthyCount - hangCount; + + for (let i = 0; i < hangCount; i++) { + rules.push({ + id: `unhealthy-hang-${i}`, + ruleType: 'Hang', + ruleGroupId: 'benchmark', + workspaceId: 'benchmark', + network, + parameters: {}, + triggerMode: 'BLOCK', + createdAt: new Date().toISOString(), + } as IAlertRule); + } + + for (let i = 0; i < errorCount; i++) { + rules.push({ + id: `unhealthy-error-${i}`, + ruleType: 'ThrowError', + ruleGroupId: 'benchmark', + workspaceId: 'benchmark', + network, + parameters: {}, + triggerMode: 'BLOCK', + createdAt: new Date().toISOString(), + } as IAlertRule); + } + + return rules; +} + +// Load a sample block +function loadSampleBlock(): any { + // When running from dist/scripts/, test_data is at ../test_data/ + const distTestDataPath = join( + __dirname, + '../test_data/solana/348694694.json' + ); + + try { + const block = JSON.parse(readFileSync(distTestDataPath, 'utf8')); + // Add required fields for processing + // Use 'benchmark' network to load processors-benchmark.js (avoids missing deps) + block.network = 'benchmark'; + block.height = block.blockHeight || 348694694; + block.timestamp = block.blockTime + ? new Date(block.blockTime * 1000).toISOString() + : new Date().toISOString(); + return block; + } catch (e) { + console.log('Failed to load block:', e.message); + // Fallback: create minimal mock block + return { + network: 'solana', + height: 348694694, + timestamp: new Date().toISOString(), + transactions: [], + }; + } +} + +function formatMemory(bytes: number): number { + return Math.round((bytes / 1024 / 1024) * 100) / 100; +} + +async function runBenchmark(): Promise { + const BLOCK_COUNT = parseInt(process.env.BENCH_BLOCKS || '1000', 10); + const RULE_COUNT = parseInt(process.env.BENCH_RULES || '50', 10); + const THREAD_COUNT = parseInt(process.env.BENCH_THREADS || '10', 10); + + console.log(`\n${'='.repeat(60)}`); + console.log(`Runtime Benchmark: ${runtime} ${runtimeVersion}`); + console.log( + `Config: ${BLOCK_COUNT} blocks, ${RULE_COUNT} rules, ${THREAD_COUNT} threads` + ); + console.log(`${'='.repeat(60)}\n`); + + // Initialize pool + console.log(`Initializing thread pool with ${THREAD_COUNT} threads...`); + await initPool({ + filename: join(__dirname, '../threadpool/worker.js'), + maxThreads: THREAD_COUNT, + concurrentTasksPerWorker: 1, + idleTimeout: 15_000, + closeTimeout: 3_000, + }); + + // Generate rules + const rules = generateRules(RULE_COUNT); + // Filter to only healthy rules for actual processing (unhealthy will be blocked after first timeout) + const healthyRules = rules.filter( + (r) => !r.ruleType.includes('Hang') && !r.ruleType.includes('ThrowError') + ); + + console.log(`Total rules: ${rules.length}`); + console.log(` Healthy: ${healthyRules.length}`); + console.log(` Unhealthy: ${rules.length - healthyRules.length}`); + + // Load sample block + const sampleBlock = loadSampleBlock(); + console.log( + `\nLoaded sample block: ${sampleBlock.network}:${sampleBlock.height}` + ); + console.log(`Block size: ~${JSON.stringify(sampleBlock).length} bytes`); + + // Track memory + let peakMemory = 0; + let gcRuns = 0; + const memoryInterval = setInterval(() => { + const mem = process.memoryUsage(); + if (mem.rss > peakMemory) peakMemory = mem.rss; + }, 100); + + // Run benchmark + console.log(`\nProcessing ${BLOCK_COUNT} blocks...`); + const startTime = Date.now(); + let totalEvents = 0; + let blocksProcessed = 0; + + // Process blocks - use all rules including unhealthy ones + // The unhealthy ones will timeout/fail but that's part of the benchmark + for (let i = 0; i < BLOCK_COUNT; i++) { + const blockData = { + ...sampleBlock, + height: sampleBlock.height + i, + timestamp: new Date().toISOString(), + }; + + // Use healthy rules after first few blocks to avoid timeout delays + // For first 10 blocks, include unhealthy rules to test timeout handling + const rulesForBlock = i < 10 ? rules : healthyRules; + + const results = await processPayload({ + blockData, + ruleList: rulesForBlock, + }); + + // Register results + results.forEach(registerTaskResult); + + // Count events + const events = results.reduce((sum, r) => sum + r.eventCount, 0); + totalEvents += events; + blocksProcessed++; + + // Progress update every 100 blocks + if ((i + 1) % 100 === 0) { + const elapsed = Date.now() - startTime; + const rate = Math.round((blocksProcessed / elapsed) * 1000); + const mem = formatMemory(process.memoryUsage().rss); + console.log( + ` ${blocksProcessed}/${BLOCK_COUNT} blocks | ${rate} blocks/s | ${mem}MB RSS` + ); + + // Force GC if available + if (global.gc) { + global.gc(); + gcRuns++; + } + } + } + + const endTime = Date.now(); + const totalTime = endTime - startTime; + + clearInterval(memoryInterval); + + // Final stats + const finalMemory = process.memoryUsage(); + const poolStats = getPoolStats(); + const bufferStats = getBufferPoolStats(); + const statsSummary = getStatsSummary(); + + // Calculate metrics + const unhealthyRulesCount = rules.length - healthyRules.length; + const totalTasks = + blocksProcessed * healthyRules.length + 10 * unhealthyRulesCount; // healthy tasks + first 10 blocks with unhealthy + const avgBlockTime = totalTime / blocksProcessed; + const blocksPerSecond = (blocksProcessed / totalTime) * 1000; + const tasksPerSecond = (totalTasks / totalTime) * 1000; + + const result: BenchmarkResult = { + runtime, + version: runtimeVersion, + total_blocks: blocksProcessed, + total_rules: rules.length, + healthy_rules: healthyRules.length, + unhealthy_rules: rules.length - healthyRules.length, + total_tasks: totalTasks, + total_time_ms: totalTime, + avg_block_time_ms: Math.round(avgBlockTime * 100) / 100, + blocks_per_second: Math.round(blocksPerSecond * 100) / 100, + tasks_per_second: Math.round(tasksPerSecond * 100) / 100, + peak_memory_mb: formatMemory(peakMemory), + final_memory_mb: formatMemory(finalMemory.rss), + gc_runs: gcRuns, + events_emitted: totalEvents, + }; + + // Print results + console.log(`\n${'='.repeat(60)}`); + console.log('BENCHMARK RESULTS'); + console.log(`${'='.repeat(60)}`); + console.log(`Runtime: ${result.runtime} ${result.version}`); + console.log(`Total Time: ${result.total_time_ms}ms`); + console.log(`Blocks Processed: ${result.total_blocks}`); + console.log(`Tasks Executed: ${result.total_tasks}`); + console.log(`Events Emitted: ${result.events_emitted}`); + console.log(`Avg Block Time: ${result.avg_block_time_ms}ms`); + console.log(`Blocks/Second: ${result.blocks_per_second}`); + console.log(`Tasks/Second: ${result.tasks_per_second}`); + console.log(`Peak Memory: ${result.peak_memory_mb}MB`); + console.log(`Final Memory: ${result.final_memory_mb}MB`); + console.log(`GC Runs: ${result.gc_runs}`); + console.log(`${'='.repeat(60)}`); + + // Pool stats + console.log('\nThread Pool Stats:'); + console.log(` Completed Tasks: ${poolStats.completed_tasks}`); + console.log(` Queue Size: ${poolStats.queue_size}`); + console.log(` Utilization: ${poolStats.utilization}%`); + + // Buffer pool stats + console.log('\nBuffer Pool Stats:'); + console.log(` Reuse Rate: ${bufferStats.reuse_rate}%`); + console.log(` Hits/Misses: ${bufferStats.hits}/${bufferStats.misses}`); + + // Cleanup + console.log('\nCleaning up...'); + await closePool(); + + return result; +} + +// Main +runBenchmark() + .then((result) => { + // Output JSON for comparison script + console.log('\n--- JSON RESULT ---'); + console.log(JSON.stringify(result, null, 2)); + process.exit(0); + }) + .catch((error) => { + console.error('Benchmark failed:', error); + process.exit(1); + }); diff --git a/src/scripts/benchmark.sh b/src/scripts/benchmark.sh new file mode 100644 index 00000000..6e7708be --- /dev/null +++ b/src/scripts/benchmark.sh @@ -0,0 +1,9 @@ +yarn +yarn build + +# Run with different rule counts (r) and thread counts (t) +for r in 1000 2000 3000 4000 5000; do + for t in 5 10 20 30 40; do + yarn start -r $r -t $t + done +done \ No newline at end of file diff --git a/src/scripts/generate-network-processors.ts b/src/scripts/generate-network-processors.ts new file mode 100644 index 00000000..00261175 --- /dev/null +++ b/src/scripts/generate-network-processors.ts @@ -0,0 +1,211 @@ +import { + readdirSync, + readFileSync, + writeFileSync, + mkdirSync, + existsSync, +} from 'fs'; +import { join } from 'path'; + +interface ProcessorInfo { + className: string; + filePath: string; + networks: string[]; + importPath: string; +} + +function resolveNetworkConstant( + constantName: string, + srcDir: string +): string[] { + const docHelperPath = join(srcDir, 'utils/doc-helper.ts'); + if (!existsSync(docHelperPath)) { + return []; + } + + const docHelperContent = readFileSync(docHelperPath, 'utf8'); + // Match: export const CONSTANT_NAME: INetwork[] = ['network1', 'network2', ...]; + const constantMatch = docHelperContent.match( + new RegExp( + `export const ${constantName}:\\s*INetwork\\[\\]\\s*=\\s*\\[([^\\]]+)\\]`, + 's' + ) + ); + + if (!constantMatch) { + // Try to match constants that reference other constants (e.g., DISTRIBUTION_NETWORKS = COSMOS_NETWORKS) + const refMatch = docHelperContent.match( + new RegExp( + `export const ${constantName}:\\s*INetwork\\[\\]\\s*=\\s*(\\w+)`, + 's' + ) + ); + if (refMatch) { + // Recursively resolve the referenced constant + return resolveNetworkConstant(refMatch[1], srcDir); + } + return []; + } + + const networksStr = constantMatch[1]; + return networksStr + .split(',') + .map((n) => n.trim().replace(/['"]/g, '')) + .filter((n) => n.length > 0); +} + +function extractProcessorInfo( + filePath: string, + relativePath: string, + srcDir: string +): ProcessorInfo | null { + const content = readFileSync(filePath, 'utf8'); + + // Extract class name from export statement + // Match classes that extend BlockProcessor, TickProcessor, OnBlockHelper, or OnTickHelper + const classMatch = content.match( + /export class (\w+) extends (BlockProcessor|TickProcessor|OnBlockHelper|OnTickHelper)/ + ); + if (!classMatch) return null; + + const className = classMatch[1]; + + // Extract networks from @Rule decorator - handle both array literals and constant references + // First try to match array literal: networks: ['network1', 'network2'] + const ruleMatch = content.match( + /@Rule(?:<[^>]+>)?\s*\(\s*\{[\s\S]*?networks:\s*\[([^\]]+)\]/ + ); + + let networks: string[] = []; + + if (ruleMatch) { + // Found array literal + const networksStr = ruleMatch[1]; + networks = networksStr + .split(',') + .map((n) => n.trim().replace(/['"]/g, '')) + .filter((n) => n.length > 0); + } else { + // Try to match constant reference: networks: COSMOS_NETWORKS + const constantMatch = content.match( + /@Rule(?:<[^>]+>)?\s*\(\s*\{[\s\S]*?networks:\s*(\w+)/ + ); + if (constantMatch) { + const constantName = constantMatch[1]; + networks = resolveNetworkConstant(constantName, srcDir); + } + } + + if (networks.length === 0) return null; + + // Convert file path to import path (remove .ts extension and adjust for dist) + // Since the generated file is in dist/processors/, we need to remove the 'processors/' prefix + let importPath = relativePath.replace(/\.ts$/, ''); + // Remove 'processors/' prefix if present (since generated files are already in processors dir) + if (importPath.startsWith('processors/')) { + importPath = importPath.replace(/^processors\//, ''); + } + + return { + className, + filePath, + networks, + importPath, + }; +} + +function findProcessorFiles( + dir: string, + baseDir: string, + processors: ProcessorInfo[] = [] +): ProcessorInfo[] { + const files = readdirSync(dir, { withFileTypes: true }); + + for (const file of files) { + const fullPath = join(dir, file.name); + + if (file.isDirectory()) { + // Skip node_modules and other non-processor directories + if (!['node_modules', 'dist'].includes(file.name)) { + findProcessorFiles(fullPath, baseDir, processors); + } + } else if ( + file.name.endsWith('.ts') && + !file.name.includes('.spec.') && + file.name !== 'processors.ts' && + file.name !== 'taskProcessor.ts' + ) { + const relativePath = fullPath.replace(baseDir + '/', ''); + const info = extractProcessorInfo(fullPath, relativePath, baseDir); + if (info) { + processors.push(info); + } + } + } + + return processors; +} + +function generateNetworkProcessorFile( + network: string, + processors: ProcessorInfo[] +): string { + const exports = processors + .map((p) => { + // ES modules require .js extension in import paths + return `export { ${p.className} } from './${p.importPath}.js';`; + }) + .join('\n'); + + return exports + '\n'; +} + +function main() { + // Read from src, write to dist + const projectRoot = join(__dirname, '../..'); + const srcDir = join(projectRoot, 'src'); + const processorsDir = join(srcDir, 'processors'); + const distProcessorsDir = join(projectRoot, 'dist', 'processors'); + + console.log('Scanning for processors in:', processorsDir); + + // Find all processor files + const allProcessors = findProcessorFiles(processorsDir, srcDir); + + console.log(`Found ${allProcessors.length} processors`); + + // Group processors by network + const processorsByNetwork = new Map(); + + for (const processor of allProcessors) { + for (const network of processor.networks) { + if (!processorsByNetwork.has(network)) { + processorsByNetwork.set(network, []); + } + processorsByNetwork.get(network)!.push(processor); + } + } + + console.log( + `Found networks: ${Array.from(processorsByNetwork.keys()).join(', ')}` + ); + + // Ensure dist/processors directory exists + if (!existsSync(distProcessorsDir)) { + mkdirSync(distProcessorsDir, { recursive: true }); + } + + // Generate a processor file for each network + for (const [network, processors] of processorsByNetwork.entries()) { + const fileName = `processors-${network}.js`; + const filePath = join(distProcessorsDir, fileName); + const content = generateNetworkProcessorFile(network, processors); + + writeFileSync(filePath, content, 'utf8'); + console.log(`Generated ${fileName} with ${processors.length} processors`); + } + + console.log('Network-specific processor files generated successfully!'); +} + +main(); diff --git a/src/scripts/monitor.ts b/src/scripts/monitor.ts new file mode 100644 index 00000000..a34a5ee0 --- /dev/null +++ b/src/scripts/monitor.ts @@ -0,0 +1,502 @@ +import { config } from 'dotenv'; +config({ quiet: true }); + +import axios from 'axios'; +import * as fs from 'fs'; +import * as path from 'path'; + +// ============================================================================= +// Configuration +// ============================================================================= + +const RUNNERS: { name: string; port: number }[] = [ + { name: 'solana', port: 3100 }, + { name: 'arb1', port: 3101 }, + { name: 'bnb', port: 3102 }, + { name: 'eth', port: 3103 }, + { name: 'pol', port: 3104 }, +]; + +const POLL_INTERVAL_MS = 30_000; +const STARTUP_DELAY_MS = 60_000; +const HOURLY_SUMMARY_INTERVAL_MS = 3_600_000; +const CACHE_DIR = path.join(process.cwd(), '.logs'); +const SLACK_WEBHOOK_URL = process.env.SLACK_WEBHOOK_URL!; + +const http = axios.create({ timeout: 10_000 }); + +// ============================================================================= +// Types +// ============================================================================= + +interface MonitorState { + ruleIds: string[]; + ruleHealth: Record; + ruleErrors: Record; + overallHealth: string; + runnerReachable: boolean; + lastUpdated: string; +} + +interface RuleDetail { + alert_rule_id: string; + trigger_mode: 'BLOCK' | 'TICK'; + status: 'healthy' | 'blocked'; + last_3_errors: string[]; + block_total_tasks?: number; + block_total_tasks_completed?: number; + block_average_processing_time?: number; + block_total_events_emitted?: number; + tick_total_tasks?: number; + tick_total_tasks_completed?: number; + tick_average_processing_time?: number; + tick_total_events_emitted?: number; +} + +interface StatsSummary { + block: { + total_blocks_processed?: number; + total_tasks: number; + total_tasks_completed: number; + total_events_emitted: number; + average_processing_time: number; + success_rate: number; + }; + tick: { + total_ticks_processed?: number; + total_tasks: number; + total_tasks_completed: number; + total_events_emitted: number; + average_processing_time: number; + success_rate: number; + }; + total_rules_available: number; + total_healthy_rules: number; + total_blocked_rules: number; + total_events_emitted: number; + memory: { + rss_mb: number; + heap_used_mb: number; + heap_total_mb: number; + }; + uptime: { + started_at: string; + uptime_seconds: number; + uptime_human: string; + }; + details: RuleDetail[]; +} + +interface HealthResponse { + status: 'healthy' | 'unhealthy'; + last_block_received_at?: string; + last_tick_received_at?: string; +} + +interface LagResponse { + block_lag_seconds: number; + tick_lag_seconds: number; + last_block_height: number | null; + is_caught_up: boolean; +} + +// ============================================================================= +// State (per runner) +// ============================================================================= + +const states: Record = {}; +const firstPoll: Record = {}; +const lastHourlyTotals: Record = {}; + +function initState(name: string): MonitorState { + return { + ruleIds: [], + ruleHealth: {}, + ruleErrors: {}, + overallHealth: 'unknown', + runnerReachable: true, + lastUpdated: new Date().toISOString(), + }; +} + +function cachePath(name: string): string { + return path.join(CACHE_DIR, `monitor-cache-${name}.json`); +} + +// ============================================================================= +// Cache (file-based persistence) +// ============================================================================= + +function loadCache(name: string): MonitorState | null { + try { + const fp = cachePath(name); + if (fs.existsSync(fp)) { + const raw = fs.readFileSync(fp, 'utf8'); + const cached = JSON.parse(raw) as MonitorState; + log( + `[${name}] Loaded cached state: ${cached.ruleIds.length} rules, health=${cached.overallHealth}` + ); + return cached; + } + } catch (err) { + log(`[${name}] Failed to load cache: ${err}`); + } + return null; +} + +function saveCache(name: string) { + try { + if (!fs.existsSync(CACHE_DIR)) fs.mkdirSync(CACHE_DIR, { recursive: true }); + fs.writeFileSync(cachePath(name), JSON.stringify(states[name], null, 2)); + } catch (err) { + log(`[${name}] Failed to save cache: ${err}`); + } +} + +// ============================================================================= +// Logging +// ============================================================================= + +function log(msg: string) { + const ts = new Date().toISOString(); + console.log(`${ts} | monitor | ${msg}`); +} + +// ============================================================================= +// Slack +// ============================================================================= + +async function sendSlack(text: string) { + try { + await http.post(SLACK_WEBHOOK_URL, { text }); + } catch (err: any) { + log(`Slack send failed: ${err.message || err}`); + } +} + +// ============================================================================= +// Polling (per runner) +// ============================================================================= + +async function fetchEndpoint( + baseUrl: string, + endpoint: string +): Promise { + try { + const res = await http.get(`${baseUrl}${endpoint}`); + return res.data; + } catch { + return null; + } +} + +async function pollRunner(runner: { name: string; port: number }) { + const { name, port } = runner; + const baseUrl = `http://127.0.0.1:${port}`; + const state = states[name]; + + const stats = await fetchEndpoint(baseUrl, '/stats'); + const health = await fetchEndpoint(baseUrl, '/health'); + const lag = await fetchEndpoint(baseUrl, '/stats/lag'); + + // Runner unreachable + if (!stats || !health) { + if (state.runnerReachable) { + state.runnerReachable = false; + saveCache(name); + await sendSlack( + `:red_circle: *[${name}] Runner Unreachable*\n` + + `Could not reach \`${baseUrl}\`.\n` + + `Last known state: ${state.overallHealth}, ${state.ruleIds.length} rules` + ); + } + return; + } + + // Runner recovered from unreachable + if (!state.runnerReachable) { + state.runnerReachable = true; + await sendSlack( + `:large_green_circle: *[${name}] Runner Recovered*\n` + + `Runner is reachable again. Uptime: ${stats.uptime.uptime_human}` + ); + } + + // Build current snapshot + const currentRuleIds = stats.details.map((d) => d.alert_rule_id); + const currentHealth: Record = {}; + const currentErrors: Record = {}; + for (const d of stats.details) { + currentHealth[d.alert_rule_id] = d.status; + currentErrors[d.alert_rule_id] = d.last_3_errors || []; + } + + const alerts: string[] = []; + + // --- Detect rule changes --- + + const prevSet = new Set(state.ruleIds); + const currSet = new Set(currentRuleIds); + + // New rules + const added = currentRuleIds.filter((id) => !prevSet.has(id)); + for (const id of added) { + const detail = stats.details.find((d) => d.alert_rule_id === id); + alerts.push( + `:new: *[${name}] New Rule:* \`${id}\` (${detail?.trigger_mode || '?'})` + ); + } + + // Deleted rules + const removed = state.ruleIds.filter((id) => !currSet.has(id)); + for (const id of removed) { + alerts.push(`:wastebasket: *[${name}] Rule Deleted:* \`${id}\``); + } + + // --- Detect health transitions --- + + for (const id of currentRuleIds) { + const prev = state.ruleHealth[id]; + const curr = currentHealth[id]; + + if (prev && prev !== curr) { + if (curr === 'blocked') { + const errors = currentErrors[id]; + const errorText = + errors.length > 0 + ? `\nRecent errors:\n${errors.map((e) => `> ${e}`).join('\n')}` + : ''; + alerts.push( + `:red_circle: *[${name}] Rule Unhealthy:* \`${id}\`${errorText}` + ); + } else if (curr === 'healthy') { + alerts.push( + `:large_green_circle: *[${name}] Rule Recovered:* \`${id}\`` + ); + } + } + } + + // --- New errors on rules (not seen in previous poll) --- + + for (const id of currentRuleIds) { + const prevErrors = new Set(state.ruleErrors[id] || []); + const currErrors = currentErrors[id] || []; + const newErrors = currErrors.filter((e) => !prevErrors.has(e)); + + if (newErrors.length > 0 && state.ruleHealth[id] === currentHealth[id]) { + alerts.push( + `:warning: *[${name}] New errors on* \`${id}\`:\n${newErrors.map((e) => `> ${e}`).join('\n')}` + ); + } + } + + // --- Overall health change --- + + if ( + state.overallHealth !== 'unknown' && + state.overallHealth !== health.status + ) { + const lagText = lag + ? `Block lag: ${lag.block_lag_seconds}s, Tick lag: ${lag.tick_lag_seconds}s, Caught up: ${lag.is_caught_up ? 'yes' : 'no'}` + : 'Lag data unavailable'; + const icon = + health.status === 'healthy' ? ':large_green_circle:' : ':red_circle:'; + alerts.push( + `${icon} *[${name}] Overall Health:* ${state.overallHealth} -> ${health.status}\n${lagText}` + ); + } + + // --- Send alerts --- + + if (!firstPoll[name] && alerts.length > 0) { + await sendSlack(alerts.join('\n\n---\n\n')); + } + + if (firstPoll[name] && alerts.length > 0) { + log( + `[${name}] First poll — skipping ${alerts.length} alert(s) to avoid startup spam` + ); + } + + // --- Update state --- + + states[name] = { + ruleIds: currentRuleIds, + ruleHealth: currentHealth, + ruleErrors: currentErrors, + overallHealth: health.status, + runnerReachable: true, + lastUpdated: new Date().toISOString(), + }; + saveCache(name); + + firstPoll[name] = false; + + log( + `[${name}] Poll OK: ${health.status}, ${stats.total_healthy_rules}/${stats.total_rules_available} healthy, ` + + `mem=${stats.memory.heap_used_mb}MB, alerts=${alerts.length}` + ); +} + +async function pollAll() { + await Promise.all(RUNNERS.map((r) => pollRunner(r))); +} + +// ============================================================================= +// Hourly Summary (unified) +// ============================================================================= + +async function hourlySummary() { + const lines: string[] = []; + + for (const runner of RUNNERS) { + const { name, port } = runner; + const baseUrl = `http://127.0.0.1:${port}`; + + const stats = await fetchEndpoint(baseUrl, '/stats'); + + if (!stats) { + lines.push(`*${name}* — :red_circle: unreachable`); + continue; + } + + const state = states[name]; + const health = state?.overallHealth || 'unknown'; + const isHealthy = health === 'healthy'; + + // Compute hourly block/tick deltas + const currentBlocks = + stats.block.total_blocks_processed ?? stats.block.total_tasks; + const currentTicks = + stats.tick.total_ticks_processed ?? stats.tick.total_tasks; + const prev = lastHourlyTotals[name]; + let blocksLastHour = currentBlocks; + let ticksLastHour = currentTicks; + if (prev) { + blocksLastHour = + currentBlocks >= prev.blocks + ? currentBlocks - prev.blocks + : currentBlocks; + ticksLastHour = + currentTicks >= prev.ticks ? currentTicks - prev.ticks : currentTicks; + } + lastHourlyTotals[name] = { blocks: currentBlocks, ticks: currentTicks }; + + const blockWarn = blocksLastHour < 30 ? ' :warning:' : ''; + const tickWarn = ticksLastHour < 30 ? ' :warning:' : ''; + const throughput = ` | Blocks/hr: ${blocksLastHour}${blockWarn} | Ticks/hr: ${ticksLastHour}${tickWarn}`; + + const headline = + `*${name}* — ${isHealthy ? health : ':red_circle: ' + health}` + + ` | ${stats.total_healthy_rules}/${stats.total_rules_available} rules` + + ` | Uptime: ${stats.uptime.uptime_human}` + + ` | heap ${stats.memory.heap_used_mb}MB / RSS ${stats.memory.rss_mb}MB` + + throughput; + + if (isHealthy) { + lines.push(headline); + continue; + } + + // Unhealthy — expand with details + const detail: string[] = [headline]; + + const lag = await fetchEndpoint(baseUrl, '/stats/lag'); + const lagText = lag + ? `Lag: block ${lag.block_lag_seconds}s, tick ${lag.tick_lag_seconds}s` + : 'Lag data unavailable'; + detail.push( + ` ${lagText} | Avg block: ${stats.block.average_processing_time.toFixed(1)}ms` + ); + + const blockedRules = stats.details + .filter((d) => d.status === 'blocked') + .map((d) => d.alert_rule_id); + if (blockedRules.length > 0) { + detail.push( + ` Blocked: ${blockedRules.map((r) => `\`${r}\``).join(', ')}` + ); + } + + const allErrors: string[] = []; + for (const d of stats.details) { + if (d.last_3_errors?.length > 0) { + allErrors.push(...d.last_3_errors); + } + } + const uniqueErrors = Array.from(new Set(allErrors)); + if (uniqueErrors.length > 0) { + detail.push( + ` Errors (${uniqueErrors.length}):\n${uniqueErrors + .slice(0, 5) + .map((e) => ` > ${e}`) + .join('\n')}` + ); + } + + lines.push(detail.join('\n')); + } + + const text = `:clock1: *Hourly Summary*\n\n${lines.join('\n')}`; + + await sendSlack(text); + log('Hourly summary sent'); +} + +// ============================================================================= +// Main +// ============================================================================= + +async function main() { + log( + `Monitor starting. Runners: ${RUNNERS.map((r) => `${r.name}:${r.port}`).join(', ')}` + ); + log(`Waiting ${STARTUP_DELAY_MS / 1000}s before first poll...`); + + // Load persisted state per runner + for (const runner of RUNNERS) { + const cached = loadCache(runner.name); + if (cached) { + states[runner.name] = cached; + firstPoll[runner.name] = false; + } else { + states[runner.name] = initState(runner.name); + firstPoll[runner.name] = true; + } + } + + // Wait for runners to warm up + await new Promise((resolve) => setTimeout(resolve, STARTUP_DELAY_MS)); + + log('Starting poll loop'); + + // First poll + await pollAll(); + + // Startup summary (same format as hourly) + await hourlySummary(); + + // Poll loop + setInterval(async () => { + try { + await pollAll(); + } catch (err) { + log(`Poll error: ${err}`); + } + }, POLL_INTERVAL_MS); + + // Hourly summary + setInterval(async () => { + try { + await hourlySummary(); + } catch (err) { + log(`Hourly summary error: ${err}`); + } + }, HOURLY_SUMMARY_INTERVAL_MS); +} + +main().catch((err) => { + console.error('Monitor fatal error:', err); + process.exit(1); +}); diff --git a/src/scripts/producer.ts b/src/scripts/producer.ts new file mode 100644 index 00000000..b7896592 --- /dev/null +++ b/src/scripts/producer.ts @@ -0,0 +1,45 @@ +import { Command } from 'commander'; +import { env } from '../env'; +import { createRedisClient, publishToStream } from '../services/consumer-redis'; +import { getCachedBlock } from '../utils/testing-helpers'; +import { sleep } from '../utils/basic'; + +async function main() { + const program = new Command(); + + program + .option('-n, --network ', 'Network name', 'eth') + .option('-h, --height ', 'Block height', parseInt, 23539020) + .parse(process.argv); + + const options = program.opts(); + const network = options.network; + const startHeight = options.height; + + const block = await getCachedBlock(network, startHeight); + // Add network field to block data + block.network = network; + + const redis = await createRedisClient(); + + for (let i = 0; i < 1000; i++) { + await publishToStream({ + client: redis, + streamName: env.BLOCK_REDIS_STREAM_NAME, + payload: block, + }); + console.log(`Published ${network}:${startHeight}`); + + await publishToStream({ + client: redis, + streamName: env.TICK_REDIS_STREAM_NAME, + payload: { + time: new Date().toISOString(), + }, + }); + console.log(`Published tick: ${new Date().toISOString()}`); + await sleep(100); + } +} + +main(); diff --git a/src/sdk.ts b/src/sdk.ts deleted file mode 100644 index 15a9bba7..00000000 --- a/src/sdk.ts +++ /dev/null @@ -1,1174 +0,0 @@ -import dayjs from 'dayjs'; -import { Kafka } from 'kafkajs'; -import { IRangeBlock } from './types/chain/IRangeBlock'; -import { IRangeError, ISubEvent } from './types/IRangeEvent'; -import { IRangeAlertRule } from './types/IRangeAlertRule'; -import { - BlockRuleGroupTaskPackage, - ErrorBlockRuleTaskPackage, - TickRuleGroupTaskPackage, -} from './types/IRangeTaskPackage'; -import { fetchBlock } from './services/fetchBlock'; -import { - fetchAlertRuleByRuleGroupAndRuleID, - fetchAlertRulesByRuleGroupID, -} from './services/fetchAlertRules'; -import { errorTaskAck, taskAck } from './services/taskAck'; -import { createAlertEvents } from './services/alertEvent'; -import { - KafkaConsumerClient, - QueueHealthStats, -} from './connections/KafkaConsumer'; -import { IRangeConfig } from './types/IRangeConfig'; -import { fetchConfig } from './services/fetchConfig'; -import { getLogger } from './logger'; -import { constants } from './constants'; -import { tickTaskAck } from './services/tickTaskAck'; -import { DebugAlert, postDebugAlert } from './services/postDebugAlert'; - -const logger = getLogger({ name: 'rangeSDK' }); - -export interface OnBlock { - callback: (block: IRangeBlock, rule: IRangeAlertRule) => Promise; -} - -export interface OnTick { - callback: (timestamp: string, rule: IRangeAlertRule) => Promise; -} - -export interface RangeSDKOptions { - token: string; -} - -export interface RangeSDKInitOptions { - onBlock?: OnBlock; - onTick?: OnTick; -} - -export interface IRangeSDK { - init(initOpts: RangeSDKInitOptions): Promise; - gracefulCleanup(): Promise; -} - -export interface RuleMetrics { - type: string; - - execCount: number; - execMinTimeMS: number; - execMaxTimeMS: number; - execTotalTimeMS: number; - - alertEventCount: number; - alertEventMinTimeMS: number; - alertEventMaxTimeMS: number; - alertEventTotalTimeMS: number; -} - -export interface BlockRuleGroupProcessingMetrics { - endToEndCount: number; - endToEndMinTimeMS: number; - endToEndMaxTimeMS: number; - endToEndTotalTimeMS: number; - - fetchRulesCount: number; - fetchRulesMinTimeMS: number; - fetchRulesMaxTimeMS: number; - fetchRulesTotalTimeMS: number; - - fetchBlockCount: number; - fetchBlockMinTimeMS: number; - fetchBlockMaxTimeMS: number; - fetchBlockTotalTimeMS: number; - - individualRuleStats: Record; -} - -export interface RangeSDKHealthStats { - blockQueueHealth: QueueHealthStats; - errorQueueHealth: QueueHealthStats; - tickQueueHealth: QueueHealthStats; -} - -class RangeSDK implements IRangeSDK { - private opts: RangeSDKOptions; - private initOpts?: RangeSDKInitOptions; - private config?: IRangeConfig; - - private blockRuleGroupTaskClient?: KafkaConsumerClient; - private errorBlockRuleTaskClient?: KafkaConsumerClient; - private tickRuleGroupTaskClient?: KafkaConsumerClient; - - private rateLimitedRules: Map = new Map(); - - private readonly rulePerExecTimeCutOffMS = - constants.RULE_QUARANTINE.PER_EXEC_TIME_CUT_OFF_MS; - private readonly ruleAvgExecTimeCutOffMS = - constants.RULE_QUARANTINE.AVG_EXEC_TIME_CUT_OFF_MS; - private readonly ruleAvgExecTimeDebugAlertMS = - constants.RULE_QUARANTINE.AVG_EXEC_TIME_DEBUG_ALERT_MS; - private readonly ruleQuarantineTimeMins = - constants.RULE_QUARANTINE.QUARANTINE_TIME_MINS; - private readonly ruleDebugAlertPauseTimeMins = 15; - private execPausedRules: Map = new Map(); // key is rule id and value is exec paused till in unix - private debugAlertedRules: Map = new Map(); // key is rule id and value is alerting paused till in unix - private ruleMetricsForQuarantine: Record = {}; - private ruleQuarantineAvgWindow = 15; - - private blockRulesMetricsByRuleGroup: Map< - string, - BlockRuleGroupProcessingMetrics - > = new Map(); - - constructor(opts: RangeSDKOptions) { - this.opts = opts; - const [runnerId] = this.opts.token.split('.'); - logger.info( - `Initiating rangeSDK for runnerID: ${runnerId}, manager: ${constants.MANAGER_SERVICE.DOMAIN}`, - ); - } - - async init(initOpts: RangeSDKInitOptions): Promise { - if (!initOpts.onBlock && !initOpts.onTick) { - throw new Error( - 'At least one of the callbacks (onBlock or onTick) are required to initialise the sdk', - ); - } - - /** - * Fetch config from the manager and setup task queues - */ - this.config = await fetchConfig({ token: this.opts.token }); - this.initOpts = initOpts; - - const kafka = new Kafka(this.config.kafka); - this.blockRuleGroupTaskClient = new KafkaConsumerClient( - kafka, - this.config.kafkaGroupIds.blockRuleGroupTasks, - { - retries: 3, - }, - ); - this.errorBlockRuleTaskClient = new KafkaConsumerClient( - kafka, - this.config.kafkaGroupIds.errorsBlockRuleTasks, - { - retries: 0, - }, - ); - this.tickRuleGroupTaskClient = new KafkaConsumerClient( - kafka, - this.config.kafkaGroupIds.tickRuleGroupTasks, - { - retries: 0, - }, - ); - - await this.initBlockRuleGroupTaskQueue(); - await this.initErrorBlockRuleTaskQueue(); - await this.initTickRuleGroupTaskQueue(); - } - - static async build( - sdkOpts: RangeSDKOptions, - sdkInitOpts: RangeSDKInitOptions, - ) { - const sdk = new RangeSDK(sdkOpts); - await sdk.init(sdkInitOpts); - return sdk; - } - - private async initBlockRuleGroupTaskQueue() { - if (!this.config) { - throw new Error('SDK not initiated, config missing'); - } - if (!this.blockRuleGroupTaskClient) { - throw new Error('SDK not initiated, blockRuleGroupTaskClient missing'); - } - if (!this.initOpts) { - throw new Error('SDK init called without options'); - } - - if ( - Object.prototype.hasOwnProperty.call(this.initOpts, 'onBlock') === - false || - this.initOpts.onBlock === undefined || - this.initOpts.onBlock === null - ) { - logger.warn({ message: 'Missing handler for block based alert rules' }); - this.initOpts.onBlock = { - callback: async (block, rule) => { - logger.error({ - message: `Missing handler for block based alert rules. Block: network: ${block.network}, height: ${block.height}, Rule: type: ${rule.ruleType}, id: ${rule.id}`, - }); - return []; - }, - }; - } - - const kafkaTopic = this.config.kafkaTopics.blockRuleGroupTasks; - const blockRuleGroupTaskQueue = - await this.blockRuleGroupTaskClient.subscribeAndConsume(kafkaTopic); - - await blockRuleGroupTaskQueue.run({ - autoCommit: true, - eachMessage: async ({ message }) => { - const rawMessage = message?.value?.toString(); - if (!rawMessage) { - logger.error(`Error decoding incoming raw message: ${rawMessage}`); - return; - } - - const parseMessage: BlockRuleGroupTaskPackage = JSON.parse(rawMessage); - await this.blockRuleGroupTaskQueueHandler(parseMessage); - }, - }); - logger.info( - `Block Rule Group Task Queue has started on topic: ${kafkaTopic}`, - ); - } - - private async blockRuleGroupTaskQueueHandler( - taskPackage: BlockRuleGroupTaskPackage, - ): Promise { - const start = Date.now(); - let rulesFetchedAt: number | null = null; - let blockFetchedAt: number | null = null; - - const [rules, block] = await Promise.all([ - fetchAlertRulesByRuleGroupID({ - token: this.opts.token, - ruleGroupId: taskPackage.ruleGroupId, - }).then((data) => { - rulesFetchedAt = Date.now(); - return data; - }), - fetchBlock({ - token: this.opts.token, - height: taskPackage.block.height, - network: taskPackage.block.network, - }) - .then((data) => { - blockFetchedAt = Date.now(); - return data; - }) - .catch((err) => { - logger.error( - err, - `Error while fetching block: network:: ${taskPackage.block.network}, height:: ${taskPackage.block.height}`, - ); - if (err?.response?.status === 404) { - return null; - } - throw err; - }), - ]); - - // call the acknowledgement API and mark the package as done if block is not found or rule group is empty - if (!block || rules.length === 0) { - logger.warn({ block, rules }, 'Early task package ack'); - await taskAck({ - token: this.opts.token, - block: taskPackage.block, - ruleGroupId: taskPackage.ruleGroupId, - runnerId: taskPackage.runnerId, - alertEventsCount: 0, - alertRulesIds: [], - }); - return; - } - - // Filter out rate limited rules - const filteredRules: IRangeAlertRule[] = []; - const rateLimitedRuleIds: string[] = []; - const execPausedRuleIds: string[] = []; - for (const rule of rules) { - if ( - this.rateLimitedRules.has(rule.id) && - dayjs - .unix(this.rateLimitedRules.get(rule.id) as number) - .isAfter(dayjs()) - ) { - logger.info( - { - ruleID: rule.id, - currentTime: dayjs().unix(), - rateLimitedTill: this.rateLimitedRules.get(rule.id), - }, - `rule processing skipped as it is rate limited.`, - ); - // Skip the rule - rateLimitedRuleIds.push(rule.id); - continue; - } - filteredRules.push(rule); - } - - // Filter out execution paused rules - for (let i = filteredRules.length - 1; i > -1; i -= 1) { - const rule = filteredRules[i]; - if ( - this.execPausedRules.has(rule.id) && - dayjs.unix(this.execPausedRules.get(rule.id) as number).isAfter(dayjs()) - ) { - logger.info( - { - ruleID: rule.id, - currentTime: dayjs().unix(), - execPausedTill: this.execPausedRules.get(rule.id), - }, - `rule processing skipped as it's execution is paused.`, - ); - // skip the rule - execPausedRuleIds.push(...filteredRules.splice(i, 1).map((r) => r.id)); - } - } - - if (!filteredRules.length) { - logger.warn( - { - rules, - rateLimitedRules: Object.fromEntries(this.rateLimitedRules), - execPausedRules: Array.from(this.execPausedRules), - }, - 'Early task package ack due to all rules getting filtered out by rate limiting or execution paused', - ); - await taskAck({ - token: this.opts.token, - block: taskPackage.block, - ruleGroupId: taskPackage.ruleGroupId, - runnerId: taskPackage.runnerId, - alertEventsCount: 0, - alertRulesIds: [], - rateLimitedAlertRuleIds: rateLimitedRuleIds, - execPausedAlertRuleIds: execPausedRuleIds, - }); - return; - } - - const { errors, alertEventsCount, ruleStats } = await this.processBlockTask( - block, - rules, - ); - await taskAck({ - token: this.opts.token, - block: taskPackage.block, - ruleGroupId: taskPackage.ruleGroupId, - runnerId: taskPackage.runnerId, - alertEventsCount, - alertRulesIds: rules.map((r) => r.id), - ...(errors?.length - ? { - errors, - } - : {}), - rateLimitedAlertRuleIds: rateLimitedRuleIds, - execPausedAlertRuleIds: execPausedRuleIds, - }); - - try { - if (rulesFetchedAt && blockFetchedAt) { - this.setMetricStats( - taskPackage.ruleGroupId, - start, - { rulesFetchedAt, blockFetchedAt }, - ruleStats, - ); - } - this.setMetricStatsForRuleQuarantine(ruleStats); - } catch (err) { - logger.error(err, `Error while setting metrics`); - } - - try { - // Check for rules to quarantine on their avg time exec - const debugAlerts: DebugAlert[] = []; - for (const ruleId of Object.keys(this.ruleMetricsForQuarantine)) { - const ruleStats = this.ruleMetricsForQuarantine[ruleId]; - const avgExecTime = Math.floor( - ruleStats.execTotalTimeMS / ruleStats.execCount, - ); - - const now = dayjs(); - let ruleQuarantined = false; - if (avgExecTime >= this.ruleAvgExecTimeCutOffMS) { - this.execPausedRules.set( - ruleId, - now.add(this.ruleQuarantineTimeMins, 'minutes').unix(), - ); - ruleQuarantined = true; - - logger.info( - { - ruleId, - ruleStats, - quarantinedTill: this.execPausedRules.get(ruleId), - }, - 'Rule quarantined due to avg execution time exceeding cutoff time', - ); - } - - if ( - avgExecTime >= this.ruleAvgExecTimeDebugAlertMS && - (!this.debugAlertedRules.has(ruleId) || - (this.debugAlertedRules.has(ruleId) && - now.isAfter( - dayjs.unix(this.debugAlertedRules.get(ruleId) as number), - ))) - ) { - this.debugAlertedRules.set( - ruleId, - now.add(this.ruleDebugAlertPauseTimeMins, 'minutes').unix(), - ); - - debugAlerts.push({ - runnerId: taskPackage.runnerId, - alert: { - msg: 'Rule avg execution exceeding than expected', - avgExecTime, - debugAlertState: { - ruleAvgExecTimeDebugAlertMS: this.ruleAvgExecTimeDebugAlertMS, - alertCreatedAt: now, - alertsPausedTill: this.debugAlertedRules.get(ruleId), - }, - ruleQuarantineState: { - isQuarantined: this.execPausedRules.has(ruleId), - ruleAvgExecTimeCutOffMS: this.ruleAvgExecTimeCutOffMS, - ...(this.execPausedRules.has(ruleId) - ? { - quarantinedAt: now, - quarantinedTill: this.execPausedRules.get(ruleId), - } - : {}), - }, - stats: JSON.parse(JSON.stringify(ruleStats)), - }, - blockNetwork: taskPackage.block.network, - blockHeight: taskPackage.block.height, - ruleGroupId: taskPackage.ruleGroupId, - ruleId, - }); - } - - // Reset the stats so that it's a fresh start after jailing period - if (ruleQuarantined) { - delete this.ruleMetricsForQuarantine[ruleId]; - } - // Window average check - else if (ruleStats.execCount >= this.ruleQuarantineAvgWindow) { - delete this.ruleMetricsForQuarantine[ruleId]; - } - } - - // no await so that we can move on to next task, however errors are handles so it should not affect other processing - if (debugAlerts.length) { - postDebugAlert({ - token: this.opts.token, - ping: true, - debugAlerts, - }).catch((err) => { - logger.error(err, 'error while posting debug alerts'); - }); - } - } catch (err) { - logger.error(err, 'error while rule avg exec checks'); - } - } - - private async initErrorBlockRuleTaskQueue() { - if (!this.config) { - throw new Error('SDK not initiated, config missing'); - } - if (!this.errorBlockRuleTaskClient) { - throw new Error('SDK not initiated, errorBlockRuleTaskClient missing'); - } - - const kafkaTopic = this.config.kafkaTopics.errorsBlockRuleTasks; - const errorBlockRuleTaskQueue = - await this.errorBlockRuleTaskClient.subscribeAndConsume(kafkaTopic); - await errorBlockRuleTaskQueue.run({ - autoCommit: true, - eachMessage: async ({ message }) => { - const rawMessage = message?.value?.toString(); - if (!rawMessage) { - logger.error(`Error decoding incoming raw message: ${rawMessage}`); - return; - } - - const parseMessage: ErrorBlockRuleTaskPackage = JSON.parse(rawMessage); - await this.errorBlockRuleTaskQueueHandler(parseMessage); - }, - }); - logger.info( - `Error Block Rule Task Queue has started on topic: ${kafkaTopic}`, - ); - } - - private async errorBlockRuleTaskQueueHandler( - taskPackage: ErrorBlockRuleTaskPackage, - ) { - const [rule, block] = await Promise.all([ - fetchAlertRuleByRuleGroupAndRuleID({ - token: this.opts.token, - ruleGroupId: taskPackage.ruleGroupId, - ruleId: taskPackage.ruleId, - }), - fetchBlock({ - token: this.opts.token, - height: taskPackage.blockNumber, - network: taskPackage.network, - }).catch((err) => { - logger.error( - err, - `Error while fetching block: network:: ${taskPackage.network}, height:: ${taskPackage.blockNumber}`, - ); - if (err?.response?.status === 404) { - return null; - } - throw err; - }), - ]); - - // call the error task acknowledgement API and mark the error task as non retry-able - if (!block || !rule) { - const e = !block - ? `Block Not Found: network: ${taskPackage.network}, height: ${taskPackage.blockNumber}` - : `Rule Not Found: id: ${taskPackage.ruleId}`; - await errorTaskAck({ - token: this.opts.token, - errorId: taskPackage.errorId, - error: e, - retry: false, - }); - return; - } - - const { errors } = await this.processBlockTask(block, [rule]); - await errorTaskAck({ - token: this.opts.token, - errorId: taskPackage.errorId, - ...(errors.length - ? { - error: errors[0].error, - retry: true, - } - : { - retry: false, - }), - }); - } - - private async processBlockTask( - block: IRangeBlock, - rules: IRangeAlertRule[], - ): Promise<{ - errors: IRangeError[]; - alertEventsCount: number; - ruleStats: BlockRuleGroupProcessingMetrics['individualRuleStats']; - }> { - const ruleStats: Record> = rules.reduce( - (map, r) => { - map[r.id] = {}; - return map; - }, - {} as Record>, - ); - - const events = await Promise.all( - rules.map( - async ( - rule, - ): Promise<{ - errors: IRangeError[]; - alertEventsCount: number; - rateLimitedStatus: { - ruleID: string; - isRateLimited: boolean; - retryAfterUnixSec: number; - }; - }> => { - const rateLimitedStatus: { - ruleID: string; - isRateLimited: boolean; - retryAfterUnixSec: number; - } = { - ruleID: rule.id, - isRateLimited: false, - retryAfterUnixSec: 0, - }; - const start = Date.now(); - let execAt: number | undefined = undefined; - - try { - const blockTimestamp = dayjs(block.timestamp); - if ( - !( - (blockTimestamp.isAfter(rule.createdAt) || - blockTimestamp.isSame(rule.createdAt)) && - blockTimestamp.isBefore( - rule.deletedAt || '2100-01-01T00:00:00.000', - ) - ) - ) { - logger.warn( - { - block: { - network: block.network, - height: block.height, - timestamp: block.timestamp, - }, - rule: rule, - condition: { - blockYoungerOrSameThanRuleCreation: - blockTimestamp.isAfter(rule.createdAt) || - blockTimestamp.isSame(rule.createdAt), - blockOlderThanRuleDeletedAt: blockTimestamp.isBefore( - rule.deletedAt || '2100-01-01T00:00:00.000', - ), - }, - }, - `rule processing skipped as timestamp conditions fail`, - ); - - delete ruleStats[rule.id]; - return { - errors: [], - alertEventsCount: 0, - rateLimitedStatus, - }; - } - - const ruleSubResults = await this.execOnBlockPerRule(block, rule); - const ruleResults = ruleSubResults.map((subResult) => ({ - ...subResult, - workspaceId: rule.workspaceId || null, - alertRuleId: rule.id, - time: block.timestamp, - blockNumber: String(block.height), - network: block.network, - txHash: subResult.txHash || '', - addressesInvolved: subResult.addressesInvolved || [], - severity: subResult.severity || rule.severity || 'medium', - })); - - execAt = Date.now(); - ruleStats[rule.id].type = rule.ruleType; - ruleStats[rule.id].execMinTimeMS = execAt - start; - ruleStats[rule.id].execMaxTimeMS = execAt - start; - ruleStats[rule.id].execCount = 1; - ruleStats[rule.id].execTotalTimeMS = execAt - start; - - if (!ruleResults.length) { - return { - errors: [], - alertEventsCount: 0, - rateLimitedStatus, - }; - } - - const alertApiResp = await createAlertEvents({ - token: this.opts.token, - workspaceId: rule.workspaceId || null, - alertRuleId: rule.id, - ruleGroupId: rule.ruleGroupId, - alerts: ruleResults, - }); - - const alertCreatedAt = Date.now(); - ruleStats[rule.id].alertEventMinTimeMS = alertCreatedAt - start; - ruleStats[rule.id].alertEventMaxTimeMS = alertCreatedAt - start; - ruleStats[rule.id].alertEventCount = 1; - ruleStats[rule.id].alertEventTotalTimeMS = alertCreatedAt - start; - - if (!alertApiResp.success) { - rateLimitedStatus.isRateLimited = true; - rateLimitedStatus.retryAfterUnixSec = - alertApiResp.retryAfterUnixSec; - } - - return { - errors: [], - alertEventsCount: ruleResults.length, - rateLimitedStatus, - }; - } catch (error) { - logger.error(error); - - let err = String(error); - if (error instanceof Error) { - err = error.message + error.stack ? `\n${error.stack}` : ''; - } - - // Set metrics so that timed out processes can be jailed - if (!execAt) { - execAt = Date.now(); - ruleStats[rule.id].type = rule.ruleType; - ruleStats[rule.id].execMinTimeMS = execAt - start; - ruleStats[rule.id].execMaxTimeMS = execAt - start; - ruleStats[rule.id].execCount = 1; - ruleStats[rule.id].execTotalTimeMS = execAt - start; - } - - return { - errors: [ - { - ruleId: rule.id, - error: err, - }, - ], - alertEventsCount: 0, - rateLimitedStatus, - }; - } - }, - ), - ); - - // Set rate limit information - for (const event of events) { - if (event.rateLimitedStatus.isRateLimited) { - this.rateLimitedRules.set( - event.rateLimitedStatus.ruleID, - event.rateLimitedStatus.retryAfterUnixSec, - ); - } - } - - return { - errors: events.flat().flatMap((obj) => obj.errors), - alertEventsCount: events.flat().reduce((alertEventsCount, obj) => { - return obj.alertEventsCount + alertEventsCount; - }, 0), - ruleStats: - ruleStats as BlockRuleGroupProcessingMetrics['individualRuleStats'], - }; - } - - private async execOnBlockPerRule(block: IRangeBlock, rule: IRangeAlertRule) { - if (!this.initOpts) { - throw new Error('SDK Init not called, onBlock missing'); - } - if (!this.initOpts.onBlock) { - throw new Error('Missing handler for block based alert rules'); - } - - const ruleSubResults = await Promise.race([ - this.initOpts.onBlock.callback(block, rule), - new Promise((_, rej) => { - setTimeout(() => { - rej( - new Error('onBlock execution terminated due to deadline timeout'), - ); - }, this.rulePerExecTimeCutOffMS); - }), - ]); - - return (ruleSubResults || []) as ISubEvent[]; - } - - private async initTickRuleGroupTaskQueue() { - if (!this.config) { - throw new Error('SDK not initiated, config missing'); - } - if (!this.tickRuleGroupTaskClient) { - throw new Error('SDK not initiated, tickRuleGroupTaskClient missing'); - } - if (!this.initOpts) { - throw new Error('SDK init called without options'); - } - - if ( - Object.prototype.hasOwnProperty.call(this.initOpts, 'onTick') === false || - this.initOpts.onTick === undefined || - this.initOpts.onTick === null - ) { - logger.warn({ message: 'Missing handler for tick based alert rules' }); - this.initOpts.onTick = { - callback: async (timestamp, rule) => { - logger.error({ - message: `Missing handler for tick based alert rules. Timestamp: ${timestamp}, Rule: type: ${rule.ruleType}, id: ${rule.id}`, - }); - return []; - }, - }; - } - - const kafkaTopic = this.config.kafkaTopics.tickRuleGroupTasks; - const tickRuleGroupTaskClient = - await this.tickRuleGroupTaskClient.subscribeAndConsume(kafkaTopic); - - await tickRuleGroupTaskClient.run({ - autoCommit: true, - eachMessage: async ({ message }) => { - const rawMessage = message?.value?.toString(); - if (!rawMessage) { - logger.error(`Error decoding incoming raw message: ${rawMessage}`); - return; - } - - const parseMessage: TickRuleGroupTaskPackage = JSON.parse(rawMessage); - await this.tickRuleGroupTaskQueueHandler(parseMessage); - }, - }); - logger.info( - `Tick Rule Group Task Queue has started on topic: ${kafkaTopic}`, - ); - } - - private async tickRuleGroupTaskQueueHandler( - taskPackage: TickRuleGroupTaskPackage, - ): Promise { - const rules = await fetchAlertRulesByRuleGroupID({ - token: this.opts.token, - ruleGroupId: taskPackage.ruleGroupId, - }); - - // call the acknowledgement API and mark the package as done if rule group is empty - if (rules.length === 0) { - logger.warn({ rules }, 'Early task package ack'); - await tickTaskAck({ - token: this.opts.token, - timestamp: taskPackage.timestamp, - ruleGroupId: taskPackage.ruleGroupId, - runnerId: taskPackage.runnerId, - alertEventsCount: 0, - }); - return; - } - - const { errors, alertEventsCount } = await this.processTickTask( - taskPackage.timestamp, - rules, - ); - await tickTaskAck({ - token: this.opts.token, - timestamp: taskPackage.timestamp, - ruleGroupId: taskPackage.ruleGroupId, - runnerId: taskPackage.runnerId, - alertEventsCount, - ...(errors?.length - ? { - errors, - } - : {}), - }); - } - - private async processTickTask( - timestamp: string, - rules: IRangeAlertRule[], - ): Promise<{ - errors: IRangeError[]; - alertEventsCount: number; - }> { - const events = await Promise.all( - rules.map( - async ( - rule, - ): Promise<{ errors: IRangeError[]; alertEventsCount: number }> => { - try { - if (!this.initOpts) { - throw new Error('SDK Init not called, onBlock missing'); - } - if (!this.initOpts.onTick) { - throw new Error('Missing handler for tick based alert rules'); - } - - const ruleSubResults = - (await this.initOpts.onTick.callback(timestamp, rule)) || []; - const ruleResults = ruleSubResults.map((subResult) => ({ - ...subResult, - workspaceId: rule.workspaceId || null, - alertRuleId: rule.id, - time: timestamp, - network: rule.network, - txHash: subResult.txHash || '', - addressesInvolved: subResult.addressesInvolved || [], - severity: subResult.severity || rule.severity || 'medium', - })); - - if (!ruleResults.length) { - return { errors: [], alertEventsCount: 0 }; - } - - await createAlertEvents({ - token: this.opts.token, - workspaceId: rule.workspaceId || null, - alertRuleId: rule.id, - ruleGroupId: rule.ruleGroupId, - alerts: ruleResults, - }); - - return { errors: [], alertEventsCount: ruleResults.length }; - } catch (error) { - let err = String(error); - if (error instanceof Error) { - err = error.message + error.stack ? `\n${error.stack}` : ''; - } - - return { - errors: [ - { - ruleId: rule.id, - error: err, - }, - ], - alertEventsCount: 0, - }; - } - }, - ), - ); - - return { - errors: events.flat().flatMap((obj) => obj.errors), - alertEventsCount: events.flat().reduce((alertEventsCount, obj) => { - return obj.alertEventsCount + alertEventsCount; - }, 0), - }; - } - - private setMetricStats( - ruleGroupId: string, - start: number, - initialStats: { - rulesFetchedAt: number; - blockFetchedAt: number; - }, - ruleStats: Record, - ) { - const { rulesFetchedAt, blockFetchedAt } = initialStats; - const end = Date.now(); - const endToEnd = end - start; - - const stats = { - fetchRulesCount: 1, - fetchRulesMinTimeMS: rulesFetchedAt - start, - fetchRulesMaxTimeMS: rulesFetchedAt - start, - fetchRulesTotalTimeMS: rulesFetchedAt - start, - - fetchBlockCount: 1, - fetchBlockMinTimeMS: blockFetchedAt - start, - fetchBlockMaxTimeMS: blockFetchedAt - start, - fetchBlockTotalTimeMS: blockFetchedAt - start, - - endToEndCount: 1, - endToEndMaxTimeMS: endToEnd, - endToEndMinTimeMS: endToEnd, - endToEndTotalTimeMS: endToEnd, - - individualRuleStats: ruleStats, - }; - - const currentStats = this.blockRulesMetricsByRuleGroup.get(ruleGroupId); - if (!currentStats) { - this.blockRulesMetricsByRuleGroup.set( - ruleGroupId, - stats as BlockRuleGroupProcessingMetrics, - ); - return; - } - - const newStats: BlockRuleGroupProcessingMetrics = JSON.parse( - JSON.stringify(currentStats), - ); - newStats.fetchRulesCount += stats.fetchRulesCount || 1; - if (newStats.fetchRulesMinTimeMS > (stats.fetchRulesMinTimeMS || 0)) { - newStats.fetchRulesMinTimeMS = stats.fetchRulesMinTimeMS || 0; - } - if (newStats.fetchRulesMaxTimeMS < (stats.fetchRulesMaxTimeMS || 0)) { - newStats.fetchRulesMaxTimeMS = stats.fetchRulesMaxTimeMS || 0; - } - newStats.fetchRulesTotalTimeMS += stats.fetchRulesTotalTimeMS || 0; - - newStats.fetchBlockCount += stats.fetchBlockCount || 1; - if ( - stats.fetchBlockMinTimeMS && - newStats.fetchBlockMinTimeMS > stats.fetchBlockMinTimeMS - ) { - newStats.fetchBlockMinTimeMS = stats.fetchBlockMinTimeMS; - } - if (newStats.fetchBlockMaxTimeMS < (stats.fetchBlockMaxTimeMS || 0)) { - newStats.fetchBlockMaxTimeMS = stats.fetchBlockMaxTimeMS || 0; - } - newStats.fetchBlockTotalTimeMS += stats.fetchBlockTotalTimeMS || 0; - - newStats.endToEndCount += stats.endToEndCount || 1; - if ( - stats.endToEndMinTimeMS && - newStats.endToEndMinTimeMS < stats.endToEndMinTimeMS - ) { - newStats.endToEndMinTimeMS = stats.endToEndMinTimeMS; - } - if (newStats.endToEndMaxTimeMS < (stats.endToEndMaxTimeMS || 0)) { - newStats.endToEndMaxTimeMS = stats.endToEndMaxTimeMS || 0; - } - newStats.endToEndTotalTimeMS += stats.endToEndTotalTimeMS || 0; - - // handle individual rule stats - for (const ruleID of Object.keys(ruleStats)) { - const existingRuleStats = newStats.individualRuleStats[ruleID]; - if (!existingRuleStats) { - newStats.individualRuleStats[ruleID] = ruleStats[ruleID]; - continue; - } - - const newRuleStats: RuleMetrics = JSON.parse( - JSON.stringify(existingRuleStats), - ); - - newRuleStats.execCount += ruleStats[ruleID].execCount; - if (newRuleStats.execMinTimeMS > ruleStats[ruleID].execMinTimeMS) { - newRuleStats.execMinTimeMS = ruleStats[ruleID].execMinTimeMS; - } - if (newRuleStats.execMaxTimeMS < ruleStats[ruleID].execMaxTimeMS) { - newRuleStats.execMaxTimeMS = ruleStats[ruleID].execMaxTimeMS; - } - newRuleStats.execTotalTimeMS += ruleStats[ruleID].execTotalTimeMS; - - if (ruleStats[ruleID].alertEventCount) { - newRuleStats.alertEventCount += ruleStats[ruleID].alertEventCount; - if ( - newRuleStats.alertEventMinTimeMS > - ruleStats[ruleID].alertEventMinTimeMS - ) { - newRuleStats.alertEventMinTimeMS = - ruleStats[ruleID].alertEventMinTimeMS; - } - if ( - newRuleStats.alertEventMaxTimeMS < - ruleStats[ruleID].alertEventMaxTimeMS - ) { - newRuleStats.alertEventMaxTimeMS = - ruleStats[ruleID].alertEventMaxTimeMS; - } - newRuleStats.alertEventTotalTimeMS += - ruleStats[ruleID].alertEventTotalTimeMS; - } - - newStats.individualRuleStats[ruleID] = newRuleStats; - } - - this.blockRulesMetricsByRuleGroup.set(ruleGroupId, newStats); - } - - private setMetricStatsForRuleQuarantine( - ruleStats: Record, - ) { - if (!Object.keys(this.ruleMetricsForQuarantine).length) { - this.ruleMetricsForQuarantine = JSON.parse(JSON.stringify(ruleStats)); - return; - } - - const newStats: Record = JSON.parse( - JSON.stringify(this.ruleMetricsForQuarantine), - ); - for (const ruleID of Object.keys(ruleStats)) { - const existingRuleStats = newStats[ruleID]; - if (!existingRuleStats) { - newStats[ruleID] = ruleStats[ruleID]; - continue; - } - - const newRuleStats: RuleMetrics = JSON.parse( - JSON.stringify(existingRuleStats), - ); - - newRuleStats.execCount += ruleStats[ruleID].execCount; - if (newRuleStats.execMinTimeMS > ruleStats[ruleID].execMinTimeMS) { - newRuleStats.execMinTimeMS = ruleStats[ruleID].execMinTimeMS; - } - if (newRuleStats.execMaxTimeMS < ruleStats[ruleID].execMaxTimeMS) { - newRuleStats.execMaxTimeMS = ruleStats[ruleID].execMaxTimeMS; - } - newRuleStats.execTotalTimeMS += ruleStats[ruleID].execTotalTimeMS; - - if (ruleStats[ruleID].alertEventCount) { - newRuleStats.alertEventCount += ruleStats[ruleID].alertEventCount; - if ( - newRuleStats.alertEventMinTimeMS > - ruleStats[ruleID].alertEventMinTimeMS - ) { - newRuleStats.alertEventMinTimeMS = - ruleStats[ruleID].alertEventMinTimeMS; - } - if ( - newRuleStats.alertEventMaxTimeMS < - ruleStats[ruleID].alertEventMaxTimeMS - ) { - newRuleStats.alertEventMaxTimeMS = - ruleStats[ruleID].alertEventMaxTimeMS; - } - newRuleStats.alertEventTotalTimeMS += - ruleStats[ruleID].alertEventTotalTimeMS; - } - - newStats[ruleID] = newRuleStats; - } - - this.ruleMetricsForQuarantine = newStats; - } - - getMetricStats() { - return { - blockRulesMetrics: Object.fromEntries(this.blockRulesMetricsByRuleGroup), - rateLimitedRules: Object.fromEntries(this.rateLimitedRules), - execPausedRules: Object.fromEntries(this.execPausedRules), - debugAlertedRules: Object.fromEntries(this.debugAlertedRules), - }; - } - - async getHealthStats(): Promise { - if ( - !this.blockRuleGroupTaskClient || - !this.errorBlockRuleTaskClient || - !this.tickRuleGroupTaskClient - ) { - return { - blockQueueHealth: { - health: 0, - }, - errorQueueHealth: { - health: 0, - }, - tickQueueHealth: { - health: 0, - }, - }; - } - - const [blockQueueHealth, errorQueueHealth, tickQueueHealth] = - await Promise.all([ - this.blockRuleGroupTaskClient.health(), - this.errorBlockRuleTaskClient.health(), - this.tickRuleGroupTaskClient.health(), - ]); - - return { - blockQueueHealth, - errorQueueHealth, - tickQueueHealth, - }; - } - - async gracefulCleanup() { - logger.info('Shutting down range sdk'); - - await new Promise((res) => - setTimeout(async () => { - if (this.blockRuleGroupTaskClient) { - await this.blockRuleGroupTaskClient.gracefulShutdown(); - } - res(null); - }, 1000), - ); - - if (this.errorBlockRuleTaskClient) { - await this.errorBlockRuleTaskClient.gracefulShutdown(); - } - if (this.tickRuleGroupTaskClient) { - await this.tickRuleGroupTaskClient.gracefulShutdown(); - } - } -} - -export { RangeSDK }; diff --git a/src/services/AssetManager.ts b/src/services/AssetManager.ts new file mode 100644 index 00000000..8eaa57cd --- /dev/null +++ b/src/services/AssetManager.ts @@ -0,0 +1,1125 @@ +import * as crypto from 'crypto'; +import axios from 'axios'; +import { dayjs } from '../utils/dayjs'; + +const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'; + +// In-memory asset stats (replaces Redis-backed consumer-metrics) +const assetStats = { + findAssetInfoCalls: 0, + unknownDenoms: new Map }>(), +}; + +export function getAndResetAssetStats() { + const snapshot = { + findAssetInfoCalls: assetStats.findAssetInfoCalls, + unknownDenoms: new Map(assetStats.unknownDenoms), + }; + assetStats.findAssetInfoCalls = 0; + assetStats.unknownDenoms.clear(); + return snapshot; +} + +const COINGECKO_START_DATE = '2023-11-13'; + +function isTestEnvironment(): boolean { + return process.env.NODE_ENV === 'test'; +} + +function findPdDenomSuffix(denom: string) { + const generalKeyIndex = denom.lastIndexOf('generalkey/'); + if (generalKeyIndex !== -1) { + return denom.substring(generalKeyIndex); + } + + const generalIndexIndex = denom.lastIndexOf('generalindex/'); + if (generalIndexIndex !== -1) { + return denom.substring(generalIndexIndex); + } + + return ''; +} + +export async function withRetry( + fn: () => Promise, + options?: { + maxRetries?: number; + delayInMs?: number; + } +): Promise { + const maxRetries = options?.maxRetries || 1; + let retryCount = 0; + + while (retryCount < maxRetries) { + try { + return await fn(); + } catch (error) { + retryCount++; + + if (retryCount === maxRetries) { + throw error; + } + + const delay = + Math.pow(2, retryCount - 1) * (options?.delayInMs || 10_000); + await new Promise((resolve) => setTimeout(resolve, delay)); + } + } + + throw new Error('Max retries reached'); +} + +export function sha256(input: unknown): string { + const str = typeof input === 'string' ? input : JSON.stringify(input); + const hash = crypto.createHash('sha256'); + hash.update(str); + return hash.digest('hex'); +} + +function isSolanaAddress(address: string): boolean { + const solanaAddressRegex = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/; + return solanaAddressRegex.test(address); +} + +function stripStellarVersion(denom: string): string | null { + const parts = denom.split('-'); + if (parts.length < 3) return null; + if (/^G[A-Z2-7]{55}$/i.test(parts[1])) { + return `${parts[0]}-${parts[1]}`; + } + return null; +} + +const ASSETS_SERVICE_V2 = 'https://assets.range.org/v2'; + +export function simplifyDenom(raw_denom: string) { + if (!raw_denom) return ''; + return raw_denom.replace(/^(transfer\/[^/]+\/)+/g, ''); +} + +export function getReverseDenom(raw_denom: string) { + if (!raw_denom) return ''; + + const pattern = /^transfer\/.+\//; + const match = raw_denom.match(pattern); + if (!match) return raw_denom; + + return raw_denom.slice(match[0].length); +} + +function checkIlliquidAtom(str: string) { + const pattern = /.*cosmosvaloper.*\/\d+$/; + return pattern.test(str); +} + +const fmtNum = (raw_num: number) => { + if (!isFinite(raw_num)) return '0'; + if (raw_num === 0) return '0'; + + const isNegative = raw_num < 0; + + const num = Math.abs(raw_num); + + let res: string; + + if (num < 10 ** -6) { + res = '~0'; + } else if (Math.abs(num) < 1_000) { + res = new Intl.NumberFormat('en-US', { + maximumFractionDigits: num >= 1 ? 2 : 6, + }).format(num); + } else if (Math.abs(num) < 1_000_000) { + res = parseFloat((num / 1000).toFixed(1)) + 'K'; + } else if (Math.abs(num) < 1_000_000_000) { + res = parseFloat((num / 1_000_000).toFixed(1)) + 'M'; + } else if (Math.abs(num) < 1_000_000_000_000) { + res = parseFloat((num / 1_000_000_000).toFixed(1)) + 'B'; + } else if (Math.abs(num) < 1_000_000_000_000_000) { + res = parseFloat((num / 1_000_000_000_000).toFixed(1)) + 'T'; + } else { + res = Number(num).toExponential(1); + } + + if (isNegative) { + res = '-' + res; + } + + return res; +}; + +Number.prototype.fmt = function () { + return fmtNum(this); +}; + +declare global { + interface Number { + fmt(): string; + } +} + +interface IAssetInfo { + name: string; + symbol: string; + denoms: { denom: string; exponent: number }[]; + cg?: string; + usd: number; + chain?: string; +} + +interface ISolanaAssetInfo { + id: string; + symbol: string | null; + name: string | null; + decimals: number; + usd: number; +} + +interface IStellarAssetInfo { + name: string; + symbol: string; + network: string; + denoms: { denom: string; exponent: number }[]; + cg?: string; + usd: number; + meta?: Record; +} + +interface INetworkInfo { + id: string; + bech32_prefix: string; + pretty_name: string; +} + +interface NetworkMapping { + bridge: string; + from: string; + to: string; +} + +class AssetManager { + // v2 + cosmos_evm_assets: IAssetInfo[] = []; + solana_assets: ISolanaAssetInfo[] = []; + stellar_assets: IStellarAssetInfo[] = []; + network_mappings: NetworkMapping[] = []; + word_to_network: Record = {}; + networks: INetworkInfo[] = []; + + assetMap = new Map(); + solanaAssetMap = new Map(); + stellarAssetMap = new Map(); + symbolMap = new Map(); + + lastInitialized; + lastPriceDate: string | null = null; + + // Unknown token reporting — dedup within process lifetime + private _reportedDenoms: Set = new Set(); + + private reportUnknownToken( + denom: string, + network?: string, + protocol?: string + ): void { + const key = `${denom}:${network || ''}:${protocol || ''}`; + if (this._reportedDenoms.has(key)) return; + this._reportedDenoms.add(key); + + axios + .post( + `${ASSETS_SERVICE_V2}/report-missing-token`, + { + token: denom, + network: network || 'unknown', + protocol: protocol || 'unknown', + reported_by: 'interchain-consumer', + }, + { timeout: 5000 } + ) + .catch(() => {}); + } + + constructor() { + if (isTestEnvironment()) { + if (this.loadFromTestCache()) { + this.lastInitialized = dayjs(); + } + } else { + setInterval(async () => { + await this.initialize(); + }, 5 * 60_000); + } + } + + async initialize() { + const now = dayjs(); + + if (this.lastInitialized && now.diff(this.lastInitialized, 'minutes') < 5) { + return; + } + + if (isTestEnvironment()) { + if (!this.lastInitialized) { + await this.fetchAndPopulate(); + this.writeTestCache(); + } + this.lastInitialized = now; + return; + } + + await this.fetchAndPopulate(); + this.lastInitialized = now; + } + + private async fetchAndPopulate() { + const fetchStart = Date.now(); + const fetches: Promise[] = []; + + if (process.env.ASSET_SERVICE_COSMOS_ENABLED === 'true') + fetches.push(this.fetchCosmosAssets()); + if (process.env.ASSET_SERVICE_NETWORKS_ENABLED === 'true') + fetches.push(this.fetchNetworks()); + if (process.env.ASSET_SERVICE_NETWORK_MAPPINGS_ENABLED === 'true') + fetches.push(this.fetchNetworkMappings()); + if (process.env.ASSET_SERVICE_WORD_TO_NETWORK_ENABLED === 'true') + fetches.push(this.fetchWordToNetwork()); + if (process.env.ASSET_SERVICE_SOLANA_ENABLED === 'true') + fetches.push(this.fetchSolanaAssets()); + if (process.env.ASSET_SERVICE_STELLAR_ENABLED === 'true') + fetches.push(this.fetchStellarAssets()); + + if (fetches.length === 0) { + console.log( + 'AssetManager: No asset fetches enabled (set ASSET_SERVICE_*_ENABLED=true)' + ); + return; + } + + const results = await Promise.allSettled(fetches); + const succeeded = results.filter( + (r) => r.status === 'fulfilled' && r.value === true + ).length; + console.log( + `AssetManager: API fetch completed in ${Date.now() - fetchStart}ms (${succeeded}/${fetches.length} succeeded)` + ); + } + + private static get testCacheDir(): string { + const path = require('path'); + return path.join(process.cwd(), '.cache', 'asset-service'); + } + + private static readonly CACHE_MAX_AGE_MS = 24 * 60 * 60 * 1000; + + private loadFromTestCache(): boolean { + const fs = require('fs'); + const path = require('path'); + const cacheDir = AssetManager.testCacheDir; + + try { + const manifestPath = path.join(cacheDir, 'manifest.json'); + if (!fs.existsSync(manifestPath)) return false; + + const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8')); + const age = Date.now() - new Date(manifest.timestamp).getTime(); + if (age > AssetManager.CACHE_MAX_AGE_MS) return false; + + this.cosmos_evm_assets = JSON.parse( + fs.readFileSync(path.join(cacheDir, 'assets.json'), 'utf8') + ); + for (let i = 0; i < this.cosmos_evm_assets.length; i++) { + for (const d of this.cosmos_evm_assets[i].denoms || []) { + this.assetMap.set(d.denom, i); + } + } + this.symbolMap = new Map( + this.cosmos_evm_assets.map((a) => [ + String(a.symbol).toLowerCase(), + a.symbol, + ]) + ); + + this.networks = JSON.parse( + fs.readFileSync(path.join(cacheDir, 'networks.json'), 'utf8') + ); + this.network_mappings = JSON.parse( + fs.readFileSync(path.join(cacheDir, 'network_mappings.json'), 'utf8') + ); + this.word_to_network = JSON.parse( + fs.readFileSync(path.join(cacheDir, 'word_to_network.json'), 'utf8') + ); + + this.solana_assets = JSON.parse( + fs.readFileSync(path.join(cacheDir, 'solana_assets.json'), 'utf8') + ); + for (let i = 0; i < this.solana_assets.length; i++) { + this.solanaAssetMap.set(this.solana_assets[i].id, i); + this.solanaAssetMap.set(this.solana_assets[i].id.toLowerCase(), i); + } + + this.stellar_assets = JSON.parse( + fs.readFileSync(path.join(cacheDir, 'stellar_assets.json'), 'utf8') + ); + for (let i = 0; i < this.stellar_assets.length; i++) { + for (const d of this.stellar_assets[i].denoms || []) { + this.stellarAssetMap.set(d.denom, i); + this.stellarAssetMap.set(d.denom.toLowerCase(), i); + } + } + + console.log( + `AssetManager: Loaded from test cache (age: ${Math.round(age / 60000)}min)` + ); + return true; + } catch { + return false; + } + } + + private writeTestCache(): void { + const fs = require('fs'); + const path = require('path'); + const cacheDir = AssetManager.testCacheDir; + + try { + fs.mkdirSync(cacheDir, { recursive: true }); + + const files: [string, any][] = [ + ['assets.json', this.cosmos_evm_assets], + ['networks.json', this.networks], + ['network_mappings.json', this.network_mappings], + ['word_to_network.json', this.word_to_network], + ['solana_assets.json', this.solana_assets], + ['stellar_assets.json', this.stellar_assets], + ]; + + for (const [filename, data] of files) { + const json = JSON.stringify(data); + const tmpPath = path.join(cacheDir, `${filename}.tmp`); + const finalPath = path.join(cacheDir, filename); + fs.writeFileSync(tmpPath, json); + fs.renameSync(tmpPath, finalPath); + } + + const manifestPath = path.join(cacheDir, 'manifest.json'); + fs.writeFileSync( + manifestPath, + JSON.stringify({ timestamp: new Date().toISOString() }) + ); + + console.log('AssetManager: Wrote test cache'); + } catch (err: any) { + console.error(`AssetManager: Failed to write test cache: ${err.message}`); + } + } + + private async fetchNetworks(): Promise { + try { + const res = await withRetry(() => + axios.get(`${ASSETS_SERVICE_V2}/networks`) + ); + this.networks = res.data; + console.log(`AssetManager: downloaded ${this.networks.length} networks`); + return true; + } catch (error: any) { + console.error( + 'AssetManager: Failed to fetch networks (using cached data):', + error?.message + ); + return false; + } + } + + private async fetchCosmosAssets(): Promise { + try { + const res = await withRetry(() => + axios.get(`${ASSETS_SERVICE_V2}/cosmos-evm-assets`) + ); + this.cosmos_evm_assets = res.data; + for (let i = 0; i < this.cosmos_evm_assets.length; i++) { + for (const d of this.cosmos_evm_assets[i].denoms || []) { + this.assetMap.set(d.denom, i); + } + } + this.symbolMap = new Map( + this.cosmos_evm_assets.map((a) => [ + String(a.symbol).toLowerCase(), + a.symbol, + ]) + ); + console.log( + `AssetManager: downloaded ${this.cosmos_evm_assets.length} cosmos-evm tokens` + ); + return true; + } catch (error: any) { + console.error( + 'AssetManager: Failed to fetch cosmos assets (using cached data):', + error?.message + ); + return false; + } + } + + private async fetchSolanaAssets(): Promise { + try { + const res = await withRetry(() => + axios.get(`${ASSETS_SERVICE_V2}/solana/popular`) + ); + console.log(`AssetManager: downloaded ${res.data.length} solana tokens`); + this.solana_assets = res.data; + for (let i = 0; i < this.solana_assets.length; i++) { + this.solanaAssetMap.set(this.solana_assets[i].id, i); + this.solanaAssetMap.set(this.solana_assets[i].id.toLowerCase(), i); + } + return true; + } catch (error: any) { + console.error( + 'AssetManager: Failed to fetch solana assets (using cached data):', + error?.message + ); + return false; + } + } + + private async fetchStellarAssets(): Promise { + try { + const res = await withRetry(() => + axios.get(`${ASSETS_SERVICE_V2}/stellar/verified`) + ); + console.log(`AssetManager: downloaded ${res.data.length} stellar tokens`); + this.stellar_assets = res.data; + this.stellarAssetMap.clear(); + for (let i = 0; i < this.stellar_assets.length; i++) { + for (const d of this.stellar_assets[i].denoms || []) { + this.stellarAssetMap.set(d.denom, i); + this.stellarAssetMap.set(d.denom.toLowerCase(), i); + } + } + return true; + } catch (error: any) { + console.error( + 'AssetManager: Failed to fetch stellar assets (using cached data):', + error?.message + ); + return false; + } + } + + private async fetchNetworkMappings(): Promise { + try { + const res = await withRetry(() => + axios.get(`${ASSETS_SERVICE_V2}/network-mappings`) + ); + this.network_mappings = res.data; + console.log( + `AssetManager: downloaded ${this.network_mappings.length} network mappings` + ); + return true; + } catch (error: any) { + console.error( + 'AssetManager: Failed to fetch network mappings (using cached data):', + error?.message + ); + return false; + } + } + + private async fetchWordToNetwork(): Promise { + try { + const res = await withRetry(() => + axios.get( + `${ASSETS_SERVICE_V2}/network-mappings/word-to-network-full-list` + ) + ); + this.word_to_network = res.data; + console.log( + `AssetManager: downloaded ${Object.keys(this.word_to_network).length} word-to-network mappings` + ); + return true; + } catch (error: any) { + console.error( + 'AssetManager: Failed to fetch word-to-network mappings (using cached data):', + error?.message + ); + return false; + } + } + + findAssetInfo( + raw_denom: string, + chains?: string[], + options?: { + skipScaling?: boolean; + sourceChannel?: string; + destinationChannel?: string; + protocol?: string; + } + ): (IAssetInfo & { preferredExponent: number }) | null { + // return null for falsy denoms + if (!raw_denom) return null; + + assetStats.findAssetInfoCalls++; + const originalDenom = String(raw_denom); + raw_denom = originalDenom.toLowerCase(); + + // solves native token issues for evm chains + if (raw_denom === ZERO_ADDRESS) { + const asset = this.findNativeEvmAsset(chains?.[0] || ''); + if (asset !== null) { + asset.usd = findAssetInfo(asset.symbol)?.usd || 0; + } + return asset; + } + + // pd general index case + if ( + raw_denom.includes('generalindex') || + raw_denom.includes('generalkey') + ) { + const generalDenom = findPdDenomSuffix(raw_denom); + const asset = this.cosmos_evm_assets.find((a) => + a.denoms.some((d) => { + return d.denom.endsWith(generalDenom); + }) + ); + if (asset) { + return { + ...asset, + preferredExponent: + asset.denoms.find((d) => { + return d.denom.endsWith(generalDenom); + })?.exponent || 0, + }; + } + } + + // adds 0x before sui denoms + if (raw_denom.includes('::') && !raw_denom.startsWith('0x')) { + raw_denom = '0x' + raw_denom; + } + + const simpleDenom = simplifyDenom(raw_denom); + + if (simpleDenom === 'uluna') { + if (chains?.includes('columbus-5')) { + const asset = this.cosmos_evm_assets.find((a) => a.symbol === 'LUNC'); + if (asset) { + return { + ...asset, + preferredExponent: 6, + }; + } + return null; + } + if (chains?.includes('phoenix-1')) { + const asset = this.cosmos_evm_assets.find((a) => a.symbol === 'LUNA'); + if (asset) { + return { + ...asset, + preferredExponent: 6, + }; + } + return null; + } + } + + // Direct check for existing IBC denoms + if (raw_denom.toLowerCase().startsWith('ibc/')) { + const index = this.assetMap.get(raw_denom.toLowerCase()); + if (index !== undefined) { + return { + ...this.cosmos_evm_assets[index], + preferredExponent: + this.cosmos_evm_assets[index].denoms.find( + (d) => d.denom === raw_denom.toLowerCase() + )?.exponent || 0, + }; + } + } + + const denomVariants = [ + { + denom: simpleDenom, + }, + { + denom: raw_denom, + }, + ]; + // Handle IBC channel routing in order: source -> reverse -> simple + if (options?.sourceChannel && options?.destinationChannel) { + denomVariants.push( + ...[ + { + denom: `ibc/${sha256(`transfer/${options.sourceChannel}/${raw_denom}`)}`, + }, + { + // ! This is wrong, but Axelar USDT is following pattern, research later + denom: `ibc/${sha256(`transfer/${options.destinationChannel}/${raw_denom}`)}`, + }, + { + denom: `ibc/${sha256(raw_denom)}`, + }, + { + denom: `ibc/${sha256(getReverseDenom(raw_denom))}`, + }, + ] + ); + } + + for (const { denom } of denomVariants) { + const index = this.assetMap.get(denom.toLowerCase()); + if (index !== undefined) { + return { + ...this.cosmos_evm_assets[index], + preferredExponent: + this.cosmos_evm_assets[index].denoms.find( + (d) => d.denom === denom.toLowerCase() + )?.exponent || 0, + }; + } + } + + // handle if denom is a potential solana mint (after assetMap lookup so Tron/Stellar addresses aren't misrouted) + if (isSolanaAddress(originalDenom) || isSolanaAddress(raw_denom)) { + const assetIndex = + this.solanaAssetMap.get(originalDenom) ?? + this.solanaAssetMap.get(raw_denom); + if (assetIndex !== undefined) { + const asset = this.solana_assets[assetIndex]; + return { + ...asset, + name: asset.name || '', + symbol: asset.symbol || '', + denoms: [{ denom: asset.id, exponent: asset.decimals || 0 }], + preferredExponent: asset.decimals || 0, + }; + } + } + + // Stellar asset lookup — check both original and lowered case + const stellarIndex = + this.stellarAssetMap.get(originalDenom) ?? + this.stellarAssetMap.get(raw_denom); + if (stellarIndex !== undefined) { + const asset = this.stellar_assets[stellarIndex]; + const matchingDenom = asset.denoms.find( + (d) => d.denom === originalDenom || d.denom.toLowerCase() === raw_denom + ); + return { + name: asset.name, + symbol: asset.symbol, + denoms: asset.denoms, + cg: asset.cg, + usd: asset.usd, + preferredExponent: matchingDenom?.exponent || 0, + }; + } + + // Stellar version-stripping fallback: CODE-ISSUER-VERSION -> CODE-ISSUER + const strippedDenom = stripStellarVersion(originalDenom); + if (strippedDenom) { + const strippedIndex = + this.stellarAssetMap.get(strippedDenom) ?? + this.stellarAssetMap.get(strippedDenom.toLowerCase()); + if (strippedIndex !== undefined) { + const asset = this.stellar_assets[strippedIndex]; + const matchingDenom = asset.denoms.find( + (d) => + d.denom === strippedDenom || + d.denom.toLowerCase() === strippedDenom.toLowerCase() + ); + return { + name: asset.name, + symbol: asset.symbol, + denoms: asset.denoms, + cg: asset.cg, + usd: asset.usd, + preferredExponent: matchingDenom?.exponent || 0, + }; + } + } + + // Handle illiquid atom + if (checkIlliquidAtom(raw_denom)) { + const atom = findAssetInfo('atom'); + return { + name: 'IATOM', + symbol: 'IATOM', + denoms: [{ denom: 'iatom', exponent: 6 }], + usd: atom?.usd || 0, + preferredExponent: 6, + }; + } + + // Symbol-based lookup as fallback + for (let i = 0; i < this.cosmos_evm_assets.length; i++) { + const asset = this.cosmos_evm_assets[i]; + if (asset.symbol.toLowerCase() === simpleDenom.toLowerCase()) { + return { + ...asset, + preferredExponent: 0, + }; + } + } + + const existing = assetStats.unknownDenoms.get(raw_denom); + if (existing) { + existing.count++; + if (options?.protocol) existing.bridges.add(options.protocol); + } else { + const bridges = new Set(); + if (options?.protocol) bridges.add(options.protocol); + assetStats.unknownDenoms.set(raw_denom, { count: 1, bridges }); + } + this.reportUnknownToken(raw_denom, chains?.[0], options?.protocol); + return null; + } + + formatAmount(am: { + amount: number | string | null | undefined; + denom?: string; + token?: string; + mint?: string; + skipScaling?: boolean; + options?: any; + chains?: string[]; + }) { + const denom = am.denom || am.token || am.mint || ''; + am.amount = Number(am.amount); + const assetInfo = this.findAssetInfo(denom, am.chains, am.options); + + if (!assetInfo) { + // Solana fallback — formatSolanaAmount has its own lookup + if (isSolanaAddress(denom)) { + return this.formatSolanaAmount({ + amount: am.amount, + mint: denom, + skipScaling: am.skipScaling, + }); + } + const symbol = simplifyDenom(denom); + const tokenUsdString = `${am.amount.fmt()} ${symbol}`; + return { + tokenAmount: am.amount, + symbol, + tokenUsdString, + usd: 0, + }; + } + + let tokenAmount = am.amount; + const exponent = assetInfo.preferredExponent || 0; + + if (!am.skipScaling) { + tokenAmount = am.amount / 10 ** exponent; + } + + const symbol = assetInfo.symbol; + const usd = tokenAmount * (assetInfo.usd || 0); + let tokenUsdString = `${tokenAmount.fmt()} ${symbol}`; + if (usd) tokenUsdString += ` ($${usd.fmt()})`; + + return { tokenAmount, symbol, tokenUsdString, usd }; + } + + findSolanaAssetInfo(mint: string) { + const p = this.solana_assets.find((e) => e.id === mint); + return p || null; + } + + findStellarAssetInfo(denom: string) { + const index = + this.stellarAssetMap.get(denom) ?? + this.stellarAssetMap.get(denom.toLowerCase()); + if (index !== undefined) { + return this.stellar_assets[index]; + } + return null; + } + + formatSolanaAmount({ + amount, + mint, + skipScaling = false, + }: { + amount: number | string; + mint: string; + skipScaling?: boolean; + }) { + amount = Number(amount); + const info = this.findSolanaAssetInfo(mint); + + if (!info) { + return { + tokenAmount: amount, + symbol: mint, + usd: 0, + tokenUsdString: `${amount.fmt()} ${mint}`, + }; + } + + let tokenAmount = amount; + if (!skipScaling) { + tokenAmount /= 10 ** info.decimals; + } + + const usd = tokenAmount * info.usd; + const symbol = info.symbol || mint; + + return { + tokenAmount, + symbol, + usd, + tokenUsdString: `${tokenAmount.fmt()} ${symbol} ($${usd.fmt()})`, + }; + } + + async setPastCoingeckoPrices(timestamp: string) { + const date = dayjs(timestamp).format('YYYY-MM-DD'); + if (this.lastPriceDate === date) return; + + const res = await withRetry(() => + axios.get(`${ASSETS_SERVICE_V2}/prices/coingecko-historic?date=${date}`) + ); + const data: any[] = res.data; + + const priceMap = new Map(); + for (const entry of data) { + priceMap.set(entry.id, Number(entry.usd)); + } + + // Merge prices with assets + this.cosmos_evm_assets.forEach((asset) => { + if (asset.cg && priceMap.has(asset.cg)) { + asset.usd = priceMap.get(asset.cg)!; + } + }); + + this.lastPriceDate = date; + console.info( + `AssetManager: fetched ${priceMap.size} coingecko historic prices for ${date}` + ); + } + + getChainIdFromAddress(addr: string) { + if (!addr) return ''; + const prefix = addr.split('1')[0]; + const chain = this.networks.find((c) => c.bech32_prefix === prefix); + return chain?.id || ''; + } + + findNetworkInfo(id: string) { + if (!id) return null; + return this.networks.find((c) => c.id === id) || null; + } + + isRangeNetwork(id: string) { + return this.networks.some((c) => c.id === id); + } + + mapNetwork({ bridge, from }: { bridge?: string; from: string }) { + if (from == null || from === '') return ''; + const fromLower = String(from).toLowerCase(); + + if (bridge) { + const bridgeMapping = this.network_mappings.find( + (e) => String(e.from).toLowerCase() === fromLower && e.bridge === bridge + ); + if (bridgeMapping) return bridgeMapping.to; + } + + const generalMapping = this.network_mappings.find( + (e) => String(e.from).toLowerCase() === fromLower && !e.bridge + ); + if (generalMapping) return generalMapping.to; + + const wordMapping = this.word_to_network[fromLower]; + if (wordMapping) return wordMapping; + + return fromLower; + } + + findNativeEvmAsset(network: string) { + const ETH_NETWORKS = new Set([ + 'eth', + 'base', + 'arb1', + 'oeth', + 'unichain', + 'soneium', + 'linea', + 'hemi', + 'scr', + ]); + + if (ETH_NETWORKS.has(network)) { + return { + symbol: 'ETH', + denoms: [{ denom: 'ETH', exponent: 18 }], + name: 'Ethereum', + usd: 0, + preferredExponent: 18, + }; + } + + switch (network) { + case 'avax': + return { + symbol: 'AVAX', + denoms: [{ denom: 'AVAX', exponent: 18 }], + name: 'Avalanche', + usd: 0, + preferredExponent: 18, + }; + case 'bnb': + return { + symbol: 'BNB', + denoms: [{ denom: 'BNB', exponent: 18 }], + name: 'BNB Chain', + usd: 0, + preferredExponent: 18, + }; + case 'pol': + return { + symbol: 'POL', + denoms: [{ denom: 'POL', exponent: 18 }], + name: 'Polygon', + usd: 0, + preferredExponent: 18, + }; + case 'solana': + return { + symbol: 'SOL', + denoms: [{ denom: 'SOL', exponent: 9 }], + name: 'Solana', + usd: 0, + preferredExponent: 9, + }; + default: + return null; + } + } + + mapAssetSymbol(symbol: string) { + return this.symbolMap.get(String(symbol).toLowerCase()) || symbol; + } + + async warmPastCoingeckoPrices() { + const start = dayjs(COINGECKO_START_DATE); + const end = dayjs(); + const totalDays = end.diff(start, 'day') + 1; + + for ( + let d = start; + d.isBefore(end) || d.isSame(end, 'day'); + d = d.add(1, 'day') + ) { + const ts = d.format('YYYY-MM-DDT00:00:00Z'); + await this.setPastCoingeckoPrices(ts); + } + + console.info(`AssetManager: warmed coingecko prices for ${totalDays} days`); + } +} + +const manager = new AssetManager(); + +// Setup methods +export const assetManagerInitialization = manager.initialize.bind(manager); +export const setPastCoingeckoPrices = + manager.setPastCoingeckoPrices.bind(manager); +export const warmPastCoingeckoPrices = + manager.warmPastCoingeckoPrices.bind(manager); + +export const getChainIdFromAddress = + manager.getChainIdFromAddress.bind(manager); +export const findNetworkInfo = manager.findNetworkInfo.bind(manager); +export const isRangeNetwork = manager.isRangeNetwork.bind(manager); + +export const findAssetInfo = manager.findAssetInfo.bind(manager); + +export const mapNetwork = manager.mapNetwork.bind(manager); +export const mapAssetSymbol = manager.mapAssetSymbol.bind(manager); + +/** + * Primary amount formatting function for cosmos, evm, solana, etc. + */ +interface FormattedAmount { + tokenAmount: number; + symbol: string; + tokenUsdString: string; + usd: number; +} + +export const formatAmountToUsd: (am: { + amount: number | string | null | undefined; + denom?: string; + token?: string; + mint?: string; + skipScaling?: boolean; + options?: any; + chains?: string[]; +}) => FormattedAmount = manager.formatAmount.bind(manager); + +// --- Backwards-compatible exports --- + +/** @deprecated Use `assetManagerInitialization` instead. */ +export const initAssetService = assetManagerInitialization; + +/** @deprecated Use `findAssetInfo(denom)?.symbol || denom` instead. */ +export function findAssetSymbol(denom: string): string { + return findAssetInfo(denom)?.symbol || denom; +} + +/** @deprecated Use `formatAmountToUsd` per-item instead. */ +export function formatAmountMulti( + amList: { + amount: number | string; + denom?: string; + token?: string; + mint?: string; + skipScaling?: boolean; + options?: any; + chains?: string[]; + }[], + numAssetCount = 2 +): { tokenUsdString: string; usd: number; token: FormattedAmount[] } { + if (!amList || amList.length === 0) + return { tokenUsdString: '', usd: 0, token: [] }; + + const formatted = amList.map((am) => formatAmountToUsd(am)); + formatted.sort((a, b) => Math.abs(b.usd) - Math.abs(a.usd)); + + const shown = formatted.slice(0, numAssetCount); + const remaining = formatted.length - numAssetCount; + + const parts = shown.map((f) => f.tokenUsdString); + if (remaining > 0) { + parts.push(`and ${remaining} more`); + } + + const totalUsd = formatted.reduce((sum, f) => sum + f.usd, 0); + + return { + tokenUsdString: parts.join(', '), + usd: totalUsd, + token: formatted, + }; +} + +/** @deprecated No-op. Solana assets are now fetched during initialization. */ +export function fetchSolanaAssets(_ids: string[]): void { + return; +} + +/** @deprecated Liquidity pools are no longer tracked. Returns null. */ +export function getOsmosisPool( + _poolId: string | number +): { usd: number } | null { + return null; +} + +/** @deprecated Liquidity pools are no longer tracked. Returns empty object. */ +export function getAllOsmosisPools(): Record { + return {}; +} diff --git a/src/services/alertEvent.ts b/src/services/alertEvent.ts deleted file mode 100644 index 0c0b6ddb..00000000 --- a/src/services/alertEvent.ts +++ /dev/null @@ -1,32 +0,0 @@ -import axios from 'axios'; -import { IRangeEvent } from '../types/IRangeEvent'; -import { constants } from '../constants'; - -export async function createAlertEvents(args: { - token: string; - workspaceId: string | null; - ruleGroupId: string; - alertRuleId: string; - alerts: IRangeEvent[]; -}): Promise<{ success: true } | { success: false; retryAfterUnixSec: number }> { - const { token, workspaceId, ruleGroupId, alertRuleId, alerts } = args; - - const { data } = await axios.post< - { success: true } | { success: false; retryAfterUnixSec: number } - >( - `${constants.MANAGER_SERVICE.DOMAIN}${constants.MANAGER_SERVICE.CREATE_ALERT_EVENT_PATH}`, - { - workspaceId, - ruleGroupId, - alertRuleId, - alerts, - }, - { - headers: { - 'X-API-KEY': token, - }, - }, - ); - - return data; -} diff --git a/src/services/alerting-redis.ts b/src/services/alerting-redis.ts new file mode 100644 index 00000000..40a78c68 --- /dev/null +++ b/src/services/alerting-redis.ts @@ -0,0 +1,73 @@ +import * as Redis from 'redis'; +import { RedisKeys } from './redis-keys'; +import { IAlertRule } from '../types/IAlertRule'; +import { isTestEnv } from '../utils/basic'; +import { env } from '../env'; + +let redisClient: Redis.RedisClientType; +const testRedis = new Map(); + +async function initRedisClient() { + if (isTestEnv) return; + redisClient = Redis.createClient({ + url: `redis://${env.RUNNER_CACHE_REDIS_URL}`, + }); + await redisClient.connect(); + redisClient.on('error', (error) => { + throw error; + }); +} + +export async function redisGet(key: string) { + if (isTestEnv) { + return testRedis.get(key); + } + + if (!redisClient) await initRedisClient(); + return await redisClient.get(key); +} + +export async function redisGetJson(key: string): Promise { + if (isTestEnv) { + const valueStr = testRedis.get(key); + return valueStr ? JSON.parse(valueStr) : ({} as T); + } + + if (!redisClient) await initRedisClient(); + const valueStr = await redisClient.get(key); + return valueStr ? (JSON.parse(valueStr) as T) : ({} as T); +} + +export async function redisSet(key: string, value: string, ttl?: number) { + if (isTestEnv) { + testRedis.set(key, value); + return; + } + + if (!redisClient) await initRedisClient(); + return await redisClient.set(key, value, { EX: ttl }); +} + +export async function redisSetJson(key: string, value: object, ttl?: number) { + if (isTestEnv) { + testRedis.set(key, JSON.stringify(value)); + return; + } + + if (!redisClient) await initRedisClient(); + return await redisClient.set(key, JSON.stringify(value), { EX: ttl }); +} + +export async function loadCache(rule: IAlertRule): Promise { + const key = RedisKeys.alertRuleCacheKey(rule); + const cache = await redisGet(key); + if (cache) { + return JSON.parse(cache); + } + return {} as T; +} + +export async function saveCache(rule: IAlertRule, cache: any) { + const key = RedisKeys.alertRuleCacheKey(rule); + return await redisSet(key, JSON.stringify(cache)); +} diff --git a/src/services/axios.ts b/src/services/axios.ts new file mode 100644 index 00000000..50feba3c --- /dev/null +++ b/src/services/axios.ts @@ -0,0 +1,6 @@ +import _axios from 'axios'; + +export const axios = _axios.create({ + timeout: 6_000, + timeoutErrorMessage: `Range Runner Custom Axios Timeout Error: Request timed out after 6 seconds`, +}); diff --git a/src/services/base-classes/BaseHelper.ts b/src/services/base-classes/BaseHelper.ts new file mode 100644 index 00000000..af73fe80 --- /dev/null +++ b/src/services/base-classes/BaseHelper.ts @@ -0,0 +1,45 @@ +import { RedisKeys } from '../../utils/redis-keys'; +import { redisGetJson, redisSetJson } from '../alerting-redis'; +import { isTestEnv } from '../../utils/basic'; +import { fetchCached } from '../cached-requests'; + +// Base helper class with shared functionality +export class BaseHelper { + async loadCache(rule: any): Promise { + if (isTestEnv && rule.cache) { + return rule.cache; + } + + const cacheKey = RedisKeys.getParamsForRuleByRuleGroupIdAndRuleId({ + ruleGroupId: rule.ruleGroupId, + ruleId: rule.id, + }); + + const cacheParams = await redisGetJson(cacheKey); + + return cacheParams || ({} as T); + } + + async saveCache(rule: any, cache: any) { + const cacheKey = RedisKeys.getParamsForRuleByRuleGroupIdAndRuleId({ + ruleGroupId: rule.ruleGroupId, + ruleId: rule.id, + }); + + const serializedCache = JSON.parse( + JSON.stringify(cache, (key, value) => { + if (typeof value === 'bigint') { + return value.toString(); + } + return value; + }) + ); + + await redisSetJson(cacheKey, serializedCache); + return true; + } + + async fetchCached(func: () => T, uniqueKey: string): Promise { + return fetchCached(func, uniqueKey); + } +} diff --git a/src/services/base-classes/BooleanStateWatcher.ts b/src/services/base-classes/BooleanStateWatcher.ts new file mode 100644 index 00000000..9f8b4e80 --- /dev/null +++ b/src/services/base-classes/BooleanStateWatcher.ts @@ -0,0 +1,80 @@ +import { ISubEvent } from '../../types/IEvent'; +import { ITickProcessor } from '../../utils/processor'; +import { dayjs } from '../../utils/dayjs'; +import { skipTick } from '../../utils/skip-tick'; +import { OnTickHelper } from './OnTickHelper'; + +interface IBooleanStateWatcherCache { + lastNotified: string | null; + previousState: boolean; +} + +const DEFAULT_NOTIFY_INTERVAL = 6 * 60; // in minutes + +export interface IBooleanStateWatcherParams { + ticker: number; + notifyInterval?: number; // in minutes +} + +/** + * Base class for boolean alert state watchers for grafana style alerts + */ +export abstract class BooleanStateWatcher extends OnTickHelper { + abstract getAlertState({ + rule, + timestamp, + }: ITickProcessor): Promise; + + abstract getPositiveEvent({ + rule, + timestamp, + }: ITickProcessor): ISubEvent; + + abstract getNegativeEvent({ + rule, + timestamp, + }: ITickProcessor): ISubEvent; + + async callback({ + rule, + timestamp, + }: ITickProcessor): Promise { + const params = rule.parameters; + + if ( + skipTick({ + ticker: params.ticker, + timestamp, + salt: rule.id, + }) + ) { + return []; + } + + const cache = await this.loadCache(rule); + const alertState = await this.getAlertState({ rule, timestamp }); + + const events: ISubEvent[] = []; + + if (alertState) { + if ( + !cache.lastNotified || + dayjs(timestamp).diff(dayjs(cache.lastNotified), 'minutes') >= + (params.notifyInterval || DEFAULT_NOTIFY_INTERVAL) + ) { + cache.lastNotified = timestamp; + cache.previousState = true; + await this.saveCache(rule, cache); + events.push(this.getPositiveEvent({ rule, timestamp })); + } + } else if (cache.previousState) { + cache.lastNotified = null; + cache.previousState = false; + await this.saveCache(rule, cache); + events.push(this.getNegativeEvent({ rule, timestamp })); + } + + this.iterationCache = {}; + return events; + } +} diff --git a/src/services/base-classes/NumericCollectionWatcher.ts b/src/services/base-classes/NumericCollectionWatcher.ts new file mode 100644 index 00000000..0a8c70d6 --- /dev/null +++ b/src/services/base-classes/NumericCollectionWatcher.ts @@ -0,0 +1,113 @@ +import { ISubEvent } from '../../types/IEvent'; +import { ITickProcessor } from '../../utils/processor'; +import { skipTick } from '../../utils/skip-tick'; +import { OnTickHelper } from './OnTickHelper'; +import { validGreaterThan } from '../../utils/validParam'; + +interface INumericCollectionWatcherCache { + previousValues: Record; +} + +export interface INumericCollectionWatcherParams { + ticker: number; + numericChange?: number; + percChange?: number; + notifyDirection?: 'positive' | 'negative'; +} + +function validDirection( + direction: string, + notifyDirection: string | undefined +) { + if (!notifyDirection) return true; + return direction === notifyDirection; +} + +export abstract class NumericCollectionWatcher extends OnTickHelper { + abstract fetchNumericValues({ + rule, + timestamp, + }: ITickProcessor): Promise< + Record + >; + + abstract getPositiveEvent({ + rule, + timestamp, + key, + changes, + }: { + rule: any; + timestamp: string; + key: string; + changes: any; + }): ISubEvent; + + async callback({ + rule, + timestamp, + }: ITickProcessor): Promise { + const params = rule.parameters; + + if ( + skipTick({ + ticker: params.ticker, + timestamp, + salt: rule.id, + }) + ) { + return []; + } + + const cache = await this.loadCache(rule); + const currentValues = await this.fetchNumericValues({ rule, timestamp }); + + const events: ISubEvent[] = []; + + // Initialize cache if empty + if (!cache.previousValues) { + cache.previousValues = {}; + } + + // Check each key in the map + for (const [key, currentValue] of Object.entries(currentValues)) { + const previousValue = cache.previousValues[key] ?? currentValue; + const delta = Math.abs(currentValue - previousValue); + const direction = currentValue > previousValue ? 'positive' : 'negative'; + const percChange = + previousValue !== 0 ? (delta / previousValue) * 100 : 0; + + const shouldNotify = + validGreaterThan(delta, params.numericChange) && + validGreaterThan(percChange, params.percChange) && + validDirection(direction, params.notifyDirection); + + this.iterationCache = { + key, + previousValue: cache.previousValues[key], + currentValue, + delta, + percChange, + direction, + }; + + if (shouldNotify) { + cache.previousValues[key] = currentValue; + events.push( + this.getPositiveEvent({ + rule, + timestamp, + key, + changes: this.iterationCache, + }) + ); + } else { + cache.previousValues[key] = currentValue; + } + } + + await this.saveCache(rule, cache); + this.iterationCache = {}; + return events; + } +} diff --git a/src/services/base-classes/NumericStateWatcher.ts b/src/services/base-classes/NumericStateWatcher.ts new file mode 100644 index 00000000..400a10e9 --- /dev/null +++ b/src/services/base-classes/NumericStateWatcher.ts @@ -0,0 +1,88 @@ +import { ISubEvent } from '../../types/IEvent'; +import { ITickProcessor } from '../../utils/processor'; +import { skipTick } from '../../utils/skip-tick'; +import { OnTickHelper } from './OnTickHelper'; +import { validGreaterThan } from '../../utils/validParam'; + +interface INumericStateWatcherCache { + previousValue: number | null; +} + +export interface INumericStateWatcherParams { + ticker: number; + numericChange?: number; + percChange?: number; + notifyDirection?: 'positive' | 'negative'; +} + +function validDirection( + direction: string, + notifyDirection: string | undefined +) { + if (!notifyDirection) return true; + return direction === notifyDirection; +} + +export abstract class NumericStateWatcher extends OnTickHelper { + abstract fetchNumericValue({ + rule, + timestamp, + }: ITickProcessor): Promise; + + abstract getPositiveEvent({ + rule, + timestamp, + }: ITickProcessor): ISubEvent; + + async callback({ + rule, + timestamp, + }: ITickProcessor): Promise { + const params = rule.parameters; + + if ( + skipTick({ + ticker: params.ticker, + timestamp, + salt: rule.id, + }) + ) { + return []; + } + + const cache = await this.loadCache(rule); + const currentValue = await this.fetchNumericValue({ rule, timestamp }); + + const events: ISubEvent[] = []; + const previousValue = cache.previousValue ?? currentValue; + const delta = Math.abs(currentValue - previousValue); + const direction = currentValue > previousValue ? 'positive' : 'negative'; + const percChange = previousValue !== 0 ? (delta / previousValue) * 100 : 0; + + const shouldNotify = + validGreaterThan(delta, params.numericChange) && + validGreaterThan(percChange, params.percChange) && + validDirection(direction, params.notifyDirection); + + this.iterationCache = { + previousValue: cache.previousValue, + currentValue, + delta, + percChange, + direction, + }; + + if (shouldNotify) { + cache.previousValue = currentValue; + await this.saveCache(rule, cache); + + events.push(this.getPositiveEvent({ rule, timestamp })); + } else { + cache.previousValue = currentValue; + await this.saveCache(rule, cache); + } + + this.iterationCache = {}; + return events; + } +} diff --git a/src/services/base-classes/OnBlockHelper.ts b/src/services/base-classes/OnBlockHelper.ts new file mode 100644 index 00000000..d4395d57 --- /dev/null +++ b/src/services/base-classes/OnBlockHelper.ts @@ -0,0 +1,27 @@ +import { ISubEvent } from '../../types/IEvent'; +import { BaseHelper } from './BaseHelper'; +import { BlockProcessor, IBlockProcessor } from '../../utils/processor'; + +export abstract class OnBlockHelper extends BlockProcessor { + protected baseHelper: BaseHelper; + iterationCache: Record = {}; + + constructor() { + super(); + this.baseHelper = new BaseHelper(); + } + + protected async loadCache(rule: any): Promise { + return this.baseHelper.loadCache(rule); + } + + protected async saveCache(rule: any, cache: any) { + return this.baseHelper.saveCache(rule, cache); + } + + protected async fetchCached(fun: () => T, key: string): Promise { + return this.baseHelper.fetchCached(fun, key); + } + + abstract callback(processorParams: IBlockProcessor): Promise; +} diff --git a/src/services/base-classes/OnTickHelper.ts b/src/services/base-classes/OnTickHelper.ts new file mode 100644 index 00000000..5b64f196 --- /dev/null +++ b/src/services/base-classes/OnTickHelper.ts @@ -0,0 +1,27 @@ +import { ISubEvent } from '../../types/IEvent'; +import { BaseHelper } from './BaseHelper'; +import { TickProcessor, ITickProcessor } from '../../utils/processor'; + +export abstract class OnTickHelper extends TickProcessor { + protected baseHelper: BaseHelper; + iterationCache: Record = {}; + + constructor() { + super(); + this.baseHelper = new BaseHelper(); + } + + protected async loadCache(rule: any): Promise { + return this.baseHelper.loadCache(rule); + } + + protected async saveCache(rule: any, cache: any) { + return this.baseHelper.saveCache(rule, cache); + } + + protected async fetchCached(fun: () => T, key: string): Promise { + return this.baseHelper.fetchCached(fun, key); + } + + abstract callback(processorParams: ITickProcessor): Promise; +} diff --git a/src/services/cached-requests.ts b/src/services/cached-requests.ts new file mode 100644 index 00000000..edc1594e --- /dev/null +++ b/src/services/cached-requests.ts @@ -0,0 +1,34 @@ +import { dayjs } from '../utils/dayjs'; +import { RedisKeys } from '../utils/redis-keys'; +import { redisGetJson, redisSetJson } from './alerting-redis'; + +const DEFAULT_CACHE_TIME_IN_MINUTES = 5; + +export async function fetchCached( + func: () => T, + uniqueKey: string +): Promise { + const currentTime = dayjs(); + + const cacheKey = RedisKeys.getCachedFunctionKey(uniqueKey); + + const cached = await redisGetJson(cacheKey); + + if ( + cached?.timestamp && + currentTime.diff(dayjs(cached.timestamp), 'minute') < + DEFAULT_CACHE_TIME_IN_MINUTES + ) { + console.log(`get cached value ${uniqueKey} fetched at ${cached.timestamp}`); + return cached.value; + } + + const value = await func(); + + console.log(`set ${uniqueKey} at ${currentTime.toISOString()}`); + redisSetJson(cacheKey, { + value, + timestamp: currentTime.toISOString(), + }); + return value; +} diff --git a/src/services/consumer-redis.ts b/src/services/consumer-redis.ts new file mode 100644 index 00000000..be995122 --- /dev/null +++ b/src/services/consumer-redis.ts @@ -0,0 +1,321 @@ +import { commandOptions } from 'redis'; +import * as r from 'redis'; +import { z } from 'zod'; +import { env } from '../env'; +import { logger } from '../utils/logger'; +import { safeJsonParse } from '../utils/basic'; + +const PayloadValidator = z.object({ + id: z.string().min(1), + message: z.object({ + message: z.string().optional(), + data: z.string().optional(), + buffer: z.string().optional(), + }), +}); + +// Store active Redis clients for graceful shutdown +const activeClients = new Map, boolean>(); + +// Global flag to signal shutdown +let isShuttingDown = false; + +// Setup graceful shutdown handlers +let shutdownHandlersSetup = false; + +function setupGracefulShutdown() { + if (shutdownHandlersSetup) return; + shutdownHandlersSetup = true; + + const gracefulShutdown = async (signal: string) => { + if (isShuttingDown) return; // Prevent multiple shutdown attempts + isShuttingDown = true; + + logger.info( + `Received ${signal}, gracefully shutting down Redis connections...` + ); + + // Disconnect Redis clients + const disconnectPromises = Array.from(activeClients.entries()).map( + async ([client, isConnected]) => { + if (!isConnected) return; // Skip already disconnected clients + + try { + await client.disconnect(); + activeClients.set(client, false); // Mark as disconnected + logger.info('Redis client disconnected successfully'); + } catch (error) { + logger.error('Error disconnecting Redis client:', error); + } + } + ); + + await Promise.all(disconnectPromises); + activeClients.clear(); + }; + + process.on('SIGINT', () => gracefulShutdown('SIGINT')); + process.on('SIGTERM', () => gracefulShutdown('SIGTERM')); +} + +export async function createRedisClient(url = env.BLOCK_REDIS_URL) { + const client = r.createClient({ + url: `redis://${url}`, + }); + await client.connect(); + + // Store URL on client for diagnostic logging + (client as any).__redisUrl = url; + + // Register client for graceful shutdown + activeClients.set(client, true); // Mark as connected + setupGracefulShutdown(); + + return client; +} + +export async function consumeRedisStream({ + client, + streamName, + consumerGroup, + consumerName, + callback, + count = 10, +}: { + client: ReturnType; + streamName: string; + consumerGroup: string; + consumerName: string; + callback: (payload: any, messageId: string) => Promise; + count?: number; +}) { + const redisUrl = (client as any).__redisUrl || 'unknown'; + const streamId = `${redisUrl}/${streamName}`; + + if (!streamName || !consumerGroup || !consumerName) { + throw new Error( + `Invalid stream config: stream=${streamName}, group=${consumerGroup}, consumer=${consumerName}, host=${redisUrl}` + ); + } + + // Ensure stream exists and consumer group is set up + try { + const groups = await client.xInfoGroups(streamName); + const groupExists = groups.some((g) => g.name === consumerGroup); + if (!groupExists) { + await client.xGroupCreate(streamName, consumerGroup, '$'); + logger.info( + `Created consumer group ${consumerGroup} for stream ${streamId}` + ); + } + } catch (error: any) { + if (error.message?.includes('no such key')) { + throw new Error( + `Stream ${streamId} does not exist. The stream must be created by the producer before the consumer can connect.`, + { cause: error } + ); + } else { + throw new Error( + `Failed to setup consumer group on ${streamId}: ${error.message}`, + { cause: error } + ); + } + } + + // Check if consumer exists in group + const consumers = await client.xInfoConsumers(streamName, consumerGroup); + const consumerExists = consumers.some((c) => c.name === consumerName); + if (!consumerExists) { + // Create consumer in group + await client.xGroupCreateConsumer(streamName, consumerGroup, consumerName); + } + + while (!isShuttingDown) { + try { + const response = await client.xReadGroup( + commandOptions({ + isolated: true, + }), + consumerGroup, + consumerName, + [ + { + key: streamName, + id: '>', // Using '>' to read new messages that haven't been delivered to any consumer yet + }, + ], + { + COUNT: count, + BLOCK: 5000, + } + ); + + if (response !== null) { + const messages = response[0].messages; + + // Process messages sequentially to reduce memory spikes + for (const row of messages) { + if (isShuttingDown) break; // Stop processing if shutdown initiated + + const msg = PayloadValidator.safeParse(row); + if (!msg.success) { + logger.warn( + `${streamId}: validation failed for ${row.id}: ${msg.error.message}` + ); + logger.warn( + `${streamId}: raw keys: ${JSON.stringify(Object.keys(row.message || {}))}` + ); + } + + // Binary path: base64-encoded FlatBuffer in `buffer` field + const bufferField = msg.data?.message?.buffer; + if (msg.success && bufferField) { + try { + const binary = Buffer.from(bufferField, 'base64'); + const payload = { + _binaryBlock: new Uint8Array( + binary.buffer, + binary.byteOffset, + binary.byteLength + ), + }; + await callback(payload, msg.data.id); + } catch (callbackError) { + logger.error( + `Callback error for binary message ${row.id}: ${callbackError}` + ); + } + + try { + await client.xAck(streamName, consumerGroup, row.id); + } catch (ackError) { + logger.error( + `Failed to acknowledge message ${row.id}:`, + ackError + ); + } + continue; + } + + // JSON path: parse `data` or `message` field + const payload = safeJsonParse( + (msg.data?.message?.data || msg.data?.message?.message) ?? '' + ); + + if (!payload && msg.success) { + logger.warn( + `${streamId}: JSON parse failed for ${row.id}, raw: ${JSON.stringify(msg.data?.message).slice(0, 200)}` + ); + } + + if (msg.success && payload) { + try { + await callback(payload, msg.data.id); + } catch (callbackError) { + logger.error( + `Callback error for message ${row.id}: ${callbackError}` + ); + // Continue processing other messages even if one fails + } + } + + // Acknowledge message after successful processing + try { + await client.xAck(streamName, consumerGroup, row.id); + } catch (ackError) { + logger.error(`Failed to acknowledge message ${row.id}:`, ackError); + } + } + } + } catch (error: any) { + if (isShuttingDown) { + logger.info('Consumer loop stopped due to shutdown'); + break; + } + + logger.error( + `Redis stream error on ${streamId} (group=${consumerGroup}): ${error.message}` + ); + + // Exponential backoff on errors to prevent tight error loops + const backoffDelay = 1000; + await new Promise((resolve) => setTimeout(resolve, backoffDelay)); + + // Don't exit immediately on error during shutdown + if (!isShuttingDown) { + process.exit(1); + } + } + } + + logger.info('Redis stream consumer stopped gracefully'); +} + +export async function publishToStream({ + client, + streamName, + payload, +}: { + client: ReturnType; + streamName: string; + payload: any; +}) { + if (!streamName) { + throw new Error(`Invalid stream name: ${streamName}`); + } + + // Create stream if it doesn't exist + try { + await client.xGroupCreate(streamName, streamName, '0', { MKSTREAM: true }); + logger.info(`Created stream ${streamName}`); + } catch (err: any) { + // Ignore if group already exists + if (!err.message.includes('BUSYGROUP')) { + throw err; + } + } + + await client.xAdd( + streamName, + '*', // Let Redis generate the message ID + { + message: JSON.stringify(payload), + } + ); + + // Trim stream to keep only the latest 100 elements + // await client.xTrim(streamName, 'MAXLEN', 100000); + + logger.debug(`Published payload to stream ${streamName}`); +} + +export async function publishBinaryToStream({ + client, + streamName, + payload, +}: { + client: ReturnType; + streamName: string; + payload: Uint8Array; +}) { + if (!streamName) { + throw new Error(`Invalid stream name: ${streamName}`); + } + + // Create stream if it doesn't exist + try { + await client.xGroupCreate(streamName, streamName, '0', { MKSTREAM: true }); + } catch (err: any) { + if (!err.message.includes('BUSYGROUP')) { + throw err; + } + } + + await client.xAdd(streamName, '*', { + buffer: Buffer.from(payload).toString('base64'), + }); + + logger.debug(`Published binary payload to stream ${streamName}`); +} + +export type IRedisClient = Awaited>; diff --git a/src/services/event-service.ts b/src/services/event-service.ts new file mode 100644 index 00000000..5c0b1e05 --- /dev/null +++ b/src/services/event-service.ts @@ -0,0 +1,63 @@ +import { IEvent } from '../types/IEvent'; +import * as r from 'redis'; +import { env } from '../env'; +import { logger } from '../utils/logger'; + +let redisClient: ReturnType; + +export async function initNotificationsRedis() { + redisClient = r.createClient({ + url: `redis://${env.NOTIFICATIONS_REDIS_URL}`, + }); + + await redisClient.connect(); +} + +export async function disconnectNotificationsRedis() { + if (redisClient) { + await redisClient.disconnect(); + } +} + +// Ensure stream exists (called once at init or on first publish) +let streamInitialized = false; + +async function ensureStreamExists() { + if (streamInitialized) return; + + const streamName = env.NOTIFICATIONS_REDIS_STREAM_NAME; + try { + await redisClient.xGroupCreate(streamName, streamName, '0', { + MKSTREAM: true, + }); + logger.info(`Created stream ${streamName}`); + } catch (err: any) { + // Ignore if group already exists + if (!err.message.includes('BUSYGROUP')) { + throw err; + } + } + streamInitialized = true; +} + +export async function publishEvents(events: IEvent[]) { + if (!events.length) return; + + await ensureStreamExists(); + + const streamName = env.NOTIFICATIONS_REDIS_STREAM_NAME; + + // Use pipeline for batch writes - single round-trip for all events + const pipeline = redisClient.multi(); + + for (const event of events) { + pipeline.xAdd(streamName, '*', { + message: JSON.stringify(event), + }); + } + + await pipeline.exec(); + + // Trim once after batch (not per-event) + // await redisClient.xTrim(streamName, 'MAXLEN', 100); +} diff --git a/src/services/fetchAlertRules.ts b/src/services/fetchAlertRules.ts deleted file mode 100644 index e9fea860..00000000 --- a/src/services/fetchAlertRules.ts +++ /dev/null @@ -1,68 +0,0 @@ -import axios from 'axios'; -import { IRangeAlertRule } from '../types/IRangeAlertRule'; -import { constants } from '../constants'; - -export async function fetchAlertRulesByRuleGroupID(args: { - token: string; - ruleGroupId: string; -}): Promise { - const { token, ruleGroupId } = args; - const url = `${ - constants.MANAGER_SERVICE.DOMAIN - }${constants.MANAGER_SERVICE.FETCH_RULES_BY_RULE_GROUP_ID_PATH(ruleGroupId)}`; - - try { - const { - data: { rules }, - } = await axios.get<{ - rules: IRangeAlertRule[]; - }>(url, { - headers: { - 'X-API-KEY': token, - }, - timeout: constants.AXIOS.TIMEOUT, - }); - - return rules; - } catch (err: any) { - if (err.response?.data?.msg) { - throw new Error(err.response.data.msg); - } - - throw err; - } -} - -export async function fetchAlertRuleByRuleGroupAndRuleID(args: { - token: string; - ruleGroupId: string; - ruleId: string; -}) { - const { token, ruleGroupId, ruleId } = args; - const url = `${ - constants.MANAGER_SERVICE.DOMAIN - }${constants.MANAGER_SERVICE.FETCH_RULE_BY_RULE_GROUP_ID_AND_RULE_ID_PATH({ - ruleGroupId, - ruleId, - })}`; - - try { - const { - data: { rule }, - } = await axios.get<{ - rule: IRangeAlertRule | null | undefined; - }>(url, { - headers: { - 'X-API-KEY': token, - }, - }); - - return rule; - } catch (err: any) { - if (err.response?.data?.msg) { - throw new Error(err.response.data.msg); - } - - throw err; - } -} diff --git a/src/services/fetchBlock.ts b/src/services/fetchBlock.ts deleted file mode 100644 index af5c1d1f..00000000 --- a/src/services/fetchBlock.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { LRUCache } from 'lru-cache'; -import axios from 'axios'; -import { IRangeBlock } from '../types/chain/IRangeBlock'; -import { constants } from '../constants'; - -const blockCache = new LRUCache({ - max: constants.BLOCK_CACHE.MAX, -}); - -export async function fetchBlock(args: { - token: string; - height: string; - network: string; - includeAvailableRangeOnNotFound?: boolean; -}): Promise { - const { token, height, network, includeAvailableRangeOnNotFound } = args; - - const cachedBlock = blockCache.get(`${network}-${height}`); - if (cachedBlock) { - return cachedBlock; - } - - const url = `${constants.MANAGER_SERVICE.DOMAIN}${constants.MANAGER_SERVICE.FETCH_BLOCK_BY_NETWORK_AND_HEIGHT}`; - const { - data: { block }, - } = await axios.get<{ - block: IRangeBlock; - }>(url, { - params: { - network, - height, - ...(includeAvailableRangeOnNotFound && { - includeAvailableRangeOnNotFound, - }), - }, - headers: { - 'X-API-KEY': token, - }, - timeout: constants.AXIOS.TIMEOUT, - }); - - blockCache.set(`${network}-${height}`, block); - - return block; -} diff --git a/src/services/fetchBlocksByRange.ts b/src/services/fetchBlocksByRange.ts deleted file mode 100644 index 19faad46..00000000 --- a/src/services/fetchBlocksByRange.ts +++ /dev/null @@ -1,31 +0,0 @@ -import axios from 'axios'; -import { IRangeBlock } from '../types/chain/IRangeBlock'; -import { constants } from '../constants'; - -export async function fetchBlocksByRange(args: { - token: string; - network: string; - startHeight: string; - endHeight: string; -}): Promise { - const { token, startHeight, endHeight, network } = args; - const url = `${constants.MANAGER_SERVICE.DOMAIN}${constants.MANAGER_SERVICE.FETCH_BLOCKS_BY_RANGE}`; - - const { - data: { blocks }, - } = await axios.get<{ - blocks: IRangeBlock[]; - }>(url, { - params: { - network, - startHeight, - endHeight, - }, - headers: { - 'X-API-KEY': token, - }, - timeout: constants.AXIOS.TIMEOUT, - }); - - return blocks; -} diff --git a/src/services/fetchConfig.ts b/src/services/fetchConfig.ts deleted file mode 100644 index d6549737..00000000 --- a/src/services/fetchConfig.ts +++ /dev/null @@ -1,17 +0,0 @@ -import axios from 'axios'; -import { constants } from '../constants'; -import { IRangeConfig } from '../types/IRangeConfig'; - -export async function fetchConfig(args: { token: string }) { - const { token } = args; - const url = `${constants.MANAGER_SERVICE.DOMAIN}${constants.MANAGER_SERVICE.FETCH_CONFIG_PATH}`; - - const { data } = await axios.get(url, { - headers: { - 'X-API-KEY': token, - }, - timeout: constants.AXIOS.TIMEOUT, - }); - - return data; -} diff --git a/src/services/getCosmosClient.ts b/src/services/getCosmosClient.ts deleted file mode 100644 index 371f6d14..00000000 --- a/src/services/getCosmosClient.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { CosmosClient } from '../cosmos/CosmosClient'; -import { Network } from '../network'; -import { IRangeNetwork } from '../types/IRangeNetwork'; - -const urlConfig = { - 'osmosis-1': { - rpc: process.env.OSMOSIS_RPC || 'https://rpc.osmosis.zone/', - }, - 'cosmoshub-4': { - rpc: process.env.COSMOS_RPC || 'https://cosmoshub.validator.network/', - }, - 'grand-1': { - rpc: - process.env.NOBLE_TESTNET_RPC || - 'https://rpc.testnet.noble.strange.love/', - }, - 'mocha-4': { - rpc: process.env.MOCHA_RPC || 'https://rpc-2.celestia-mocha.com/', - }, - 'osmo-test-5': { - rpc: process.env.OSMOSIS_TEST_RPC || 'https://rpc.osmotest5.osmosis.zone', - }, - celestia: { - rpc: process.env.CELESTIA_RPC || 'https://rpc.lavenderfive.com/celestia', - }, - 'noble-1': { - rpc: process.env.NOBLE_RPC || 'https://noble-rpc.polkachu.com/', - }, - 'neutron-1': { - rpc: process.env.NEUTRON_RPC || 'https://neutron-rpc.publicnode.com/', - }, - 'dydx-mainnet-1': { - rpc: process.env.DYDX_RPC || 'https://dydx-rpc.publicnode.com:443', - }, - 'dymension_1100-1': { - rpc: - process.env.DYMENSION_RPC || 'https://dymension-rpc.publicnode.com:443', - }, - 'stride-1': { - rpc: process.env.STRIDE_RPC || 'https://stride-rpc.publicnode.com:443/', - }, -}; - -const networkToClients: Record = { - 'osmosis-1': new CosmosClient(urlConfig['osmosis-1'].rpc), - 'cosmoshub-4': new CosmosClient(urlConfig['cosmoshub-4'].rpc), - celestia: new CosmosClient(urlConfig.celestia.rpc), - 'stride-1': new CosmosClient(urlConfig['stride-1'].rpc), - 'noble-1': new CosmosClient(urlConfig['noble-1'].rpc), - 'neutron-1': new CosmosClient(urlConfig['neutron-1'].rpc), - 'dydx-mainnet-1': new CosmosClient(urlConfig['dydx-mainnet-1'].rpc), - 'dymension_1100-1': new CosmosClient(urlConfig['dymension_1100-1'].rpc), - 'grand-1': new CosmosClient(urlConfig['grand-1'].rpc), - 'mocha-4': new CosmosClient(urlConfig['mocha-4'].rpc), - 'osmo-test-5': new CosmosClient(urlConfig['osmo-test-5'].rpc), -}; - -export function getCosmosClient(network: IRangeNetwork): CosmosClient { - return networkToClients[network]; -} - -export function getCustomCosmosClient(rpc: string, lcd?: string): CosmosClient { - return new CosmosClient(rpc, lcd); -} diff --git a/src/services/postDebugAlert.ts b/src/services/postDebugAlert.ts deleted file mode 100644 index 46f12ad5..00000000 --- a/src/services/postDebugAlert.ts +++ /dev/null @@ -1,39 +0,0 @@ -import axios from 'axios'; -import { constants } from '../constants'; - -export interface DebugAlert { - runnerId: string; - alert: Record; - blockNetwork?: string; - blockHeight?: string; - ruleGroupId?: string; - ruleId?: string; -} - -export async function postDebugAlert(args: { - token: string; - ping: boolean; - debugAlerts: DebugAlert[]; -}): Promise<{ success: boolean }> { - const { token, ping, debugAlerts } = args; - const url = `${constants.MANAGER_SERVICE.DOMAIN}${constants.MANAGER_SERVICE.POST_DEBUG_ALERT_PATH}`; - - const { data } = await axios.post<{ success: boolean }>( - url, - { - debugAlerts: debugAlerts.map((da) => ({ - ...da, - alert: JSON.stringify(da.alert, null, 2), - })), - ping, - }, - { - headers: { - 'X-API-KEY': token, - }, - timeout: constants.AXIOS.TIMEOUT, - }, - ); - - return data; -} diff --git a/src/services/prometheus-metrics.ts b/src/services/prometheus-metrics.ts new file mode 100644 index 00000000..5f8daf63 --- /dev/null +++ b/src/services/prometheus-metrics.ts @@ -0,0 +1,201 @@ +import * as client from 'prom-client'; +import { getStatsSummary, getLagStats } from './stats-service'; +import { getPoolStats } from '../threadpool/pool'; +import { getBufferPoolStats } from '../processors/taskProcessor'; +import { prometheusRegistry } from './prometheus-registry'; + +export { prometheusRegistry }; + +// Add default Node.js metrics (heap, GC, event loop) +client.collectDefaultMetrics({ register: prometheusRegistry }); + +// --- Counters --- +const blocksProcessedTotal = new client.Counter({ + name: 'runner_blocks_processed_total', + help: 'Total number of blocks processed', + registers: [prometheusRegistry], +}); + +const ticksProcessedTotal = new client.Counter({ + name: 'runner_ticks_processed_total', + help: 'Total number of ticks processed', + registers: [prometheusRegistry], +}); + +const tasksTotal = new client.Counter({ + name: 'runner_tasks_total', + help: 'Total tasks by trigger mode and status', + labelNames: ['trigger_mode', 'status'] as const, + registers: [prometheusRegistry], +}); + +const eventsEmittedTotal = new client.Counter({ + name: 'runner_events_emitted_total', + help: 'Total events emitted', + registers: [prometheusRegistry], +}); + +// --- Gauges --- +const rulesTotal = new client.Gauge({ + name: 'runner_rules_total', + help: 'Number of rules by status', + labelNames: ['status'] as const, + registers: [prometheusRegistry], +}); + +const threadPoolThreads = new client.Gauge({ + name: 'runner_thread_pool_threads', + help: 'Thread pool threads by state', + labelNames: ['state'] as const, + registers: [prometheusRegistry], +}); + +const queueSize = new client.Gauge({ + name: 'runner_queue_size', + help: 'Current task queue size', + registers: [prometheusRegistry], +}); + +const blockLagSeconds = new client.Gauge({ + name: 'runner_block_lag_seconds', + help: 'Seconds behind real-time for blocks', + registers: [prometheusRegistry], +}); + +const tickLagSeconds = new client.Gauge({ + name: 'runner_tick_lag_seconds', + help: 'Seconds behind real-time for ticks', + registers: [prometheusRegistry], +}); + +const uptimeSeconds = new client.Gauge({ + name: 'runner_uptime_seconds', + help: 'Service uptime in seconds', + registers: [prometheusRegistry], +}); + +const bufferPoolSize = new client.Gauge({ + name: 'runner_buffer_pool_size', + help: 'Number of buffers in the pool by bucket size', + labelNames: ['bucket_mb'] as const, + registers: [prometheusRegistry], +}); + +// --- Histograms --- +const taskDurationSeconds = new client.Histogram({ + name: 'runner_task_duration_seconds', + help: 'Task processing duration in seconds', + labelNames: ['trigger_mode'] as const, + buckets: [0.01, 0.05, 0.1, 0.5, 1, 2, 5, 10], + registers: [prometheusRegistry], +}); + +// --- Update function (call before scrape) --- +let lastBlocksProcessed = 0; +let lastTicksProcessed = 0; +let lastEventsEmitted = 0; +let lastBlockTasksCompleted = 0; +let lastBlockTasksFailed = 0; +let lastTickTasksCompleted = 0; +let lastTickTasksFailed = 0; + +export function updatePrometheusMetrics(): void { + const stats = getStatsSummary(); + const lag = getLagStats(); + const pool = getPoolStats(); + const bufferStats = getBufferPoolStats(); + + // Update counters (increment by delta) + const blocksDelta = + (stats.block.total_blocks_processed || 0) - lastBlocksProcessed; + if (blocksDelta > 0) blocksProcessedTotal.inc(blocksDelta); + lastBlocksProcessed = stats.block.total_blocks_processed || 0; + + const ticksDelta = + (stats.tick.total_ticks_processed || 0) - lastTicksProcessed; + if (ticksDelta > 0) ticksProcessedTotal.inc(ticksDelta); + lastTicksProcessed = stats.tick.total_ticks_processed || 0; + + const eventsDelta = stats.total_events_emitted - lastEventsEmitted; + if (eventsDelta > 0) eventsEmittedTotal.inc(eventsDelta); + lastEventsEmitted = stats.total_events_emitted; + + // Update task counters by trigger_mode and status + const blockCompletedDelta = + stats.block.total_tasks_completed - lastBlockTasksCompleted; + if (blockCompletedDelta > 0) { + tasksTotal.inc( + { trigger_mode: 'block', status: 'success' }, + blockCompletedDelta + ); + } + lastBlockTasksCompleted = stats.block.total_tasks_completed; + + const blockFailedDelta = + stats.block.total_tasks_cancelled_skipped - lastBlockTasksFailed; + if (blockFailedDelta > 0) { + tasksTotal.inc( + { trigger_mode: 'block', status: 'failed' }, + blockFailedDelta + ); + } + lastBlockTasksFailed = stats.block.total_tasks_cancelled_skipped; + + const tickCompletedDelta = + stats.tick.total_tasks_completed - lastTickTasksCompleted; + if (tickCompletedDelta > 0) { + tasksTotal.inc( + { trigger_mode: 'tick', status: 'success' }, + tickCompletedDelta + ); + } + lastTickTasksCompleted = stats.tick.total_tasks_completed; + + const tickFailedDelta = + stats.tick.total_tasks_cancelled_skipped - lastTickTasksFailed; + if (tickFailedDelta > 0) { + tasksTotal.inc({ trigger_mode: 'tick', status: 'failed' }, tickFailedDelta); + } + lastTickTasksFailed = stats.tick.total_tasks_cancelled_skipped; + + // Update gauges + rulesTotal.set({ status: 'healthy' }, stats.total_healthy_rules); + rulesTotal.set({ status: 'blocked' }, stats.total_blocked_rules); + + threadPoolThreads.set({ state: 'active' }, pool.active_threads); + threadPoolThreads.set({ state: 'idle' }, pool.idle_threads); + + queueSize.set(pool.queue_size); + + // Handle -1 (no data) for lag values + blockLagSeconds.set(lag.block_lag_seconds >= 0 ? lag.block_lag_seconds : 0); + tickLagSeconds.set(lag.tick_lag_seconds >= 0 ? lag.tick_lag_seconds : 0); + + uptimeSeconds.set(stats.uptime.uptime_seconds); + + // Update buffer pool stats + for (const bucket of bufferStats.buckets) { + bufferPoolSize.set({ bucket_mb: String(bucket.size_mb) }, bucket.count); + } + + // Observe processing times for histogram (convert ms to seconds) + // Note: These are averages, not individual observations. For more accurate + // histograms, we would need to track individual task durations. + if (stats.block.average_processing_time > 0) { + taskDurationSeconds.observe( + { trigger_mode: 'block' }, + stats.block.average_processing_time / 1000 + ); + } + if (stats.tick.average_processing_time > 0) { + taskDurationSeconds.observe( + { trigger_mode: 'tick' }, + stats.tick.average_processing_time / 1000 + ); + } +} + +export async function getMetrics(): Promise { + updatePrometheusMetrics(); + return prometheusRegistry.metrics(); +} diff --git a/src/services/prometheus-registry.ts b/src/services/prometheus-registry.ts new file mode 100644 index 00000000..431a6d8e --- /dev/null +++ b/src/services/prometheus-registry.ts @@ -0,0 +1,6 @@ +import * as client from 'prom-client'; + +// Shared Prometheus registry — extracted so lightweight consumers +// (seed metrics) can register metrics without pulling in heavy +// runtime modules (stats-service, pool, taskProcessor). +export const prometheusRegistry = new client.Registry(); diff --git a/src/services/range-api.ts b/src/services/range-api.ts new file mode 100644 index 00000000..ec1d8c8e --- /dev/null +++ b/src/services/range-api.ts @@ -0,0 +1,167 @@ +import { env } from '../env'; +import { redisGet, redisSet } from './alerting-redis'; +import { axios } from './axios'; + +interface IAddressInfo { + address: string; + name_tag: string; +} + +const CACHE_TTL_SECONDS = 7 * 24 * 60 * 60; // 7 days +const RISK_SCORE_CACHE_TTL_SECONDS = 24 * 60 * 60; // 1 day + +export async function fetchAddressInfoBatch({ + addresses, + network, +}: { + addresses: string[]; + network: string; +}): Promise> { + const nameMap: Record = {}; + const unknownAddresses: string[] = []; + + // Check cache for each address + for (const address of addresses) { + const cacheKey = `address-global-info-${address}`; + const cachedInfo = await redisGet(cacheKey); + + if (cachedInfo !== undefined && cachedInfo !== null) { + // Cache hit with a valid value + nameMap[address] = JSON.parse(cachedInfo); + } else if (cachedInfo === undefined) { + // Cache miss + unknownAddresses.push(address); + } + } + + // If all addresses were cached, return early + if (unknownAddresses.length === 0) { + return nameMap; + } + + // Fetch unknown addresses from API + const params = new URLSearchParams(); + params.set('networks', network); + + unknownAddresses.forEach((a) => params.append('addresses', a)); + params.set('includeNft', 'false'); + params.set('validateSearch', 'true'); + + const url = `${env.RANGE_API_HOST}/v1/address/labels/search?${params.toString()}`; + const res = await axios.get(url, { + headers: { + accept: 'application/json', + 'X-API-KEY': env.RANGE_API_KEY, + }, + timeout: 10000, + }); + + // Create a set of addresses that were found in the API response + const foundAddresses = new Set(); + + // Cache and map the results + for (const e of res.data) { + nameMap[e.address] = e; + foundAddresses.add(e.address); + + // Cache the found value with 7 days TTL + const cacheKey = `address-global-info-${e.address}`; + await redisSet(cacheKey, JSON.stringify(e), CACHE_TTL_SECONDS); + } + + // Cache null values for addresses that weren't found + for (const address of unknownAddresses) { + if (!foundAddresses.has(address)) { + const cacheKey = `address-global-info-${address}`; + await redisSet(cacheKey, 'null', CACHE_TTL_SECONDS); + } + } + + return nameMap; +} + +export async function fetchAddressRiskScore(address: string, network: string) { + const cacheKey = `risk-score-${address}-${network}`; + const cachedRiskScore = await redisGet(cacheKey); + + if (cachedRiskScore !== undefined && cachedRiskScore !== null) { + return JSON.parse(cachedRiskScore); + } + + const url = `${env.RANGE_API_HOST}/v1/risk/address?address=${address}&network=${network}`; + + const res = await axios.get(url, { + headers: { + accept: 'application/json', + 'X-API-KEY': env.RANGE_API_KEY, + }, + timeout: 10000, + }); + + const riskScoreData = res.data; + await redisSet( + cacheKey, + JSON.stringify(riskScoreData), + RISK_SCORE_CACHE_TTL_SECONDS + ); + + return riskScoreData; +} + +export interface ISanctionsResult { + is_ofac_sanctioned: boolean; + is_token_blacklisted: boolean; + ofac_info?: { name_tag: string; category: string }; + attribution?: { name: string; category: string; malicious: boolean }; +} + +export async function fetchSanctionsCheck( + address: string, + network: string +): Promise { + try { + const url = `${env.RANGE_API_HOST}/v1/risk/sanctions/${address}?network=${network}`; + + const res = await axios.get(url, { + headers: { + accept: 'application/json', + 'X-API-KEY': env.RANGE_API_KEY, + }, + timeout: 10000, + }); + + return res.data; + } catch { + return null; + } +} + +export async function fetchLabelledAddressTransaction( + address: string, + network: string, + startTime?: string +) { + const params = new URLSearchParams({ + address, + network, + limit: '50', + offset: '0', + status: 'success', + }); + + if (startTime) { + params.append('startTime', startTime); + } + + const url = `${env.RANGE_API_HOST}/v1/address/transactions?${params.toString()}`; + + const res = await axios.get(url, { + headers: { + accept: 'application/json', + 'X-API-KEY': env.RANGE_API_KEY, + }, + timeout: 10000, + }); + + return res.data.transactions; +} diff --git a/src/services/redis-keys.ts b/src/services/redis-keys.ts new file mode 100644 index 00000000..6aa1a7b5 --- /dev/null +++ b/src/services/redis-keys.ts @@ -0,0 +1,17 @@ +export const RedisKeys = { + alertRuleCacheKey: (input: { id: string }) => { + return `rule-cache:${input.id}`; + }, + + getCachedFunctionKey(funName: string) { + return `cached:function:{${funName}}`; + }, + + getBgAggregationKey(aggName: string) { + return `bg:aggregation:${aggName}`; + }, + + getProgramIdlKey(programId: string) { + return `solanafm:idl:${programId}`; + }, +}; diff --git a/src/services/rpc.ts b/src/services/rpc.ts new file mode 100644 index 00000000..85eeeca6 --- /dev/null +++ b/src/services/rpc.ts @@ -0,0 +1,99 @@ +import { env } from '../env'; +import { Connection } from '@solana/web3.js'; +import { ethers } from 'ethers'; +import { axios } from './axios'; +import { cosmos, ibc, cosmwasm } from 'osmojs'; +import { IEvmNetwork } from '../types/INetwork'; + +const customRPCs: Record = {}; + +export function getRpc(network: string) { + if (customRPCs[network]) { + return customRPCs[network]; + } + + return `${env.RPC_PROXY_HOST}/api/embed-auth/${env.RPC_PROXY_TOKEN}/rpc/${network}`; +} + +let _solanaConnection: Connection | null = null; +export function getSolanaConnection(): Connection { + if (!_solanaConnection) { + _solanaConnection = new Connection(getRpc('solana'), { + commitment: 'confirmed', + }); + } + return _solanaConnection; +} + +const clientMapping: any = {}; +export const getEvmProvider = ( + network: IEvmNetwork +): ethers.JsonRpcProvider => { + if (clientMapping[network]) return clientMapping[network]; + + const request = new ethers.FetchRequest(getRpc(network)); + const provider = new ethers.JsonRpcProvider(request); + clientMapping[network] = provider; + return provider; +}; + +const cosmosClients: Record< + string, + Awaited> +> = {}; +const cwClients: Record< + string, + Awaited> +> = {}; +const ibcClients: Record< + string, + Awaited> +> = {}; + +export const getCosmosRpcClient = async (network: string) => { + if (cosmosClients[network]) return cosmosClients[network]; + cosmosClients[network] = await cosmos.ClientFactory.createRPCQueryClient({ + rpcEndpoint: getRpc(network), + }); + return cosmosClients[network]; +}; + +export const getCwRpcClient = async (network: string) => { + if (cwClients[network]) return cwClients[network]; + cwClients[network] = await cosmwasm.ClientFactory.createRPCQueryClient({ + rpcEndpoint: getRpc(network), + }); + return cwClients[network]; +}; + +export const getIbcRpcClient = async (network: string) => { + if (ibcClients[network]) return ibcClients[network]; + ibcClients[network] = await ibc.ClientFactory.createRPCQueryClient({ + rpcEndpoint: getRpc(network), + }); + return ibcClients[network]; +}; + +let validNetworks: null | string[] = null; +let lastFetched: number = 0; +const CACHE_DURATION = 60 * 60 * 1000; // 1 hour in milliseconds + +export async function getValidRpc(network: string) { + const now = Date.now(); + + if (!validNetworks || now - lastFetched > CACHE_DURATION) { + const res = await axios.get(`${env.RPC_PROXY_HOST}/api/rpc`, { + headers: { + Authorization: `Bearer ${env.RPC_PROXY_TOKEN}`, + }, + }); + validNetworks = res.data; + lastFetched = now; + } + + if (validNetworks!.includes(network)) { + return getRpc(network); + } + + return null; +} diff --git a/src/services/slack-monitor.ts b/src/services/slack-monitor.ts new file mode 100644 index 00000000..1369cef7 --- /dev/null +++ b/src/services/slack-monitor.ts @@ -0,0 +1,72 @@ +import cron from 'node-cron'; +import axios from 'axios'; +import { env } from '../env'; +import { logger } from '../utils/logger'; +import { getStatsSummary, checkStanding, getLagStats } from './stats-service'; + +let lastSentAt = 0; + +function formatNumber(n: number): string { + return n.toLocaleString('en-US'); +} + +function buildSummary(): string { + const stats = getStatsSummary(); + const standing = checkStanding(); + const lag = getLagStats(); + + const network = env.RUNNER_NETWORK; + const health = standing.status; + const icon = health === 'healthy' ? ':large_green_circle:' : ':red_circle:'; + + const lines: string[] = [ + `${icon} *Runner Summary — ${network}*`, + `Health: ${health} | Rules: ${stats.total_healthy_rules}/${stats.total_rules_available} healthy | Uptime: ${stats.uptime.uptime_human}`, + `Block lag: ${lag.block_lag_seconds}s | Tick lag: ${lag.tick_lag_seconds}s | Caught up: ${lag.is_caught_up ? 'yes' : 'no'}`, + `Memory: Heap ${stats.memory.heap_used_mb}MB / RSS ${stats.memory.rss_mb}MB`, + `Block: ${formatNumber(stats.block.total_tasks)} processed, avg ${stats.block.average_processing_time.toFixed(1)}ms, ${stats.block.success_rate.toFixed(1)}% success`, + `Tick: ${formatNumber(stats.tick.total_tasks)} processed, avg ${stats.tick.average_processing_time.toFixed(1)}ms, ${stats.tick.success_rate.toFixed(1)}% success`, + `Events emitted: ${formatNumber(stats.total_events_emitted)}`, + ]; + + const blockedRules = stats.details.filter((d) => d.status === 'blocked'); + if (blockedRules.length > 0) { + lines.push(''); + lines.push( + `*Blocked rules:* ${blockedRules.map((r) => `\`${r.alert_rule_id}\``).join(', ')}` + ); + + const errors = blockedRules.flatMap((r) => r.last_3_errors).filter(Boolean); + if (errors.length > 0) { + const unique = [...new Set(errors)].slice(0, 5); + lines.push(`Recent errors:\n${unique.map((e) => `> ${e}`).join('\n')}`); + } + } + + return lines.join('\n'); +} + +export function startSlackMonitor() { + const webhookUrl = env.SLACK_WEBHOOK_URL; + if (!webhookUrl) return; + + const intervalMs = env.SLACK_ALERT_INTERVAL_HR * 60 * 60 * 1000; + + logger.info( + `Slack monitor enabled — summary every ${env.SLACK_ALERT_INTERVAL_HR}h` + ); + + cron.schedule('* * * * *', async () => { + const now = Date.now(); + if (now - lastSentAt < intervalMs) return; + + try { + const text = buildSummary(); + await axios.post(webhookUrl, { text }, { timeout: 10_000 }); + lastSentAt = now; + logger.info('Slack summary sent'); + } catch (err: any) { + logger.error(`Slack summary failed: ${err.message || err}`); + } + }); +} diff --git a/src/services/stats-service.ts b/src/services/stats-service.ts new file mode 100644 index 00000000..4b4579cf --- /dev/null +++ b/src/services/stats-service.ts @@ -0,0 +1,1310 @@ +import { IStat } from '../types/ITask'; +import { IAlertRule } from '../types/IAlertRule'; +import { IEvent } from '../types/IEvent'; +import { dayjs } from '../utils/dayjs'; +import cron from 'node-cron'; +import { logger } from '../utils/logger'; +import { axios } from './axios'; +import { env } from '../env'; +import * as fs from 'fs'; +import * as path from 'path'; + +// Constants - reduced to be more aggressive about memory cleanup +const MIN_SAMPLE_SIZE = 10; +const MAX_SAMPLE_SIZE = 10000; // Reduced from 2000 to limit memory usage +const STAT_CONSIDERATION_LIMIT = 60 * 60 * 1000; // 1 hour +const MAX_ALLOWED_TIMEOUTS = 2; +const HEALTHY_BLOCK_THRESHOLD_MS = 1_000; +const HEALTHY_TICK_THRESHOLD_MS = 10_000; + +/** + * Circular buffer for stats - avoids unbounded growth and GC pauses from splice() + */ +class CircularStatBuffer { + private buffer: (IStat | undefined)[]; + private writeIndex = 0; + private size = 0; + private readonly capacity: number; + + constructor(capacity = MAX_SAMPLE_SIZE) { + this.capacity = capacity; + this.buffer = new Array(capacity); + } + + push(stat: IStat) { + this.buffer[this.writeIndex] = stat; + this.writeIndex = (this.writeIndex + 1) % this.capacity; + if (this.size < this.capacity) this.size++; + } + + getSize(): number { + return this.size; + } + + toArray(): IStat[] { + if (this.size === 0) return []; + if (this.size < this.capacity) { + return this.buffer.slice(0, this.size) as IStat[]; + } + // Full buffer: return in chronological order + return [ + ...this.buffer.slice(this.writeIndex), + ...this.buffer.slice(0, this.writeIndex), + ] as IStat[]; + } + + // Filter stats by time - returns new array (doesn't modify buffer) + filterByTime(cutoffTime: dayjs.Dayjs): IStat[] { + return this.toArray().filter((stat) => + dayjs(stat.startedAt).isAfter(cutoffTime) + ); + } +} + +/** + * Slim JSONL writer — one line per task, only useful fields. + * Drops events[], error, waitTimeSpent, alertRuleId (in filename), blockInfo.network/time, tickInfo. + * Fields omitted when empty/zero to minimize line size. + */ +class StatLogger { + private buffer: { alertRuleId: string; line: string }[] = []; + private streams = new Map(); + private flushInterval: ReturnType | null = null; + private logsDir: string; + private isShuttingDown = false; + private readonly FLUSH_THRESHOLD = 100; + private readonly FLUSH_INTERVAL_MS = 1000; + + constructor() { + this.logsDir = env.STATS_LOG_DIR; + if (!fs.existsSync(this.logsDir)) { + fs.mkdirSync(this.logsDir, { recursive: true }); + } + } + + start() { + if (!this.flushInterval) { + this.flushInterval = setInterval( + () => this.flush(), + this.FLUSH_INTERVAL_MS + ); + } + } + + log(alertRuleId: string, stat: IStat) { + if (this.isShuttingDown) return; + + const slim: Record = { + ts: new Date(stat.startedAt).getTime(), + s: stat.status, + pt: stat.threadTimeSpent, + }; + if (stat.eventCount > 0) slim.ec = stat.eventCount; + if (stat.blockInfo) slim.h = stat.blockInfo.height; + if (stat.events?.length > 0) slim.ev = stat.events; + if (stat.error) slim.err = stat.error; + + const line = JSON.stringify(slim) + '\n'; + this.buffer.push({ alertRuleId, line }); + if (this.buffer.length >= this.FLUSH_THRESHOLD) { + this.flush(); + } + } + + private getStream(alertRuleId: string): fs.WriteStream { + if (!this.streams.has(alertRuleId)) { + const filePath = path.join(this.logsDir, `${alertRuleId}.jsonl`); + const stream = fs.createWriteStream(filePath, { flags: 'a' }); + this.streams.set(alertRuleId, stream); + } + return this.streams.get(alertRuleId)!; + } + + private flush() { + if (this.buffer.length === 0) return; + + const grouped = new Map(); + for (const item of this.buffer) { + if (!grouped.has(item.alertRuleId)) { + grouped.set(item.alertRuleId, []); + } + grouped.get(item.alertRuleId)!.push(item.line); + } + + this.buffer = []; + + for (const [alertRuleId, lines] of grouped) { + const stream = this.getStream(alertRuleId); + stream.write(lines.join('')); + } + } + + private async closeStreams(): Promise { + const closePromises: Promise[] = []; + for (const stream of this.streams.values()) { + closePromises.push( + new Promise((resolve) => { + stream.end(() => resolve()); + }) + ); + } + await Promise.all(closePromises); + this.streams.clear(); + } + + /** Remove lines older than STAT_RETENTION_DAYS from all JSONL files */ + async compact(): Promise { + const retentionMs = env.STAT_RETENTION_DAYS * 86_400_000; + const cutoff = Date.now() - retentionMs; + + await this.closeStreams(); + + const files = fs + .readdirSync(this.logsDir) + .filter((f: string) => f.endsWith('.jsonl')); + let totalRemoved = 0; + let totalKept = 0; + + for (const file of files) { + const filePath = path.join(this.logsDir, file); + try { + const content = fs.readFileSync(filePath, 'utf8'); + const lines = content.split('\n').filter((l: string) => l.trim()); + const kept: string[] = []; + + for (const line of lines) { + try { + const parsed = JSON.parse(line); + // New format uses ts, legacy uses startedAt + const ts = parsed.ts ?? new Date(parsed.startedAt).getTime(); + if (ts >= cutoff) { + kept.push(line); + } else { + totalRemoved++; + } + } catch { + totalRemoved++; + } + } + + totalKept += kept.length; + fs.writeFileSync( + filePath, + kept.length > 0 ? kept.join('\n') + '\n' : '' + ); + } catch { + // Skip files that can't be read + } + } + + if (totalKept > 0 || totalRemoved > 0) { + logger.info( + `Stats compaction: kept ${totalKept} lines, removed ${totalRemoved} lines across ${files.length} files` + ); + } + } + + async shutdown(): Promise { + this.isShuttingDown = true; + if (this.flushInterval) { + clearInterval(this.flushInterval); + this.flushInterval = null; + } + this.flush(); + await this.closeStreams(); + } +} + +// Singleton stat logger instance +const statLogger = new StatLogger(); + +// State - using circular buffers instead of unbounded arrays +export const statMap: Map = new Map(); +let statQueue: IStat[] = []; +let blockRuleList: IAlertRule[] = []; +let tickRuleList: IAlertRule[] = []; + +// Track when blocks and ticks are received (not processed) +let lastBlockReceivedAt: number | null = null; +let lastTickReceivedAt: number | null = null; +let lastBlockHeight: number | null = null; +let lastBlockTime: string | null = null; +let lastTickTime: string | null = null; + +// Service start time for uptime tracking +const serviceStartedAt = Date.now(); + +// Memory history for time series (sampled every 10 seconds, keep 1 hour) +interface IMemorySample { + timestamp: number; + heap_mb: number; + rss_mb: number; +} +const memoryHistory: IMemorySample[] = []; +const MEMORY_SAMPLE_INTERVAL = 10_000; // 10 seconds +const MEMORY_HISTORY_MAX = 360; // 1 hour at 10s intervals + +function sampleMemory() { + const mem = process.memoryUsage(); + memoryHistory.push({ + timestamp: Date.now(), + heap_mb: Math.round((mem.heapUsed / 1024 / 1024) * 100) / 100, + rss_mb: Math.round((mem.rss / 1024 / 1024) * 100) / 100, + }); + if (memoryHistory.length > MEMORY_HISTORY_MAX) { + memoryHistory.shift(); + } +} + +// Export memory history for time series +export function getMemoryHistory(): IMemorySample[] { + return memoryHistory; +} + +// Periodic cleanup to prevent memory leaks +let lastCleanupTime = Date.now(); +const CLEANUP_INTERVAL = 2 * 60 * 1000; // Every 2 minutes + +// Stats cache for getStatsSummary() +let statsCache: IStatsSummary | null = null; +let statsCacheTime = 0; +const STATS_CACHE_TTL = 5000; // 5 seconds + +// Core stat management functions +export function registerTaskResult(stat: IStat) { + // Invalidate stats cache when new stats arrive + statsCache = null; + + statQueue.push(stat); + + if (!statMap.has(stat.alertRuleId)) { + statMap.set(stat.alertRuleId, new CircularStatBuffer()); + } + + const statsBuffer = statMap.get(stat.alertRuleId)!; + statsBuffer.push(stat); + + // Circular buffer handles size limits automatically - no splice needed + + // Log to JSONL file asynchronously (non-blocking) + statLogger.log(stat.alertRuleId, stat); + + // Trigger cleanup if enough time has passed + const now = Date.now(); + if (now - lastCleanupTime > CLEANUP_INTERVAL) { + process.nextTick(() => { + cleanupStatQueue(); + }); + lastCleanupTime = now; + } +} + +export function showStats() { + for (const key of statMap.keys()) { + const statsBuffer = statMap.get(key)!; + const stats = statsBuffer.toArray(); + if (stats.length === 0) { + continue; + } + + const isHealthy = isHealthyBlockRule(stats); + if (!isHealthy) { + const blockedUntil = dayjs(stats[stats.length - 1].startedAt).add( + STAT_CONSIDERATION_LIMIT, + 'ms' + ); + + logger.warn( + `Alert rule ${key} is blocked, unlocking in ${dayjs(blockedUntil).fromNow(true)}` + ); + continue; + } + + const totalTime = stats.reduce( + (acc, curr) => acc + curr.threadTimeSpent, + 0 + ); + const total = stats.length; + const avgTimeElapsed = totalTime / total; + // logger.info(`Alert rule ${key} is healthy, avg time: ${avgTimeElapsed}ms`); + } +} + +function trimStats() { + // With circular buffers, we don't need to trim by size. + // Just remove rules that have no recent stats (inactive rules). + const keysToDelete: string[] = []; + + for (const ruleId of statMap.keys()) { + const statsBuffer = statMap.get(ruleId)!; + if (statsBuffer.getSize() === 0) { + keysToDelete.push(ruleId); + } + } + + // Batch delete empty entries + keysToDelete.forEach((key) => statMap.delete(key)); +} + +function cleanupStatQueue() { + // Keep only recent stats in the queue to prevent unbounded growth + const maxQueueSize = 1000; + if (statQueue.length > maxQueueSize) { + statQueue = statQueue.slice(-maxQueueSize); + } +} + +// Health check functions - optimized to avoid unnecessary object creation +function isHealthyBlockRule(stats: IStat[] | undefined): boolean { + if (!stats) return true; + + // Count timeouts more efficiently + let timeoutCount = 0; + let totalTime = 0; + + for (const stat of stats) { + if (stat.status === 'timeout') { + timeoutCount++; + } + totalTime += stat.threadTimeSpent; + } + + if (timeoutCount >= MAX_ALLOWED_TIMEOUTS) { + return false; + } + + if (stats.length < MIN_SAMPLE_SIZE) return true; + + const avgTimeElapsed = totalTime / stats.length; + return avgTimeElapsed < HEALTHY_BLOCK_THRESHOLD_MS; +} + +function isHealthyTickRule(stats: IStat[] | undefined): boolean { + if (!stats) return true; + + let timeoutCount = 0; + let totalTime = 0; + + for (const stat of stats) { + if (stat.status === 'timeout') { + timeoutCount++; + } + totalTime += stat.threadTimeSpent; + } + + const avgTimeElapsed = totalTime / stats.length; + + if (timeoutCount >= MAX_ALLOWED_TIMEOUTS) { + return false; + } + + if (stats.length < MIN_SAMPLE_SIZE) return true; + + return avgTimeElapsed < HEALTHY_TICK_THRESHOLD_MS; +} + +// Rule management functions +export function getHealthyBlockRules() { + // Avoid calling trimStats on every call - let the periodic cleanup handle it + return blockRuleList.filter((e) => { + const buffer = statMap.get(e.id); + return isHealthyBlockRule(buffer?.toArray()); + }); +} + +export function getHealthyTickRules() { + // Avoid calling trimStats on every call - let the periodic cleanup handle it + return tickRuleList.filter((e) => { + const buffer = statMap.get(e.id); + return isHealthyTickRule(buffer?.toArray()); + }); +} + +export interface IBlockTickStats { + total_blocks_processed?: number; + total_ticks_processed?: number; + total_tasks: number; + total_tasks_completed: number; + total_tasks_cancelled_skipped: number; + total_events_emitted: number; + + average_processing_time: number; + success_rate: number; +} + +export interface IRuleDetail { + alert_rule_id: string; + trigger_mode: 'BLOCK' | 'TICK'; + // Block-specific fields (only present if trigger_mode === 'BLOCK') + block_total_tasks?: number; + block_total_tasks_completed?: number; + block_total_tasks_cancelled_skipped?: number; + block_total_events_emitted?: number; + + block_average_processing_time?: number; + // Tick-specific fields (only present if trigger_mode === 'TICK') + tick_total_tasks?: number; + tick_total_tasks_completed?: number; + tick_total_tasks_cancelled_skipped?: number; + tick_total_events_emitted?: number; + + tick_average_processing_time?: number; + status: 'healthy' | 'blocked'; + last_3_events: IEvent[]; + last_3_errors: string[]; +} + +export interface IMemoryStats { + rss_mb: number; + heap_used_mb: number; + heap_total_mb: number; + external_mb: number; + array_buffers_mb: number; +} + +export interface IStatsSummary { + block: IBlockTickStats; + tick: IBlockTickStats; + total_rules_available: number; + total_healthy_rules: number; + total_blocked_rules: number; + total_events_emitted: number; + memory: IMemoryStats; + uptime: IUptimeStats; + details: IRuleDetail[]; +} + +/** + * Get current memory usage statistics + */ +export function getMemoryStats(): IMemoryStats { + const memUsage = process.memoryUsage(); + return { + rss_mb: Math.round((memUsage.rss / 1024 / 1024) * 100) / 100, + heap_used_mb: Math.round((memUsage.heapUsed / 1024 / 1024) * 100) / 100, + heap_total_mb: Math.round((memUsage.heapTotal / 1024 / 1024) * 100) / 100, + external_mb: Math.round((memUsage.external / 1024 / 1024) * 100) / 100, + array_buffers_mb: + Math.round((memUsage.arrayBuffers / 1024 / 1024) * 100) / 100, + }; +} + +export function getStatsSummary(): IStatsSummary { + // Return cached stats if still valid + const now = Date.now(); + if (statsCache && now - statsCacheTime < STATS_CACHE_TTL) { + return statsCache; + } + + const result = computeStatsSummary(); + statsCache = result; + statsCacheTime = now; + return result; +} + +function computeStatsSummary(): IStatsSummary { + // Block-level stats + let totalBlocksProcessed = 0; + let blockTasksCompleted = 0; + let blockTasksCancelledSkipped = 0; + let blockEventsEmitted = 0; + let blockTotalWaitTime = 0; + let blockTotalProcessingTime = 0; + + // Tick-level stats + let totalTicksProcessed = 0; + let tickTasksCompleted = 0; + let tickTasksCancelledSkipped = 0; + let tickEventsEmitted = 0; + let tickTotalWaitTime = 0; + let tickTotalProcessingTime = 0; + + // Calculate rule statistics + const totalRulesAvailable = blockRuleList.length + tickRuleList.length; + const healthyBlockRules = getHealthyBlockRules(); + const healthyTickRules = getHealthyTickRules(); + const healthyRuleIds = new Set([ + ...healthyBlockRules.map((r) => r.id), + ...healthyTickRules.map((r) => r.id), + ]); + const totalHealthyRules = healthyRuleIds.size; + const totalBlockedRules = totalRulesAvailable - totalHealthyRules; + + // Build details for each rule and accumulate totals + const details: IRuleDetail[] = []; + const allRules = [...blockRuleList, ...tickRuleList]; + const blockRuleIds = new Set(blockRuleList.map((r) => r.id)); + const tickRuleIds = new Set(tickRuleList.map((r) => r.id)); + + for (const rule of allRules) { + const ruleId = rule.id; + const statsBuffer = statMap.get(ruleId); + const stats = statsBuffer?.toArray() || []; + const isBlockRule = blockRuleIds.has(ruleId); + const triggerMode: 'BLOCK' | 'TICK' = isBlockRule ? 'BLOCK' : 'TICK'; + + // Rule-level stats (unified - only one type per rule) + let ruleTasksCompleted = 0; + let ruleTasksCancelledSkipped = 0; + let ruleEventsEmitted = 0; + let ruleTotalWaitTime = 0; + let ruleTotalProcessingTime = 0; + let ruleTaskCount = 0; + + // Collect all events and errors chronologically + const allEvents: IEvent[] = []; + const allErrors: string[] = []; + + for (const stat of stats) { + // Only process stats that match the rule's trigger mode + if (isBlockRule && stat.blockInfo) { + totalBlocksProcessed++; + + // Count task statuses for blocks + if (stat.status === 'success') { + blockTasksCompleted++; + ruleTasksCompleted++; + } else if (stat.status === 'failure' || stat.status === 'timeout') { + blockTasksCancelledSkipped++; + ruleTasksCancelledSkipped++; + } + + // Sum block events + const eventCount = stat.eventCount || 0; + blockEventsEmitted += eventCount; + ruleEventsEmitted += eventCount; + + // Accumulate wait and processing times for blocks + blockTotalWaitTime += stat.waitTimeSpent || 0; + blockTotalProcessingTime += stat.threadTimeSpent || 0; + ruleTotalWaitTime += stat.waitTimeSpent || 0; + ruleTotalProcessingTime += stat.threadTimeSpent || 0; + ruleTaskCount++; + + // Collect events and errors for this rule + if (stat.events && stat.events.length > 0) { + allEvents.push(...stat.events); + } + if (stat.error) { + allErrors.push(stat.error); + } + } else if (!isBlockRule && stat.tickInfo) { + totalTicksProcessed++; + + // Count task statuses for ticks + if (stat.status === 'success') { + tickTasksCompleted++; + ruleTasksCompleted++; + } else if (stat.status === 'failure' || stat.status === 'timeout') { + tickTasksCancelledSkipped++; + ruleTasksCancelledSkipped++; + } + + // Sum tick events + const eventCount = stat.eventCount || 0; + tickEventsEmitted += eventCount; + ruleEventsEmitted += eventCount; + + // Accumulate wait and processing times for ticks + tickTotalWaitTime += stat.waitTimeSpent || 0; + tickTotalProcessingTime += stat.threadTimeSpent || 0; + ruleTotalWaitTime += stat.waitTimeSpent || 0; + ruleTotalProcessingTime += stat.threadTimeSpent || 0; + ruleTaskCount++; + + // Collect events and errors for this rule + if (stat.events && stat.events.length > 0) { + allEvents.push(...stat.events); + } + if (stat.error) { + allErrors.push(stat.error); + } + } + } + + // Get last 3 events and errors + const last3Events = allEvents.slice(-3); + const last3Errors = allErrors.slice(-3); + + // Determine if rule is healthy or blocked + const isHealthy = healthyRuleIds.has(ruleId); + const status: 'healthy' | 'blocked' = isHealthy ? 'healthy' : 'blocked'; + + // Calculate averages for rule + const ruleAvgWaitTime = + ruleTaskCount > 0 ? ruleTotalWaitTime / ruleTaskCount : 0; + const ruleAvgProcessingTime = + ruleTaskCount > 0 ? ruleTotalProcessingTime / ruleTaskCount : 0; + + // Build rule detail based on trigger mode + const ruleDetail: IRuleDetail = { + alert_rule_id: ruleId, + trigger_mode: triggerMode, + status, + last_3_events: last3Events, + last_3_errors: last3Errors, + }; + + if (triggerMode === 'BLOCK') { + ruleDetail.block_total_tasks = + ruleTasksCompleted + ruleTasksCancelledSkipped; + ruleDetail.block_total_tasks_completed = ruleTasksCompleted; + ruleDetail.block_total_tasks_cancelled_skipped = + ruleTasksCancelledSkipped; + ruleDetail.block_total_events_emitted = ruleEventsEmitted; + ruleDetail.block_average_processing_time = ruleAvgProcessingTime; + } else { + ruleDetail.tick_total_tasks = + ruleTasksCompleted + ruleTasksCancelledSkipped; + ruleDetail.tick_total_tasks_completed = ruleTasksCompleted; + ruleDetail.tick_total_tasks_cancelled_skipped = ruleTasksCancelledSkipped; + ruleDetail.tick_total_events_emitted = ruleEventsEmitted; + ruleDetail.tick_average_processing_time = ruleAvgProcessingTime; + } + + details.push(ruleDetail); + } + + // Total tasks = total blocks/ticks processed (each task execution) + const blockTotalTasks = totalBlocksProcessed; + const tickTotalTasks = totalTicksProcessed; + + // Calculate averages for block and tick stats + const blockAvgWaitTime = + blockTotalTasks > 0 ? blockTotalWaitTime / blockTotalTasks : 0; + const blockAvgProcessingTime = + blockTotalTasks > 0 ? blockTotalProcessingTime / blockTotalTasks : 0; + const tickAvgWaitTime = + tickTotalTasks > 0 ? tickTotalWaitTime / tickTotalTasks : 0; + const tickAvgProcessingTime = + tickTotalTasks > 0 ? tickTotalProcessingTime / tickTotalTasks : 0; + + // Calculate success rates (completed / total * 100) + const blockSuccessRate = + blockTotalTasks > 0 ? (blockTasksCompleted / blockTotalTasks) * 100 : 0; + const tickSuccessRate = + tickTotalTasks > 0 ? (tickTasksCompleted / tickTotalTasks) * 100 : 0; + + return { + block: { + total_blocks_processed: totalBlocksProcessed, + total_tasks: blockTotalTasks, + total_tasks_completed: blockTasksCompleted, + total_tasks_cancelled_skipped: blockTasksCancelledSkipped, + total_events_emitted: blockEventsEmitted, + average_processing_time: blockAvgProcessingTime, + success_rate: blockSuccessRate, + }, + tick: { + total_ticks_processed: totalTicksProcessed, + total_tasks: tickTotalTasks, + total_tasks_completed: tickTasksCompleted, + total_tasks_cancelled_skipped: tickTasksCancelledSkipped, + total_events_emitted: tickEventsEmitted, + average_processing_time: tickAvgProcessingTime, + success_rate: tickSuccessRate, + }, + total_rules_available: totalRulesAvailable, + total_healthy_rules: totalHealthyRules, + total_blocked_rules: totalBlockedRules, + total_events_emitted: blockEventsEmitted + tickEventsEmitted, + memory: getMemoryStats(), + uptime: getUptimeStats(), + details, + }; +} + +// Functions to track when blocks and ticks are received +export function recordBlockReceived(height?: number, blockTime?: string) { + lastBlockReceivedAt = Date.now(); + if (height !== undefined) lastBlockHeight = height; + if (blockTime) lastBlockTime = blockTime; +} + +export function recordTickReceived(tickTime?: string) { + lastTickReceivedAt = Date.now(); + if (tickTime) lastTickTime = tickTime; +} + +// Uptime tracking +export interface IUptimeStats { + started_at: string; + uptime_seconds: number; + uptime_human: string; +} + +function formatUptime(seconds: number): string { + const days = Math.floor(seconds / 86400); + const hours = Math.floor((seconds % 86400) / 3600); + const minutes = Math.floor((seconds % 3600) / 60); + + const parts: string[] = []; + if (days > 0) parts.push(`${days}d`); + if (hours > 0) parts.push(`${hours}h`); + if (minutes > 0 || parts.length === 0) parts.push(`${minutes}m`); + + return parts.join(' '); +} + +export function getUptimeStats(): IUptimeStats { + const uptimeSeconds = Math.floor((Date.now() - serviceStartedAt) / 1000); + return { + started_at: dayjs(serviceStartedAt).toISOString(), + uptime_seconds: uptimeSeconds, + uptime_human: formatUptime(uptimeSeconds), + }; +} + +// Lag tracking +export interface ILagStats { + block_lag_seconds: number; + tick_lag_seconds: number; + last_block_height: number | null; + last_block_time: string | null; + last_tick_time: string | null; + last_block_received_at: string | null; + last_tick_received_at: string | null; + is_caught_up: boolean; +} + +export function getLagStats(): ILagStats { + const now = Date.now(); + const blockLagSeconds = lastBlockReceivedAt + ? Math.floor((now - lastBlockReceivedAt) / 1000) + : -1; + const tickLagSeconds = lastTickReceivedAt + ? Math.floor((now - lastTickReceivedAt) / 1000) + : -1; + + // Caught up if block lag < 30s and tick lag < 2min + const isCaughtUp = + blockLagSeconds >= 0 && + blockLagSeconds < 30 && + tickLagSeconds >= 0 && + tickLagSeconds < 120; + + return { + block_lag_seconds: blockLagSeconds, + tick_lag_seconds: tickLagSeconds, + last_block_height: lastBlockHeight, + last_block_time: lastBlockTime, + last_tick_time: lastTickTime, + last_block_received_at: lastBlockReceivedAt + ? dayjs(lastBlockReceivedAt).toISOString() + : null, + last_tick_received_at: lastTickReceivedAt + ? dayjs(lastTickReceivedAt).toISOString() + : null, + is_caught_up: isCaughtUp, + }; +} + +export function checkStanding() { + const now = Date.now(); + const BLOCK_THRESHOLD_MS = 30 * 1000; // 30 seconds + const TICK_THRESHOLD_MS = 2 * 60 * 1000; // 2 minutes + + // Check if we have recent block and tick reception (not processing) + const hasRecentBlock = + lastBlockReceivedAt !== null && + now - lastBlockReceivedAt <= BLOCK_THRESHOLD_MS; + const hasRecentTick = + lastTickReceivedAt !== null && + now - lastTickReceivedAt <= TICK_THRESHOLD_MS; + + const ok = hasRecentBlock && hasRecentTick; + + return { + status: ok ? 'healthy' : 'unhealthy', + last_block_received_at: lastBlockReceivedAt + ? dayjs(lastBlockReceivedAt).toISOString() + : undefined, + last_tick_received_at: lastTickReceivedAt + ? dayjs(lastTickReceivedAt).toISOString() + : undefined, + }; +} + +export async function fetchRules(testAlertRules: IAlertRule[]) { + if (env.NODE_ENV === 'local' && testAlertRules?.length) { + blockRuleList = testAlertRules.filter((e) => e.triggerMode === 'BLOCK'); + tickRuleList = testAlertRules.filter((e) => e.triggerMode === 'TICK'); + return; + } + + try { + const res = await axios.get(env.FETCH_RULE_ENDPOINT, { + headers: { + Authorization: `Bearer ${env.RANGE_SDK_TOKEN}`, + }, + }); + + const rules = res.data.rules; + + blockRuleList = rules.filter((e: IAlertRule) => e.triggerMode === 'BLOCK'); + tickRuleList = rules.filter((e: IAlertRule) => e.triggerMode === 'TICK'); + + if (!blockRuleList.length && !tickRuleList.length) { + logger.error('No rules found'); + throw new Error('No rules found'); + } + + logger.info( + `Fetched ${blockRuleList.length} block rules and ${tickRuleList.length} tick rules` + ); + } catch (error) { + logger.error('Error fetching rules:', error); + throw error; + } +} + +// --- Named cron callbacks (started by initStatsSchedulers) --- + +function runStatsCleanup() { + try { + trimStats(); + cleanupStatQueue(); + if (global.gc) { + global.gc(); + } + logger.debug( + `Stats cleanup completed. Active rules: ${statMap.size}, Queue size: ${statQueue.length}` + ); + } catch (error) { + logger.error('Error during stats cleanup:', error); + } +} + +async function runDailyCompaction() { + try { + await statLogger.compact(); + } catch (err) { + logger.error('Daily compaction failed:', err); + } +} + +let lastMemoryReport = Date.now(); +function runMemoryReport() { + const now = Date.now(); + if (now - lastMemoryReport > 5 * 60 * 1000) { + const memUsage = process.memoryUsage(); + logger.info( + `Memory: RSS=${(memUsage.rss / 1024 / 1024).toFixed(0)}MB, Heap=${(memUsage.heapUsed / 1024 / 1024).toFixed(0)}MB, Stats=${statMap.size} rules` + ); + lastMemoryReport = now; + } +} + +// --- Scheduler lifecycle --- + +type ScheduledTask = ReturnType; + +const cronTasks: ScheduledTask[] = []; +let memorySamplerHandle: ReturnType | null = null; +let showStatsHandle: ReturnType | null = null; + +export function initStatsSchedulers() { + if (env.NODE_ENV === 'test') return; + + statLogger.start(); + statLogger + .compact() + .catch((err) => logger.error('Startup compaction failed:', err)); + + cronTasks.push( + cron.schedule('*/2 * * * *', runStatsCleanup), + cron.schedule('59 23 * * *', runDailyCompaction), + cron.schedule('*/5 * * * *', runMemoryReport), + cron.schedule('*/1 * * * *', runStatsUpload) + ); + + memorySamplerHandle = setInterval(sampleMemory, MEMORY_SAMPLE_INTERVAL); + showStatsHandle = setInterval(showStats, 60 * 1000); +} + +export function stopStatsSchedulers() { + for (const task of cronTasks) { + task.stop(); + } + cronTasks.length = 0; + + if (memorySamplerHandle) { + clearInterval(memorySamplerHandle); + memorySamplerHandle = null; + } + if (showStatsHandle) { + clearInterval(showStatsHandle); + showStatsHandle = null; + } +} + +export async function shutdownStatsService(): Promise { + stopStatsSchedulers(); + await statLogger.shutdown(); +} + +interface ITaskExecution { + network: string | null; + height: string | null; + processorId: string; + totalEvents: number; + steps: string[]; + error: string | undefined; + input: { + timestamp: string; + runner: string; + }; + metadata_indexed: { + uploadedAt: string; + source: string; + uniqueId: string; + }; + environment: string; +} + +async function upload() { + if (env.NODE_ENV === 'local') return; + if (!statQueue.length) return; + + const copiedStatList = [...statQueue]; + statQueue = []; + + const statList: ITaskExecution[] = copiedStatList.map((e) => { + return { + environment: env.NODE_ENV, + error: e.error, + height: e.blockInfo?.height || null, + input: { + timestamp: (e.blockInfo?.time || e.tickInfo?.time)!, + runner: env.RUNNER_ID, + }, + metadata_indexed: { + source: 'cron-upload', + uniqueId: '', + uploadedAt: dayjs().toISOString(), + }, + network: e.blockInfo?.network || null, + processorId: e.alertRuleId, + steps: [], + totalEvents: e.eventCount, + }; + }); + + const url = `${env.MONITORING_SERVER_URL}/block-engine/${env.NODE_ENV}/blocks/evaluations`; + + // Upload in batches of 50 + const BATCH_SIZE = 50; + let totalUploaded = 0; + + for (let i = 0; i < statList.length; i += BATCH_SIZE) { + const batch = statList.slice(i, i + BATCH_SIZE); + + try { + await axios.post(url, batch, { + headers: { + Authorization: `Bearer ${env.MONITORING_SERVER_TOKEN}`, + }, + timeout: 30_000, + }); + + totalUploaded += batch.length; + } catch (err: any) { + logger.error(`Stats upload failed: ${err.message || err}`); + return; + } + } + + logger.info( + `Uploaded ${totalUploaded} stats in ${Math.ceil(statList.length / BATCH_SIZE)} batch(es)` + ); +} + +async function runStatsUpload() { + await upload(); +} + +// Time series data types +export type TimeSeriesMetric = + | 'events_per_minute' + | 'block_avg_processing_time' + | 'tick_avg_processing_time' + | 'throughput_tasks' + | 'success_rate' + | 'memory_heap'; + +export interface ITimeSeriesPoint { + timestamp: string; // ISO timestamp + value: number; +} + +export interface ITimeSeriesResponse { + metric: TimeSeriesMetric; + interval: string; // e.g., "1m", "5m" + data: ITimeSeriesPoint[]; + frames?: any[]; // Optional frames array for Grafana compatibility +} + +/** + * Read and aggregate stats from JSONL log files for time series + */ +export function getTimeSeriesData( + metric: TimeSeriesMetric, + intervalMinutes: number = 1, + durationMinutes: number = 60 +): ITimeSeriesResponse { + const logsDir = env.STATS_LOG_DIR; + + if (!fs.existsSync(logsDir)) { + return { + metric, + interval: `${intervalMinutes}m`, + data: [], + }; + } + + // Calculate time range + const now = dayjs(); + const startTime = now.subtract(durationMinutes, 'minutes'); + const intervalMs = intervalMinutes * 60 * 1000; + + // Initialize time buckets + const buckets: Map< + number, + { + count: number; + sum: number; + events: number; + success: number; + failed: number; + } + > = new Map(); + const numBuckets = Math.ceil(durationMinutes / intervalMinutes); + + for (let i = 0; i < numBuckets; i++) { + const bucketTime = startTime.add(i * intervalMinutes, 'minutes'); + const bucketKey = bucketTime.startOf('minute').valueOf(); + buckets.set(bucketKey, { + count: 0, + sum: 0, + events: 0, + success: 0, + failed: 0, + }); + } + + // For memory_heap metric, use memory history instead of JSONL + if (metric === 'memory_heap') { + const data: ITimeSeriesPoint[] = memoryHistory + .filter((sample) => { + const sampleTime = dayjs(sample.timestamp); + return sampleTime.isAfter(startTime) && sampleTime.isBefore(now); + }) + .map((sample) => ({ + timestamp: dayjs(sample.timestamp).toISOString(), + value: sample.heap_mb, + })); + + return { + metric, + interval: `${intervalMinutes}m`, + data, + frames: [ + { + schema: { + fields: [ + { name: 'Time', type: 'time' }, + { name: 'Value', type: 'number' }, + ], + }, + data: { + values: [ + data.map((d) => new Date(d.timestamp).getTime()), + data.map((d) => d.value), + ], + }, + }, + ], + }; + } + + // Read all JSONL files (supports both new aggregated and legacy IStat formats) + const files = fs + .readdirSync(logsDir) + .filter((file: string) => file.endsWith('.jsonl')); + + for (const file of files) { + const filePath = path.join(logsDir, file); + try { + const content = fs.readFileSync(filePath, 'utf8'); + const lines = content.split('\n').filter((line: string) => line.trim()); + + for (const line of lines) { + try { + const parsed = JSON.parse(line); + const isSlim = 'ts' in parsed; + + // Determine timestamp + const ts = isSlim ? parsed.ts : new Date(parsed.startedAt).getTime(); + if (ts < startTime.valueOf() || ts > now.valueOf()) continue; + + const bucketKey = Math.floor(ts / 60_000) * 60_000; + if (!buckets.has(bucketKey)) { + buckets.set(bucketKey, { + count: 0, + sum: 0, + events: 0, + success: 0, + failed: 0, + }); + } + const bucket = buckets.get(bucketKey)!; + + if (isSlim) { + // New slim format: {ts, s, pt, ec?, h?, ev?, err?} + switch (metric) { + case 'events_per_minute': + bucket.events += parsed.ec || 0; + bucket.count += 1; + break; + case 'block_avg_processing_time': + if (parsed.h !== undefined) { + bucket.sum += parsed.pt || 0; + bucket.count += 1; + } + break; + case 'tick_avg_processing_time': + if (parsed.h === undefined) { + bucket.sum += parsed.pt || 0; + bucket.count += 1; + } + break; + case 'throughput_tasks': + bucket.count += 1; + break; + case 'success_rate': + bucket.count += 1; + if (parsed.s === 'success') { + bucket.success += 1; + } else { + bucket.failed += 1; + } + break; + } + } else { + // Legacy format: full IStat + const stat = parsed as IStat; + switch (metric) { + case 'events_per_minute': + bucket.events += stat.eventCount || 0; + bucket.count += 1; + break; + case 'block_avg_processing_time': + if (stat.blockInfo) { + bucket.sum += stat.threadTimeSpent || 0; + bucket.count += 1; + } + break; + case 'tick_avg_processing_time': + if (stat.tickInfo) { + bucket.sum += stat.threadTimeSpent || 0; + bucket.count += 1; + } + break; + case 'throughput_tasks': + bucket.count += 1; + break; + case 'success_rate': + bucket.count += 1; + if (stat.status === 'success') { + bucket.success += 1; + } else { + bucket.failed += 1; + } + break; + } + } + } catch { + continue; + } + } + } catch { + continue; + } + } + + // Convert buckets to time series points + const data: ITimeSeriesPoint[] = Array.from(buckets.entries()) + .sort(([a], [b]) => a - b) + .map(([timestamp, bucket]) => { + let value = 0; + + switch (metric) { + case 'events_per_minute': + // Total events in this bucket divided by interval minutes + value = bucket.count > 0 ? bucket.events / intervalMinutes : 0; + break; + + case 'block_avg_processing_time': + case 'tick_avg_processing_time': + // Average processing time in this bucket + value = bucket.count > 0 ? bucket.sum / bucket.count : 0; + break; + + case 'throughput_tasks': + // Tasks per minute + value = bucket.count / intervalMinutes; + break; + + case 'success_rate': + // Success rate as percentage + value = + bucket.count > 0 ? (bucket.success / bucket.count) * 100 : 100; + break; + } + + return { + timestamp: dayjs(timestamp).toISOString(), + value: Math.round(value * 100) / 100, // Round to 2 decimal places + }; + }) + .filter((point) => { + // Only include buckets that have data (except for metrics where 0 is valid) + return ( + point.value > 0 || + metric === 'events_per_minute' || + metric === 'throughput_tasks' || + metric === 'success_rate' + ); + }); + + // Return in format compatible with Grafana JSON API plugin + // The plugin expects an array of objects with timestamp and value fields + return { + metric, + interval: `${intervalMinutes}m`, + data, + // Also provide a frames array for better Grafana compatibility + frames: [ + { + schema: { + fields: [ + { + name: 'Time', + type: 'time', + }, + { + name: 'Value', + type: 'number', + }, + ], + }, + data: { + values: [ + data.map((d) => new Date(d.timestamp).getTime()), + data.map((d) => d.value), + ], + }, + }, + ], + }; +} diff --git a/src/services/taskAck.ts b/src/services/taskAck.ts deleted file mode 100644 index 1253bae1..00000000 --- a/src/services/taskAck.ts +++ /dev/null @@ -1,81 +0,0 @@ -import axios from 'axios'; -import { constants } from '../constants'; - -export async function taskAck(args: { - token: string; - block: { - network: string; - height: string; - }; - ruleGroupId: string; - runnerId: string; - alertEventsCount: number; - alertRulesIds: string[]; - errors?: { - ruleId: string; - error: string; - }[]; - rateLimitedAlertRuleIds?: string[]; - execPausedAlertRuleIds?: string[]; -}): Promise<{ ackId: string }> { - const { - token, - block, - ruleGroupId, - runnerId, - errors, - alertEventsCount, - alertRulesIds, - rateLimitedAlertRuleIds, - execPausedAlertRuleIds, - } = args; - const url = `${constants.MANAGER_SERVICE.DOMAIN}${constants.MANAGER_SERVICE.ACK_TASK_PATH}`; - - const { data } = await axios.post<{ ackId: string }>( - url, - { - block: block, - ruleGroupId: ruleGroupId, - runnerId, - alertEventsCount, - alertRulesIds, - ...(errors?.length ? { errors } : {}), - ...(rateLimitedAlertRuleIds?.length ? { rateLimitedAlertRuleIds } : {}), - ...(execPausedAlertRuleIds?.length ? { execPausedAlertRuleIds } : {}), - }, - { - headers: { - 'X-API-KEY': token, - }, - timeout: constants.AXIOS.TIMEOUT, - }, - ); - - return data; -} - -export async function errorTaskAck(args: { - token: string; - errorId: string; - error?: string; - retry: boolean; -}) { - const { token, errorId, error, retry } = args; - const url = `${constants.MANAGER_SERVICE.DOMAIN}${constants.MANAGER_SERVICE.ACK_ERROR_TASK_PATH}`; - - const { data } = await axios.patch<{ success: boolean }>( - url, - { - errorId, - ...(error && { error }), - retry, - }, - { - headers: { - 'X-API-KEY': token, - }, - }, - ); - - return data; -} diff --git a/src/services/tickTaskAck.ts b/src/services/tickTaskAck.ts deleted file mode 100644 index ed6d2bfe..00000000 --- a/src/services/tickTaskAck.ts +++ /dev/null @@ -1,37 +0,0 @@ -import axios from 'axios'; -import { constants } from '../constants'; - -export async function tickTaskAck(args: { - token: string; - timestamp: string; - ruleGroupId: string; - runnerId: string; - alertEventsCount: number; - errors?: { - ruleId: string; - error: string; - }[]; -}): Promise<{ ackId: string }> { - const { token, timestamp, ruleGroupId, runnerId, errors, alertEventsCount } = - args; - const url = `${constants.MANAGER_SERVICE.DOMAIN}${constants.MANAGER_SERVICE.ACK_TICK_TASK_PATH}`; - - const { data } = await axios.post<{ ackId: string }>( - url, - { - timestamp, - ruleGroupId, - runnerId, - alertEventsCount, - ...(errors?.length ? { errors } : {}), - }, - { - headers: { - 'X-API-KEY': token, - }, - timeout: constants.AXIOS.TIMEOUT, - }, - ); - - return data; -} diff --git a/src/start.ts b/src/start.ts new file mode 100644 index 00000000..14f36b51 --- /dev/null +++ b/src/start.ts @@ -0,0 +1,78 @@ +import { config } from 'dotenv'; +config({ + quiet: true, +}); + +import { startRunner } from './threadpool/runner'; +import { join } from 'path'; + +async function main() { + const testAlertRules: any[] = [ + // 10 BLOCK rules (9 healthy + 1 hang) + { + ruleType: 'PercBasedBenchmark', + parameters: { perc: 100 }, + triggerMode: 'BLOCK', + }, + { ruleType: 'EmptyRule', parameters: {}, triggerMode: 'BLOCK' }, + { ruleType: 'EmptyRule', parameters: {}, triggerMode: 'BLOCK' }, + { ruleType: 'EmptyRule', parameters: {}, triggerMode: 'BLOCK' }, + { ruleType: 'BlockLiveness', parameters: {}, triggerMode: 'BLOCK' }, + { ruleType: 'BlockLiveness', parameters: {}, triggerMode: 'BLOCK' }, + { ruleType: 'EmptyRule', parameters: {}, triggerMode: 'BLOCK' }, + { ruleType: 'EmptyRule', parameters: {}, triggerMode: 'BLOCK' }, + { ruleType: 'EmptyRule', parameters: {}, triggerMode: 'BLOCK' }, + { ruleType: 'Hang', parameters: {}, triggerMode: 'BLOCK' }, // Faulty - will timeout + + // 10 TICK rules (9 healthy + 1 hang) + { ruleType: 'TickLiveness', parameters: {}, triggerMode: 'TICK' }, + { ruleType: 'EmptyRuleTick', parameters: {}, triggerMode: 'TICK' }, + { ruleType: 'EmptyRuleTick', parameters: {}, triggerMode: 'TICK' }, + { ruleType: 'EmptyRuleTick', parameters: {}, triggerMode: 'TICK' }, + { ruleType: 'EmptyRuleTick', parameters: {}, triggerMode: 'TICK' }, + { ruleType: 'EmptyRuleTick', parameters: {}, triggerMode: 'TICK' }, + { ruleType: 'EmptyRuleTick', parameters: {}, triggerMode: 'TICK' }, + { ruleType: 'EmptyRuleTick', parameters: {}, triggerMode: 'TICK' }, + { ruleType: 'EmptyRuleTick', parameters: {}, triggerMode: 'TICK' }, + { ruleType: 'HangTick', parameters: {}, triggerMode: 'TICK' }, // Faulty - will timeout + ]; + + testAlertRules.forEach((e: any, i) => { + e.createdAt = new Date().toISOString(); + e.network = 'eth'; + e.id = i; + }); + + await startRunner({ + processors: join(__dirname, 'processors', 'processors.js'), + testAlertRules, + config: { + rangeSdkToken: process.env.RANGE_SDK_TOKEN!, + port: Number(process.env.PORT) || 3000, + redisUrl: process.env.BLOCK_REDIS_URL, + redis: { + tickUrl: process.env.TICK_REDIS_URL, + notificationsUrl: process.env.NOTIFICATIONS_REDIS_URL, + }, + blockStream: { + name: process.env.BLOCK_REDIS_STREAM_NAME || 'decoded/solana', + consumerGroup: process.env.BLOCK_REDIS_CONSUMER_GROUP || 'test-group', + consumerName: + process.env.BLOCK_REDIS_CONSUMER_NAME || 'test-consumer-0', + }, + tickStream: { + name: process.env.TICK_REDIS_STREAM_NAME || 'ticks', + consumerGroup: process.env.TICK_REDIS_CONSUMER_GROUP || 'test-group', + consumerName: process.env.TICK_REDIS_CONSUMER_NAME || 'test-consumer-0', + }, + notificationsStreamName: + process.env.NOTIFICATIONS_REDIS_STREAM_NAME || 'notifications', + }, + }); + throw new Error('Should not return'); +} + +main().catch((error) => { + console.log(error); + process.exit(1); +}); diff --git a/src/test-sdk.ts b/src/test-sdk.ts deleted file mode 100644 index 0137ff17..00000000 --- a/src/test-sdk.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { IRangeSDK, RangeSDKInitOptions, RangeSDKOptions } from './sdk'; -import { getLogger } from './logger'; -import { constants } from './constants'; -import { fetchBlock } from './services/fetchBlock'; -import { IRangeAlertRule } from './types/IRangeAlertRule'; -import { IRangeBlock } from './types/chain/IRangeBlock'; - -const logger = getLogger({ name: 'testRangeSDK' }); - -class TestRangeSDK implements IRangeSDK { - private opts: RangeSDKOptions; - public runnerId?: string; - private initOpts?: RangeSDKInitOptions; - - constructor(opts: RangeSDKOptions) { - this.opts = opts; - const [runnerId] = this.opts.token.split('.'); - this.runnerId = runnerId; - - logger.info( - `Initiating rangeSDK in TEST MODE for runnerID: ${runnerId}, manager: ${constants.MANAGER_SERVICE.DOMAIN}`, - ); - } - - async init(initOpts: RangeSDKInitOptions): Promise { - /** - * Fetch config from the manager and setup task queues - */ - this.initOpts = initOpts; - } - - async getNetworkBlock(args: { - network: string; - height: string; - }): Promise { - return fetchBlock({ - token: this.opts.token, - height: args.height, - network: args.network, - includeAvailableRangeOnNotFound: true, - }); - } - - async assertRule( - blockInfo: { network: string; height: string }, - rule: IRangeAlertRule, - ) { - if (!this.initOpts || !this.initOpts.onBlock) { - throw new Error( - 'TestRangeSDK not Init, please provide with the onBlock Method to run block and rule against', - ); - } - - const block = await this.getNetworkBlock(blockInfo); - if (!block) { - throw new Error( - `Block not available for network: ${blockInfo.network} and height: ${blockInfo.height}`, - ); - } - - return this.initOpts.onBlock.callback(block, rule); - } - - async assertRuleWithBlock(block: IRangeBlock, rule: IRangeAlertRule) { - if (!this.initOpts || !this.initOpts.onBlock) { - throw new Error( - 'TestRangeSDK not Init, please provide with the onBlock Method to run block and rule against', - ); - } - - return this.initOpts.onBlock.callback(block, rule); - } - - async assertRuleWithTick(timestamp: string, rule: IRangeAlertRule) { - if (!this.initOpts || !this.initOpts.onTick) { - throw new Error( - 'TestRangeSDK not Init, please provide with the onTick Method to run block and rule against', - ); - } - - return this.initOpts.onTick.callback(timestamp, rule); - } - - async gracefulCleanup(): Promise { - // no-op - } -} - -export { TestRangeSDK }; diff --git a/src/test_data/eth/.gitkeep b/src/test_data/eth/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/src/test_data/osmosis-1/.gitkeep b/src/test_data/osmosis-1/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/src/test_data/solana/.gitkeep b/src/test_data/solana/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/src/threadpool/pool.ts b/src/threadpool/pool.ts new file mode 100644 index 00000000..2c89d5be --- /dev/null +++ b/src/threadpool/pool.ts @@ -0,0 +1,213 @@ +import { Piscina, version } from 'piscina'; +import { IStat, ITaskResult, ITask, ITaskStatus } from '../types/ITask'; +import { randomUUID } from 'crypto'; +import { logger } from '../utils/logger'; +import { dayjs } from '../utils/dayjs'; + +const taskMap = new Map< + string, + { + controller: AbortController; + timingArr: Float64Array; + } +>(); + +// how to cancel threads related to failed tasks +export let pool: Piscina; + +export async function initPool( + options: ConstructorParameters[0] +) { + // Filter out V8 flags from parent process that are invalid for worker threads + const parentArgv = options?.execArgv || []; + const safeArgv = parentArgv.filter( + (arg) => !arg.startsWith('--max-old-space-size') + ); + + const optimizedOptions: ConstructorParameters[0] = { + ...options, + execArgv: ['--trace-warnings', '--trace-uncaught', ...safeArgv], + }; + + pool = new Piscina(optimizedOptions); + logger.info( + `Piscina Pool version ${version} Initialized with ${optimizedOptions.maxThreads} threads.` + ); + + // Warm up pool with fewer concurrent initializations to reduce memory spike + const warmupBatchSize = optimizedOptions.maxThreads || 10; + + const batch = Array(warmupBatchSize) + .fill(0) + .map(() => pool.run(null as any)); // types override here since its a warm up task + await Promise.all(batch); + + logger.info('Piscina Pool warmed up.'); +} + +// Reduced timeout for faster failure detection +const ABORT_THRESHOLD = 12_000; +const ABORT_MESSAGE = 'Aborting due to timeout'; + +let threadMonitorInterval: ReturnType | null = null; + +export function initThreadMonitor() { + if (!threadMonitorInterval) { + threadMonitorInterval = setInterval(() => { + for (const [taskId, { controller, timingArr }] of taskMap.entries()) { + const threadBegin = timingArr![0]; + const threadProcessingTime = Date.now() - threadBegin; + + if (threadBegin && threadProcessingTime > ABORT_THRESHOLD) { + controller.abort(ABORT_MESSAGE); + taskMap.delete(taskId); + } + } + }, 100); + } +} + +export function stopThreadMonitor() { + if (threadMonitorInterval) { + clearInterval(threadMonitorInterval); + threadMonitorInterval = null; + } +} + +export function trackTask( + taskId: string, + controller: AbortController, + timingArr: Float64Array +) { + taskMap.set(taskId, { controller, timingArr }); +} + +export function untrackTask(taskId: string) { + taskMap.delete(taskId); +} + +export async function closePool() { + stopThreadMonitor(); + + // Clean up remaining tasks + for (const [taskId, { controller }] of taskMap.entries()) { + controller.abort('Pool shutdown'); + } + taskMap.clear(); + + logger.info('Piscina Pool destroyed.'); + if (pool) { + await pool.destroy(); + } +} + +/** + * Get current thread pool statistics for monitoring + */ +export interface IPoolStats { + threads: number; + active_threads: number; + idle_threads: number; + queue_size: number; + completed_tasks: number; + utilization: number; + pending_aborts: number; +} + +export function getPoolStats(): IPoolStats { + if (!pool) { + return { + threads: 0, + active_threads: 0, + idle_threads: 0, + queue_size: 0, + completed_tasks: 0, + utilization: 0, + pending_aborts: 0, + }; + } + + const threads = pool.threads.length; + const utilization = pool.utilization; + const activeThreads = Math.round(threads * utilization); + + return { + threads, + active_threads: activeThreads, + idle_threads: threads - activeThreads, + queue_size: pool.queueSize, + completed_tasks: pool.completed, + utilization: Math.round(utilization * 100), + pending_aborts: taskMap.size, + }; +} + +export async function runTask(task: ITask): Promise { + const taskId = randomUUID(); + const controller = new AbortController(); + const parentBegin = Date.now(); + + // Create timing communication buffer - using smaller buffer + const timingBuffer = new SharedArrayBuffer(8); + const timingArr = new Float64Array(timingBuffer); + timingArr[0] = 0; + + const enhancedTask = { ...task, timingBuffer }; + + trackTask(taskId, controller, timingArr); + + try { + const result = await pool.run(enhancedTask, { signal: controller.signal }); + const parentEnd = Date.now(); + + const totalTime = parentEnd - parentBegin; + const processingTime = result.threadTimeSpent; + const waitTime = totalTime - processingTime; + + untrackTask(taskId); + + return { + threadTimeSpent: processingTime, + waitTimeSpent: waitTime, + status: result.status, + alertRuleId: task.alertRule.id, + blockInfo: 'blockInfo' in task ? task.blockInfo : undefined, + tickInfo: 'tickInfo' in task ? task.tickInfo : undefined, + events: result.events, + eventCount: result.events.length, + error: result.error, + startedAt: dayjs(parentBegin).toISOString(), + }; + } catch (error) { + let status: ITaskStatus = 'failure'; + + const parentEnd = Date.now(); + const totalTime = parentEnd - parentBegin; + const threadBegin = 0; + const threadEnd = 0; + let processingTime = threadEnd - threadBegin; + let waitTime = totalTime - processingTime; + + untrackTask(taskId); + + if (error.cause === ABORT_MESSAGE) { + status = 'timeout'; + processingTime = ABORT_THRESHOLD; + waitTime = totalTime - ABORT_THRESHOLD; + } + + return { + events: [], + threadTimeSpent: processingTime, + waitTimeSpent: waitTime, + status, + alertRuleId: task.alertRule.id, + ...('blockInfo' in task && { blockInfo: task.blockInfo }), + ...('tickInfo' in task && { tickInfo: task.tickInfo }), + eventCount: 0, + error: + error instanceof Error ? error.stack || error.message : String(error), + startedAt: dayjs(parentBegin).toISOString(), + }; + } +} diff --git a/src/threadpool/runner.ts b/src/threadpool/runner.ts new file mode 100644 index 00000000..8c3ef1f6 --- /dev/null +++ b/src/threadpool/runner.ts @@ -0,0 +1,503 @@ +import 'reflect-metadata'; +import { Command } from 'commander'; +import { join } from 'path'; +import axios from 'axios'; +import express, { Request, Response } from 'express'; +import { closePool, initPool, getPoolStats, initThreadMonitor } from './pool'; +import { + createRedisClient, + consumeRedisStream, +} from '../services/consumer-redis'; +import { assetManagerInitialization } from '../services/AssetManager'; +import { env, applyConfig } from '../env'; +import { logger } from '../utils/logger'; +import { IRunnerConfig } from '../types/IRunnerConfig'; +import { ProcessorRegistry } from '../utils/processor'; +import { + processPayload, + getBufferPoolStats, + extractBlockMeta, + initBufferPoolCleanup, +} from '../processors/taskProcessor'; +import { SolanaBlockWrapper } from '../wrappers/solana-block-wrapper'; +import { + getHealthyBlockRules, + registerTaskResult, + fetchRules, + statMap, + getStatsSummary, + checkStanding, + getHealthyTickRules, + recordBlockReceived, + recordTickReceived, + getTimeSeriesData, + TimeSeriesMetric, + getLagStats, + initStatsSchedulers, +} from '../services/stats-service'; +import { + initNotificationsRedis, + publishEvents, +} from '../services/event-service'; +import { dayjs } from '../utils/dayjs'; +import { getMetrics } from '../services/prometheus-metrics'; +import { startSlackMonitor } from '../services/slack-monitor'; + +// Maps EVM chain IDs to runner network names +const CHAIN_ID_TO_NETWORK: Record = { + '1': 'eth', + '56': 'bnb', + '137': 'pol', + '42161': 'arb1', +}; + +/** + * Normalize EVM blocks to have top-level height, network, timestamp + * matching the Solana/Cosmos format. Mutates the block in-place. + * No-op if the block already has these fields. + */ +function normalizeBlock(block: any): void { + if (block.height !== undefined && block.network !== undefined) return; + + if (block.block?.result?.number) { + const result = block.block.result; + block.height = parseInt(result.number, 16); + block.timestamp = result.timestamp + ? new Date(parseInt(result.timestamp, 16) * 1000).toISOString() + : undefined; + } + + if (block.network === undefined && block.chain_id !== undefined) { + block.network = + CHAIN_ID_TO_NETWORK[String(block.chain_id)] || String(block.chain_id); + } +} + +function isBlockForNetwork( + blockNetwork: string, + runnerNetwork: string +): boolean { + const normalized = CHAIN_ID_TO_NETWORK[blockNetwork] || blockNetwork; + return normalized === runnerNetwork || blockNetwork === runnerNetwork; +} + +// Graceful shutdown handling +let isShuttingDown = false; + +function setupGracefulShutdown() { + const gracefulShutdown = async (signal: string) => { + if (isShuttingDown) return; + isShuttingDown = true; + + logger.info(`Received ${signal}, initiating graceful shutdown...`); + + try { + // Close the pool and clean up resources + await closePool(); + + // Force garbage collection one final time + if (global.gc) { + global.gc(); + } + + logger.info('Graceful shutdown completed'); + process.exit(0); + } catch (error) { + logger.error('Error during graceful shutdown:', error); + process.exit(1); + } + }; + + process.on('SIGINT', () => gracefulShutdown('SIGINT')); + process.on('SIGTERM', () => gracefulShutdown('SIGTERM')); + + // Handle uncaught exceptions + process.on('uncaughtException', (error) => { + logger.error('Uncaught exception:', error); + gracefulShutdown('uncaughtException'); + }); + + process.on('unhandledRejection', (reason, promise) => { + logger.error( + `Unhandled promise rejection at: ${promise}, reason: ${reason}` + ); + gracefulShutdown('unhandledRejection'); + }); +} + +// Enhanced memory monitoring +function setupMemoryMonitoring() { + const MEMORY_CHECK_INTERVAL = 60_000; // Every 60 seconds + const CRITICAL_MEMORY_THRESHOLD = 3500; // 3.5GB in MB + + setInterval(() => { + try { + const memUsage = process.memoryUsage(); + const rssMB = memUsage.rss / 1024 / 1024; + const heapUsedMB = memUsage.heapUsed / 1024 / 1024; + const heapTotalMB = memUsage.heapTotal / 1024 / 1024; + const externalMB = memUsage.external / 1024 / 1024; + const arrayBuffersMB = memUsage.arrayBuffers / 1024 / 1024; + + logger.info( + `Memory usage: RSS=${rssMB.toFixed(0)}MB, Heap=${heapUsedMB.toFixed(0)}/${heapTotalMB.toFixed(0)}MB, External=${externalMB.toFixed(0)}MB, Buffers=${arrayBuffersMB.toFixed(0)}MB` + ); + + // Critical memory warning + if (rssMB > CRITICAL_MEMORY_THRESHOLD) { + logger.error( + `CRITICAL: Memory usage is very high: RSS=${rssMB.toFixed(0)}MB. Consider restart.` + ); + + // Force GC + if (global.gc) { + global.gc(); + logger.info('Forced garbage collection due to high memory usage'); + } + } + } catch (error) { + logger.error('Error in memory monitoring:', error); + } + }, MEMORY_CHECK_INTERVAL); +} + +async function registerAlertTemplates(alertTemplates: Map) { + try { + logger.info('Registering alert templates...'); + const templatesArray = Array.from(alertTemplates.values()); + + if (env.REGISTER_EXTERNAL_RULE_TYPES_ENDPOINT) { + const runnerId = env.RANGE_SDK_TOKEN.split('.')[0]; + await axios.post( + env.REGISTER_EXTERNAL_RULE_TYPES_ENDPOINT, + { + runnerId, + ruleTypes: templatesArray, + }, + { + timeout: 60_000, + } + ); + } + + logger.info(`Registered ${alertTemplates.size} alert templates.`); + } catch (error: any) { + logger.error(`Error registering alert templates: ${error.message}`); + throw error; + } +} + +export async function startRunner({ + processors: processorsFile, + range_sdk_token, + config, + testAlertRules, +}: IRunnerConfig) { + if (range_sdk_token) process.env.RANGE_SDK_TOKEN = range_sdk_token; + if (config) applyConfig(config); + + if (env.REGISTER_RULE_TYPES) { + // Load processors to populate the registry (import triggers @Rule decorators) + await import( + processorsFile || join(__dirname, 'processors', 'processors.js') + ); + + const network = env.RUNNER_NETWORK || undefined; + const alertTemplates = ProcessorRegistry.getAlertTemplates(network); + + // Dump registration payload for debugging + const runnerId = env.RANGE_SDK_TOKEN.split('.')[0]; + await registerAlertTemplates(alertTemplates); + logger.info(`Alert templates registered for runner: ${runnerId}`); + process.exit(0); + } + + // Setup graceful shutdown handlers + setupGracefulShutdown(); + + // Setup memory monitoring + setupMemoryMonitoring(); + + // Setup Express server for status endpoints + const app = express(); + + // Add JSON middleware + app.use(express.json()); + + // Stats endpoint + app.get('/stats', (req: Request, res: Response) => { + const stats = getStatsSummary(); + res.json(stats); + }); + + // Time series endpoint + app.get('/stats/timeseries', (req: Request, res: Response) => { + const metric = req.query.metric as TimeSeriesMetric; + const intervalMinutes = parseInt(req.query.interval as string) || 1; + const durationMinutes = parseInt(req.query.duration as string) || 60; + + // Validate metric + const validMetrics: TimeSeriesMetric[] = [ + 'events_per_minute', + 'block_avg_processing_time', + 'tick_avg_processing_time', + 'throughput_tasks', + 'success_rate', + 'memory_heap', + ]; + + if (!metric || !validMetrics.includes(metric)) { + res.status(400).json({ + error: 'Invalid metric', + validMetrics, + }); + return; + } + + // Validate interval (1-60 minutes) + if (intervalMinutes < 1 || intervalMinutes > 60) { + res.status(400).json({ + error: 'Interval must be between 1 and 60 minutes', + }); + return; + } + + // Validate duration (1-1440 minutes = 24 hours) + if (durationMinutes < 1 || durationMinutes > 1440) { + res.status(400).json({ + error: 'Duration must be between 1 and 1440 minutes (24 hours)', + }); + return; + } + + try { + const timeSeries = getTimeSeriesData( + metric, + intervalMinutes, + durationMinutes + ); + res.json(timeSeries); + } catch (error: any) { + logger.error('Error generating time series:', error); + res.status(500).json({ + error: 'Failed to generate time series', + message: error.message, + }); + } + }); + + // Health check endpoint + app.get('/health', (req: Request, res: Response) => { + const standing = checkStanding(); + const statusCode = standing.status === 'healthy' ? 200 : 503; + res.status(statusCode).json(standing); + }); + + // Thread pool stats endpoint + app.get('/stats/pool', (req: Request, res: Response) => { + res.json(getPoolStats()); + }); + + // Buffer pool stats endpoint + app.get('/stats/buffers', (req: Request, res: Response) => { + res.json(getBufferPoolStats()); + }); + + // Lag stats endpoint - shows how far behind real-time + app.get('/stats/lag', (req: Request, res: Response) => { + res.json(getLagStats()); + }); + + // Prometheus metrics endpoint + app.get('/metrics', async (req: Request, res: Response) => { + try { + res.set('Content-Type', 'text/plain; version=0.0.4; charset=utf-8'); + res.send(await getMetrics()); + } catch (error) { + res.status(500).send('Error generating metrics'); + } + }); + + app.listen(env.PORT, '127.0.0.1', () => { + logger.info(`Status server listening on port ${env.PORT}`); + }); + + const program = new Command(); + + program + .option('-t, --thread-count ', 'number of threads', '4') + .option('-l, --log-every ', 'log every N blocks', '10') + .parse(); + + const options = program.opts(); + const THREAD_COUNT = parseInt(options.threadCount); + const LOG_EVERY = parseInt(options.logEvery); + + logger.info(`Starting Piscina Runner with ${THREAD_COUNT} threads`); + + // Fetch asset data in main thread and write cache for workers + await assetManagerInitialization(); + + await initPool({ + filename: join(__dirname, 'worker.js'), // worker file path + maxThreads: THREAD_COUNT, // max no. of threads to spin up + concurrentTasksPerWorker: 1, // generally pass 1, but can be adjusted for higher concurrency + idleTimeout: 15_000, // reduced from 30 seconds + closeTimeout: 3_000, // reduced from 5 seconds + execArgv: [ + '--trace-warnings', + '--trace-uncaught', + '--max-old-space-size=4096', + ], + workerData: {}, + }); + + initThreadMonitor(); + await initNotificationsRedis(); + await fetchRules(testAlertRules || []); + initStatsSchedulers(); + initBufferPoolCleanup(); + startSlackMonitor(); + + setInterval(async () => { + await fetchRules(testAlertRules || []); + }, 60_000); + + const blockRedis = await createRedisClient(env.BLOCK_REDIS_URL); + const tickRedis = + env.TICK_REDIS_URL !== env.BLOCK_REDIS_URL + ? await createRedisClient(env.TICK_REDIS_URL) + : blockRedis; + + const promise1 = consumeRedisStream({ + client: blockRedis, + streamName: env.BLOCK_REDIS_STREAM_NAME, + consumerGroup: env.BLOCK_REDIS_CONSUMER_GROUP, + consumerName: env.BLOCK_REDIS_CONSUMER_NAME, + callback: async (block) => { + if (isShuttingDown) return; + + // Binary path: block arrived as pre-encoded FlatBuffer from Redis + if (block._binaryBlock instanceof Uint8Array) { + const wrapper = new SolanaBlockWrapper(block._binaryBlock); + const blockMeta = { + height: String(wrapper.height), + network: wrapper.network, + timestamp: String(wrapper.timestamp), + }; + recordBlockReceived(Number(blockMeta.height), blockMeta.timestamp); + + if (!isBlockForNetwork(blockMeta.network, env.RUNNER_NETWORK)) { + return; + } + + let begin, end; + begin = Date.now(); + + const results = await processPayload({ + blockData: block._binaryBlock, + ruleList: getHealthyBlockRules(), + processorsFile, + }); + end = Date.now(); + const processingTime = end - begin; + + begin = Date.now(); + results.forEach(registerTaskResult); + + const allEvents = results.flatMap((result) => result.events); + await publishEvents(allEvents); + end = Date.now(); + const publishingTime = end - begin; + + const blockHeight = Number(blockMeta.height); + if (blockHeight % LOG_EVERY === 0) { + const ago = dayjs().diff(dayjs(blockMeta.timestamp), 's'); + logger.info( + `height: ${blockHeight}, events: ${allEvents.length}, time: ${processingTime}ms, pub: ${publishingTime}ms, age: ${ago}s ago` + ); + } + return; + } + + // JSON path: existing behavior + normalizeBlock(block); + + // Record that we received a block (for standing check and lag tracking) + const blockMeta = extractBlockMeta(block); + recordBlockReceived(Number(blockMeta.height), blockMeta.timestamp); + + // Skip blocks from other networks + if (!isBlockForNetwork(blockMeta.network, env.RUNNER_NETWORK)) { + return; + } + + let begin, end; + begin = Date.now(); + + const results = await processPayload({ + blockData: block, + ruleList: getHealthyBlockRules(), + processorsFile, + }); + end = Date.now(); + const processingTime = end - begin; + + begin = Date.now(); + results.forEach(registerTaskResult); + + const allEvents = results.flatMap((result) => result.events); + await publishEvents(allEvents); + end = Date.now(); + const publishingTime = end - begin; + + const blockHeight = Number(blockMeta.height); + if (blockHeight % LOG_EVERY === 0) { + const ago = dayjs().diff(dayjs(blockMeta.timestamp), 's'); + logger.info( + `height: ${blockHeight}, events: ${allEvents.length}, time: ${processingTime}ms, pub: ${publishingTime}ms, age: ${ago}s ago` + ); + } + }, + }); + + const promise2 = consumeRedisStream({ + client: tickRedis, + streamName: env.TICK_REDIS_STREAM_NAME, + consumerGroup: env.TICK_REDIS_CONSUMER_GROUP, + consumerName: env.TICK_REDIS_CONSUMER_NAME, + callback: async (tickInfo: { time: string }) => { + if (isShuttingDown) return; + + // Record that we received a tick (for standing check and lag tracking) + recordTickReceived(tickInfo.time); + + let begin, end; + begin = Date.now(); + + const results = await processPayload({ + time: tickInfo.time, + ruleList: getHealthyTickRules(), + processorsFile, + }); + end = Date.now(); + const processingTime = end - begin; + + const allEvents = results.flatMap((result) => result.events); + if (allEvents.length === 0) return; + + begin = Date.now(); + results.forEach(registerTaskResult); + await publishEvents(allEvents); + end = Date.now(); + const publishingTime = end - begin; + + const ago = dayjs().diff(dayjs(tickInfo.time), 's'); + logger.info( + `TICK: ${tickInfo.time}, events: ${allEvents.length}, time: ${processingTime}ms, pub: ${publishingTime}ms, age: ${ago}s ago` + ); + }, + }); + + await Promise.all([promise1, promise2]); +} diff --git a/src/threadpool/worker.ts b/src/threadpool/worker.ts new file mode 100644 index 00000000..e5e48e40 --- /dev/null +++ b/src/threadpool/worker.ts @@ -0,0 +1,68 @@ +import { threadId } from 'worker_threads'; + +// Track seen threads +const seenThreads = new Set(); + +import { ITask, ITaskResult } from '../types/ITask'; +import { processTask } from '../processors'; +import { initAssetService } from '../services/AssetManager'; +import { sleep } from '../utils/basic'; +import { logger } from '../utils/logger'; + +async function warmUpThread() { + await sleep(1000); + return null; +} + +let threadInitialized = false; +async function initThread() { + await initAssetService(); +} + +export default async function (task: ITask): Promise { + if (task?.processorsFile) { + await import(task.processorsFile); + } + + if (!seenThreads.has(threadId)) { + seenThreads.add(threadId); + logger.info(`New thread ${threadId} initialized`); + } else { + // console.log(`Reusing old thread: ${threadId}`); + } + + if (!task) { + return (await warmUpThread()) as unknown as ITaskResult; + } + + if (!threadInitialized) { + await initThread(); + threadInitialized = true; + } + + const threadBegin = Date.now(); + + const timingArr = new Float64Array(task.timingBuffer!); + timingArr[0] = threadBegin; + + const start = Date.now(); + try { + const events = await processTask(task); + const end = Date.now(); + return { + status: 'success', + events, + threadTimeSpent: end - start, + }; + } catch (error) { + // console.log(error); + const end = Date.now(); + return { + status: 'failure', + error: + error instanceof Error ? error.stack || error.message : String(error), + events: [], + threadTimeSpent: end - start, + }; + } +} diff --git a/src/types/IAlertRule.ts b/src/types/IAlertRule.ts new file mode 100644 index 00000000..c8992bfb --- /dev/null +++ b/src/types/IAlertRule.ts @@ -0,0 +1,13 @@ +import { INetwork } from './INetwork'; + +export interface IAlertRule { + id: string; + ruleType: string; + workspaceId?: string | null; + network: INetwork; + parameters: Parameters; + createdAt: string; + deletedAt?: Date | null; + severity?: string; + triggerMode: 'BLOCK' | 'TICK'; +} diff --git a/src/types/ICosmosBlock.ts b/src/types/ICosmosBlock.ts new file mode 100644 index 00000000..5313ab4a --- /dev/null +++ b/src/types/ICosmosBlock.ts @@ -0,0 +1,83 @@ +import { z } from 'zod'; + +const ISanctionedVal = z.record( + z.string(), + z.object({ + entity: z.string(), + }) +); + +const EventAttributeVal = z.object({ + key: z.string(), + value: z.string(), +}); + +const EventVal = z.object({ + type: z.string(), + attributes: z.array(EventAttributeVal), +}); + +const CosmosMessageVal = z.object({ + network_id: z.string().optional(), + tx_hash: z.string().optional(), + index: z.number().optional(), + type: z.string(), + data: z.unknown(), + status: z.string().optional(), + addresses: z.array(z.string()).nullable().optional(), + contract_addresses: z.array(z.string()).optional(), + events: z.array(EventVal).optional(), +}); + +const CosmosTransactionVal = z.object({ + network: z.string().optional(), + height: z.union([z.string(), z.number()]).optional(), + hash: z.string(), + index: z.number().optional(), + messages: z.array(CosmosMessageVal), + info: z.string().optional(), + gas_wanted: z.union([z.string(), z.number()]).optional(), + gas_used: z.union([z.string(), z.number()]).optional(), + events: z.array(EventVal).optional(), + data: z.unknown().optional(), + status: z.string().optional(), + success: z.boolean().optional(), + codespace: z.string().optional(), + code: z.number().optional(), + log: z.string().optional(), +}); + +const BlockEventsVal = z.object({ + begin_block: z.array(EventVal).optional(), + end_block: z.array(EventVal).optional(), +}); + +const BlockDataVal = z.object({ + malicious_addresses: z + .union([z.array(z.string()), ISanctionedVal]) + .optional(), + malicious_entities: z.array(z.unknown()).optional(), + blacklisted_addresses: z + .union([z.array(z.string()), ISanctionedVal]) + .optional(), + blacklisted_entities: z.array(z.unknown()).optional(), + sanctioned_addresses: z + .union([z.array(z.string()), ISanctionedVal]) + .optional(), + sanctioned_entities: z.array(z.unknown()).optional(), +}); + +export const CosmosBlockVal = z.object({ + network: z.string(), + height: z.union([z.string(), z.number()]), + timestamp: z.string(), + transactions: z.array(CosmosTransactionVal), + block_events: BlockEventsVal.optional(), + block_data: BlockDataVal.optional(), +}); + +export type ICosmosBlock = z.infer; +export type ICosmosTransaction = z.infer< + typeof CosmosBlockVal +>['transactions'][number]; +export type ICosmosMessage = ICosmosTransaction['messages'][number]; diff --git a/src/types/IEVMBlock.ts b/src/types/IEVMBlock.ts new file mode 100644 index 00000000..30fef8bd --- /dev/null +++ b/src/types/IEVMBlock.ts @@ -0,0 +1,180 @@ +import { z } from 'zod'; + +// ── Transaction ── + +const EVMAccessListVal = z.object({ + address: z.string(), + storageKeys: z.array(z.string()), +}); + +const EVMAuthorizationVal = z.object({ + chainId: z.string(), + address: z.string(), + nonce: z.string(), + yParity: z.string(), + r: z.string(), + s: z.string(), +}); + +const EVMTransactionVal = z.object({ + blockHash: z.string(), + blockNumber: z.string(), + from: z.string(), + gas: z.string(), + gasPrice: z.string(), + maxFeePerGas: z.string().optional(), + maxPriorityFeePerGas: z.string().optional(), + maxFeePerBlobGas: z.string().optional(), + hash: z.string(), + input: z.string(), + nonce: z.string(), + to: z.string().nullable(), + transactionIndex: z.string(), + value: z.string(), + type: z.string(), + accessList: z.array(EVMAccessListVal).optional(), + chainId: z.string().optional(), + blobVersionedHashes: z.array(z.string()).optional(), + v: z.string(), + r: z.string(), + s: z.string(), + yParity: z.string().optional(), + // EIP-7702 + authorizationList: z.array(EVMAuthorizationVal).optional(), + // OP stack + depositReceiptVersion: z.string().optional(), + sourceHash: z.string().optional(), + mint: z.string().optional(), +}); + +// ── Block result ── + +const WithdrawalVal = z.object({ + index: z.string(), + validatorIndex: z.string(), + address: z.string(), + amount: z.string(), +}); + +const EVMResultVal = z.object({ + baseFeePerGas: z.string(), + blobGasUsed: z.string().optional(), + difficulty: z.string(), + excessBlobGas: z.string().optional(), + extraData: z.string(), + gasLimit: z.string(), + gasUsed: z.string(), + hash: z.string(), + logsBloom: z.string(), + miner: z.string(), + mixHash: z.string(), + nonce: z.string(), + number: z.string(), + parentBeaconBlockRoot: z.string().optional(), + parentHash: z.string(), + receiptsRoot: z.string(), + sha3Uncles: z.string(), + size: z.string(), + stateRoot: z.string(), + timestamp: z.string(), + transactions: z.array(EVMTransactionVal), + transactionsRoot: z.string().optional(), + uncles: z.array(z.unknown()).optional(), + withdrawals: z.array(WithdrawalVal).optional(), + withdrawalsRoot: z.string().optional(), + requestsHash: z.string().optional(), + // L2 / chain-specific + l1BlockNumber: z.string().optional(), + sendCount: z.string().optional(), + sendRoot: z.string().optional(), + milliTimestamp: z.string().optional(), + totalDifficulty: z.string().optional(), +}); + +export const EVMBlockRPCVal = z.object({ + jsonrpc: z.string(), + id: z.union([z.string(), z.number()]), + result: EVMResultVal, +}); + +// ── Receipt ── + +const EVMLogVal = z.object({ + address: z.string(), + topics: z.array(z.string()), + data: z.string(), + blockNumber: z.string(), + transactionHash: z.string(), + transactionIndex: z.string(), + blockHash: z.string(), + blockTimestamp: z.string().optional(), + logIndex: z.string(), + removed: z.boolean(), +}); + +const EVMReceiptVal = z.object({ + blockHash: z.string(), + blockNumber: z.string(), + contractAddress: z.string().nullable(), + cumulativeGasUsed: z.string(), + effectiveGasPrice: z.string(), + from: z.string(), + gasUsed: z.string(), + logs: z.array(EVMLogVal), + logsBloom: z.string(), + status: z.string(), + to: z.string().nullable(), + transactionHash: z.string(), + transactionIndex: z.string(), + type: z.string(), + // L2 / chain-specific + gasUsedForL1: z.string().optional(), + l1BlockNumber: z.string().optional(), + l1Fee: z.string().optional(), + l1GasPrice: z.string().optional(), + l1GasUsed: z.string().optional(), + l1BaseFeeScalar: z.string().optional(), + l1BlobBaseFee: z.string().optional(), + l1BlobBaseFeeScalar: z.string().optional(), + daFootprintGasScalar: z.string().optional(), + blobGasUsed: z.string().optional(), + blobGasPrice: z.string().optional(), + depositNonce: z.string().optional(), + depositReceiptVersion: z.string().optional(), + timeboosted: z.boolean().optional(), +}); + +// ── Transfer ── + +const EVMTransferVal = z.object({ + sender: z.string(), + receiver: z.string(), + amount: z.string(), + asset: z.string(), + block_time: z.string(), + native: z.boolean(), + native_inside_contract: z.boolean(), +}); + +// ── Top-level block ── + +export const EVMBlockVal = z.object({ + network: z.string(), + height: z.union([z.string(), z.number()]), + timestamp: z.string(), + chain_id: z.number(), + block: EVMBlockRPCVal, + receipts: z.record(z.string(), EVMReceiptVal), + transfers: z.record(z.string(), z.array(EVMTransferVal)), +}); + +// ── Exported types ── + +export type IEVMBlockRPC = z.infer; +export type IEVMBlock = z.infer; +export type IEVMTransaction = z.infer< + typeof EVMBlockRPCVal +>['result']['transactions'][number]; +export type IEVMReceipt = z.infer; +export type IEVMLog = z.infer; +export type IEVMTransfer = z.infer; diff --git a/src/types/IEvent.ts b/src/types/IEvent.ts new file mode 100644 index 00000000..096f07a3 --- /dev/null +++ b/src/types/IEvent.ts @@ -0,0 +1,22 @@ +export interface IEventDetails { + message: string; + customAttributes?: any; + [key: string]: any; +} + +export interface IEvent { + id: string; + details: IEventDetails; + workspaceId: string | null; + alertRuleId: string; + time: string; + txHash: string; + blockNumber?: string; + network?: string; + addressesInvolved: string[]; + severity?: string; + caption: string; +} + +export type ISubEvent = Pick & + Partial>; diff --git a/src/types/INetwork.ts b/src/types/INetwork.ts new file mode 100644 index 00000000..c0071c61 --- /dev/null +++ b/src/types/INetwork.ts @@ -0,0 +1,31 @@ +export type KnownEvmNetwork = 'eth' | 'arb1' | 'bnb' | 'pol'; + +export type KnownNetwork = + | 'cosmoshub-4' + | 'solana' + | 'neutron-1' + | 'noble-1' + | 'osmosis-1' + | 'stride-1' + | 'celestia' + | 'dydx-mainnet-1' + | 'dymension_1100-1' + | 'agoric-3' + | 'pio-mainnet-1' + | 'mantra-1' + | KnownEvmNetwork; + +export const ETHEREUM = 'eth' as const; +export const ARBITRUM = 'arb1' as const; +export const BINANCE_SMART_CHAIN = 'bnb' as const; +export const POLYGON = 'pol' as const; + +export const EVM_NETWORKS: KnownEvmNetwork[] = [ + ETHEREUM, + ARBITRUM, + BINANCE_SMART_CHAIN, + POLYGON, +]; + +export type IEvmNetwork = KnownEvmNetwork | (string & {}); +export type INetwork = KnownNetwork | (string & {}); diff --git a/src/types/IRangeAlertRule.ts b/src/types/IRangeAlertRule.ts deleted file mode 100644 index 19ca84ca..00000000 --- a/src/types/IRangeAlertRule.ts +++ /dev/null @@ -1,11 +0,0 @@ -export interface IRangeAlertRule { - id: string; - ruleType: string; - workspaceId?: string | null; - ruleGroupId: string; - network: string; - parameters: Record | null; - createdAt: Date; - deletedAt?: Date | null; - severity?: string; -} diff --git a/src/types/IRangeConfig.ts b/src/types/IRangeConfig.ts deleted file mode 100644 index 7e824bfd..00000000 --- a/src/types/IRangeConfig.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { KafkaConfig } from 'kafkajs'; - -export interface IRangeConfig { - kafka: Pick; - kafkaTopics: { - blockRuleGroupTasks: string; - errorsBlockRuleTasks: string; - tickRuleGroupTasks: string; - }; - kafkaGroupIds: { - blockRuleGroupTasks: string; - errorsBlockRuleTasks: string; - tickRuleGroupTasks: string; - }; -} diff --git a/src/types/IRangeEvent.ts b/src/types/IRangeEvent.ts deleted file mode 100644 index fa0c77ab..00000000 --- a/src/types/IRangeEvent.ts +++ /dev/null @@ -1,22 +0,0 @@ -export interface IRangeEvent { - details: { message: string } & Record; - workspaceId: string | null; - alertRuleId: string; - time: string; - txHash: string; - blockNumber?: string; - network?: string; - addressesInvolved: string[]; - severity?: string; - caption: string; -} - -export type ISubEvent = Pick & - Partial>; - -export interface IRangeError { - ruleId: string; - error: string; -} - -export type IRangeResult = IRangeEvent | IRangeError; diff --git a/src/types/IRangeNetwork.ts b/src/types/IRangeNetwork.ts deleted file mode 100644 index e3fd47a9..00000000 --- a/src/types/IRangeNetwork.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { Network } from '../network'; - -export type IRangeNetwork = Network; -export { NetworkEnum } from '../network'; diff --git a/src/types/IRangeTaskPackage.ts b/src/types/IRangeTaskPackage.ts deleted file mode 100644 index 20b08d9e..00000000 --- a/src/types/IRangeTaskPackage.ts +++ /dev/null @@ -1,24 +0,0 @@ -export interface BlockRuleGroupTaskPackage { - block: { - network: string; - height: string; - }; - ruleGroupId: string; - runnerId: string; -} - -export interface ErrorBlockRuleTaskPackage { - network: string; - blockNumber: string; - ruleGroupId: string; - ruleId: string; - errorId: string; - error: string; - retryCount: number; -} - -export interface TickRuleGroupTaskPackage { - timestamp: string; - ruleGroupId: string; - runnerId: string; -} diff --git a/src/types/IRule.ts b/src/types/IRule.ts new file mode 100644 index 00000000..1f34ebfc --- /dev/null +++ b/src/types/IRule.ts @@ -0,0 +1,205 @@ +import { INetwork } from './INetwork'; + +// For solana network, address ~ account and contract ~ program +export type FieldType = + | 'Address' // single address selector for given network + | 'AddressList' // multi address selector for given network + | 'Number' // number input + | 'Contract' // single contract selector for given network + | 'ContractList' // multi contract selector for given network + | 'AddressContract' // addresses + contracts combined + | 'AddressesContractsList' // addresses + contracts combined + | 'CosmosAddress' // multi address selector for all networks + | 'CosmosAddressList' // multi address selector for all networks + | 'AssetSymbol' + | 'TimeDuration' + | 'Text' + | 'SolanaMint' + | 'ProgramInstructionOptions' + | 'CustomDropdownSingle' // todo: options array of format {label, value, icon} will be provided + | 'CustomDropdownMulti' // todo: options array of format {label, value, icon} will be provided + | 'Boolean'; // todo: show a checkbox + +export const FieldTypeToTSType: Record = { + Address: 'string', + AddressList: 'string[]', + Number: 'number', + Contract: 'string', + ContractList: 'string[]', + AddressContract: 'string', + AddressesContractsList: 'string[]', + AssetSymbol: 'string', + TimeDuration: 'number', + Text: 'string', + SolanaMint: 'string', + ProgramInstructionOptions: 'string[]', + CustomDropdownSingle: 'string', + CustomDropdownMulti: 'string[]', + CosmosAddress: 'string', + CosmosAddressList: 'string[]', + Boolean: 'boolean', +} as const; + +type RuleTag = + // Blockchain-specific + | 'evm' + | 'solana' + | 'osmosis' + | 'neutron' + | 'stride' + | 'cosmwasm' + | 'ibc' + | 'sui' + | 'aptos' + | 'sei' + | 'injective' + | 'celestia' + | 'bitcoin' + + // Protocol Specific + | 'mars' + | 'astroport' + | 'red-bank' + | 'dex' + | 'money market' + | 'lending' + | 'ics' + + // Token + | 'token' + | 'cw20' + | 'balance' + | 'tokenfactory' + + // NFT / Token operations + | 'nft' + | 'mint' + | 'burn' + | 'airdrop' + + // Financial operations + | 'economic' + | 'distribution' + | 'incentives' + | 'liquidation' + | 'trading' + + // DeFi + | 'defi' + | 'swap' + | 'yield' + | 'vault' + | 'amm' + | 'perpetuals' + | 'borrowing' + | 'flashloan' + + // Governance + | 'governance' + | 'community' + | 'community pool' + | 'spend' + | 'admin' + | 'multisig' + | 'validator' + | 'evidence' + | 'upgrade' + | 'stake' + | 'delegate' + | 'events' + | 'proposal' + | 'vote' + | 'emergency' + + // Security and risk management + | 'security' + | 'risk' + | 'halt' + | 'sanctions' + | 'blacklist' + | 'exploit' + | 'mev' + | 'reentrancy' + + // EVM / Safe + | 'gnosis-safe' + | 'proxy' + | 'access-control' + | 'ownership' + | 'timelock' + + // Cross Chain + | 'bridges' + | 'contract' + | 'relayer' + | 'oracle' + + // Analytics and monitoring + | 'analytics' + | 'aggregation' + | 'high volume' + | 'account' + | 'program' + | 'unusual' + | 'spl-token' + | 'error' + | 'authority' + | 'freeze' + | 'safe' + | 'squads-multisig' + | 'squads' + | 'hydro' + | 'liquidity-anomaly' + | 'volume-anomaly' + | 'price-anomaly' + | 'latency' + | 'downtime' + | 'gas' + | 'fee' + + // Stablecoin + | 'stablecoin' + | 'depeg' + | 'price-deviation' + | 'peg-monitor' + | 'reserve' + | 'backing' + | 'redemption' + + // Transfer + | 'transfer' + + // Treasury / EOA + | 'eoa' + | 'treasury' + | 'treasury-management' + | 'whale' + | 'large-transfer' + | 'outflow' + | 'inflow' + | 'dormant-account' + | 'threshold' + + // Custom tags (allows any string) + | (string & {}); + +interface IParam { + label: string; + description: string; + field: T; + fieldType: FieldType; + optional?: boolean; // note: by default all params are required + options?: { label: string; value: string; icon?: string }[]; +} + +export interface IRule { + tags: RuleTag[]; + type: string; + networks: INetwork[]; + label: string; + description: string; + parameters: IParam[]; + workspaces?: string[]; + severity?: 'high' | 'medium' | 'low' | 'info' | 'critical'; + trigger?: 'BLOCK' | 'TICK'; +} diff --git a/src/types/IRunnerConfig.ts b/src/types/IRunnerConfig.ts new file mode 100644 index 00000000..e58349c2 --- /dev/null +++ b/src/types/IRunnerConfig.ts @@ -0,0 +1,32 @@ +import { IAlertRule } from './IAlertRule'; + +export interface ISDKConfig { + // Required — minimum to run + rangeSdkToken: string; + blockStream?: { name: string; consumerGroup: string; consumerName: string }; + tickStream?: { name: string; consumerGroup: string; consumerName: string }; + notificationsStreamName?: string; + + // Redis — single URL for everything, optional per-connection overrides + redisUrl?: string; // default '127.0.0.1:6379', used for block, alerting, and notifications + redis?: { + alertingUrl?: string; // override for alerting connection + notificationsUrl?: string; // override for notifications connection + tickUrl?: string; // override for tick stream connection (defaults to redisUrl) + }; + + // Optional + port?: number; + logLevel?: string; + rpcProxy?: { host: string; token: string }; + rangeApi?: { host: string; key: string }; + slack?: { webhookUrl: string; intervalHr?: number }; + monitoring?: { enabled: boolean; serverUrl: string; serverToken: string }; +} + +export interface IRunnerConfig { + processors: string; + range_sdk_token?: string; + config?: ISDKConfig; + testAlertRules?: IAlertRule[]; +} diff --git a/src/types/ISolanaBlock.ts b/src/types/ISolanaBlock.ts new file mode 100644 index 00000000..890ca802 --- /dev/null +++ b/src/types/ISolanaBlock.ts @@ -0,0 +1,127 @@ +import { z } from 'zod'; + +// ── Instruction ── + +const InstructionVal = z.object({ + parsed: z.union([z.string(), z.record(z.string(), z.unknown())]).optional(), + programId: z.string(), + program: z.string().optional(), + accounts: z.array(z.string()).optional(), + data: z.string().optional(), + stackHeight: z.number().nullable(), +}); + +// ── Address table lookups ── + +const AddressTableLookupVal = z.object({ + accountKey: z.string(), + readonlyIndexes: z.array(z.number()), + writableIndexes: z.array(z.number()), +}); + +// ── Token balance ── + +const TokenBalanceVal = z.object({ + accountIndex: z.number(), + mint: z.string(), + owner: z.string(), + programId: z.string(), + uiTokenAmount: z.object({ + amount: z.string(), + decimals: z.number(), + uiAmount: z.number().nullable(), + uiAmountString: z.string(), + }), +}); + +// ── Sanctioned addresses ── + +const ISanctionedVal = z.record( + z.string(), + z.object({ + entity: z.string(), + }) +); + +// ── Block events ── + +const BlockEventsVal = z.object({ + begin_block: z.array(z.unknown()).optional(), + end_block: z.array(z.unknown()).optional(), +}); + +// ── Block ── + +const SolanaBlockVal = z.object({ + network: z.literal('solana'), + height: z.string(), + hash: z.string(), + timestamp: z.string(), + block_data: z.object({ + slot: z.string(), + parent_slot: z.string(), + previous_blockhash: z.string(), + malicious_addresses: z.union([ + ISanctionedVal, + z.record(z.string(), z.never()), + ]), + sanctioned_addresses: z.union([ + ISanctionedVal, + z.record(z.string(), z.never()), + ]), + blacklisted_addresses: z.union([ + ISanctionedVal, + z.record(z.string(), z.never()), + ]), + }), + block_events: BlockEventsVal.optional(), + transactions: z.array( + z.object({ + version: z.union([z.string(), z.number()]), + transaction: z.object({ + message: z.object({ + accountKeys: z.array( + z.object({ + pubkey: z.string(), + signer: z.boolean(), + source: z.string(), + writable: z.boolean(), + }) + ), + instructions: z.array(InstructionVal), + recentBlockhash: z.string(), + addressTableLookups: z.array(AddressTableLookupVal).optional(), + }), + signatures: z.array(z.string()), + }), + meta: z.object({ + computeUnitsConsumed: z.number(), + costUnits: z.number(), + err: z.any().nullable(), + fee: z.number(), + innerInstructions: z.array( + z.object({ + index: z.number(), + instructions: z.array(InstructionVal), + }) + ), + logMessages: z.array(z.string()), + preBalances: z.array(z.number()), + postBalances: z.array(z.number()), + preTokenBalances: z.array(TokenBalanceVal), + postTokenBalances: z.array(TokenBalanceVal), + rewards: z.array(z.unknown()), + status: z.union([ + z.object({ Ok: z.null() }), + z.object({ Err: z.unknown() }), + ]), + }), + }) + ), +}); + +export { SolanaBlockVal }; +export type ISolanaBlock = z.infer; +export type ISolanaTransaction = z.infer< + typeof SolanaBlockVal +>['transactions'][number]; diff --git a/src/types/ITask.ts b/src/types/ITask.ts new file mode 100644 index 00000000..def37681 --- /dev/null +++ b/src/types/ITask.ts @@ -0,0 +1,49 @@ +import { IAlertRule } from './IAlertRule'; +import { IEvent } from './IEvent'; + +export interface ITask { + alertRule: IAlertRule; + blockInfo?: { + network: string; + height: string; + time: string; + }; + tickInfo?: { + time: string; + }; + sharedBuffer?: SharedArrayBuffer; + sharedBufferLength?: number; // actual payload byte count within the SharedArrayBuffer + flatBuffer?: boolean; // true = sharedBuffer contains FlatBuffer bytes (not JSON) + // Add timing communication buffer for thread begin time tracking + timingBuffer?: SharedArrayBuffer; // 16 bytes: [threadBeginTime, isProcessing] + processorsFile: string; +} + +export type ITaskStatus = 'success' | 'failure' | 'timeout'; + +export interface ITaskResult { + status: ITaskStatus; + events: IEvent[]; + threadTimeSpent: number; + threadBeginTime?: number; // Add thread begin time to result + error?: string; +} + +export interface IStat { + alertRuleId: string; + blockInfo?: { + network: string; + height: string; + time: string; + }; + tickInfo?: { + time: string; + }; + events: IEvent[]; + eventCount: number; + status: ITaskStatus; + threadTimeSpent: number; + waitTimeSpent: number; + error?: string; + startedAt: string; +} diff --git a/src/types/chain/IRangeBlock.ts b/src/types/chain/IRangeBlock.ts deleted file mode 100644 index 6d5d10c2..00000000 --- a/src/types/chain/IRangeBlock.ts +++ /dev/null @@ -1,99 +0,0 @@ -import { NetworkEnum } from '../IRangeNetwork'; -import { Osmosis1Trx } from './osmosis-1/IRangeBlockOsmosis1Trx'; -import { Grand1Trx } from './grand-1/IRangeBlockGrand1Trx'; -import { CosmosHub4Trx } from './cosmoshub-4/IRangeBlockCosmosHub4Trx'; -import { Mocha4Trx } from './mocha-4/IRangeBlockMocha4Trx'; -import { Neutron1Trx } from './neutron-1/IRangeBlockNeutron1Trx'; -import { Noble1Trx } from './noble-1/IRangeBlockNoble1Trx'; -import { Stride1Trx } from './stride-1/IRangeBlockStride1Trx'; -import { OsmoTest5Trx } from './osmo-test-5/IRangeBlockOsmoTest5Trx'; -import { CelestiaTrx } from './celestia/IRangeBlockCelestiaTrx'; -import { DydxMainnet1Trx } from './dydx-mainnet-1/IRangeBlockDydxMainnet1Trx'; -import { SolanaTrx } from './solana/IRangeBlockSolanaTrx'; - -interface BlockBase { - hash: string; - height: string; - transactions: unknown[]; - network: NetworkEnum; - timestamp: string; - block_data?: Record; - block_events?: BlockEvents; -} - -export interface BlockEvent { - type: string; - attributes: { key: string; value: string }[]; -} - -export interface BlockEvents { - end_block: BlockEvent[]; - begin_block: BlockEvent[]; -} - -export interface Osmosis1Block extends BlockBase { - transactions: Osmosis1Trx[]; - network: NetworkEnum.Osmosis1; -} - -export interface Grand1Block extends BlockBase { - transactions: Grand1Trx[]; - network: NetworkEnum.Grand1; -} - -export interface CosmosHub4Block extends BlockBase { - transactions: CosmosHub4Trx[]; - network: NetworkEnum.CosmosHub4; -} - -export interface Mocha4Block extends BlockBase { - transactions: Mocha4Trx[]; - network: NetworkEnum.Mocha4; -} - -export interface Neutron1Block extends BlockBase { - transactions: Neutron1Trx[]; - network: NetworkEnum.Neutron1; -} - -export interface Noble1Block extends BlockBase { - transactions: Noble1Trx[]; - network: NetworkEnum.Noble1; -} - -export interface Stride1Block extends BlockBase { - transactions: Stride1Trx[]; - network: NetworkEnum.Stride1; -} - -export interface OsmoTest5Block extends BlockBase { - transactions: OsmoTest5Trx[]; - network: NetworkEnum.OsmoTest5; -} - -export interface CelestiaBlock extends BlockBase { - transactions: CelestiaTrx[]; - network: NetworkEnum.Celestia; -} - -export interface DydxMainnet1Block extends BlockBase { - transactions: DydxMainnet1Trx[]; - network: NetworkEnum.DydxMainnet1; -} - -export interface SolanaBlock extends BlockBase { - transactions: SolanaTrx[]; - network: NetworkEnum.Solana; -} - -export type IRangeBlock = - | Osmosis1Block - | Grand1Block - | CosmosHub4Block - | Mocha4Block - | Neutron1Block - | Noble1Block - | Stride1Block - | OsmoTest5Block - | CelestiaBlock - | DydxMainnet1Block; diff --git a/src/types/chain/IRangeMessage.ts b/src/types/chain/IRangeMessage.ts deleted file mode 100644 index c8afc25f..00000000 --- a/src/types/chain/IRangeMessage.ts +++ /dev/null @@ -1,22 +0,0 @@ -interface IKeyValuePair { - key: string; - value: string; - type?: 'binary'; -} - -export interface IRangeMessageEvent { - type: string; - attributes: IKeyValuePair[]; -} - -export interface IRangeMessage { - network_id: string; - tx_hash: string; - index: number; - type: string; - data: unknown; - status: string; - addresses: string[]; - events: IRangeMessageEvent[]; - contract_addresses?: any; -} diff --git a/src/types/chain/IRangeTransaction.ts b/src/types/chain/IRangeTransaction.ts deleted file mode 100644 index f475bf58..00000000 --- a/src/types/chain/IRangeTransaction.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { IRangeMessage } from './IRangeMessage'; - -export interface IKeyValuePair { - key: string; - value: string; - binary?: boolean; -} - -export interface ITransactionEvent { - type: string; - attributes: IKeyValuePair[]; -} - -export interface ITransactionLog { - events: ITransactionEvent[]; -} - -export interface IRangeTransaction { - data: unknown; - hash: string; - logs?: ITransactionLog[]; - events?: ITransactionEvent[]; - index: number; - height: string; - status: string; - network: string; - success: boolean; - messages: IRangeMessage[]; -} diff --git a/src/types/chain/celestia/IRangeBlockCelestiaTrx.ts b/src/types/chain/celestia/IRangeBlockCelestiaTrx.ts deleted file mode 100644 index 3c0f46cf..00000000 --- a/src/types/chain/celestia/IRangeBlockCelestiaTrx.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { IRangeTransaction } from '../IRangeTransaction'; -import { CelestiaTrxMsg } from './IRangeBlockCelestiaTrxMsg'; - -export interface CelestiaTrx extends IRangeTransaction { - messages: CelestiaTrxMsg[]; -} diff --git a/src/types/chain/celestia/IRangeBlockCelestiaTrxMsg.ts b/src/types/chain/celestia/IRangeBlockCelestiaTrxMsg.ts deleted file mode 100644 index e75d900e..00000000 --- a/src/types/chain/celestia/IRangeBlockCelestiaTrxMsg.ts +++ /dev/null @@ -1,973 +0,0 @@ -import { IRangeMessage } from '../IRangeMessage'; - -export enum CelestiaTrxMsgTypes { - CelestiaQgbV1MsgRegisterEVMAddress = 'celestia.qgb.v1.MsgRegisterEVMAddress', - CelestiaBlobV1MsgPayForBlobs = 'celestia.blob.v1.MsgPayForBlobs', - CosmosAuthzV1beta1MsgExec = 'cosmos.authz.v1beta1.MsgExec', - CosmosAuthzV1beta1MsgGrant = 'cosmos.authz.v1beta1.MsgGrant', - CosmosAuthzV1beta1MsgRevoke = 'cosmos.authz.v1beta1.MsgRevoke', - CosmosBankV1beta1MsgMultiSend = 'cosmos.bank.v1beta1.MsgMultiSend', - CosmosBankV1beta1MsgSend = 'cosmos.bank.v1beta1.MsgSend', - CosmosDistributionV1beta1MsgSetWithdrawAddress = 'cosmos.distribution.v1beta1.MsgSetWithdrawAddress', - CosmosDistributionV1beta1MsgWithdrawDelegatorReward = 'cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward', - CosmosDistributionV1beta1MsgWithdrawValidatorCommission = 'cosmos.distribution.v1beta1.MsgWithdrawValidatorCommission', - CosmosFeegrantV1beta1MsgGrantAllowance = 'cosmos.feegrant.v1beta1.MsgGrantAllowance', - CosmosGovV1beta1MsgVote = 'cosmos.gov.v1beta1.MsgVote', - CosmosSlashingV1beta1MsgUnjail = 'cosmos.slashing.v1beta1.MsgUnjail', - CosmosStakingV1beta1MsgBeginRedelegate = 'cosmos.staking.v1beta1.MsgBeginRedelegate', - CosmosStakingV1beta1MsgCancelUnbondingDelegation = 'cosmos.staking.v1beta1.MsgCancelUnbondingDelegation', - CosmosStakingV1beta1MsgCreateValidator = 'cosmos.staking.v1beta1.MsgCreateValidator', - CosmosStakingV1beta1MsgDelegate = 'cosmos.staking.v1beta1.MsgDelegate', - CosmosStakingV1beta1MsgEditValidator = 'cosmos.staking.v1beta1.MsgEditValidator', - CosmosStakingV1beta1MsgUndelegate = 'cosmos.staking.v1beta1.MsgUndelegate', - CosmosVestingV1beta1MsgCreateVestingAccount = 'cosmos.vesting.v1beta1.MsgCreateVestingAccount', - IbcApplicationsTransferV1MsgTransfer = 'ibc.applications.transfer.v1.MsgTransfer', - IbcCoreChannelV1MsgAcknowledgement = 'ibc.core.channel.v1.MsgAcknowledgement', - IbcCoreChannelV1MsgChannelOpenAck = 'ibc.core.channel.v1.MsgChannelOpenAck', - IbcCoreChannelV1MsgChannelOpenConfirm = 'ibc.core.channel.v1.MsgChannelOpenConfirm', - IbcCoreChannelV1MsgChannelOpenInit = 'ibc.core.channel.v1.MsgChannelOpenInit', - IbcCoreChannelV1MsgChannelOpenTry = 'ibc.core.channel.v1.MsgChannelOpenTry', - IbcCoreChannelV1MsgRecvPacket = 'ibc.core.channel.v1.MsgRecvPacket', - IbcCoreChannelV1MsgTimeout = 'ibc.core.channel.v1.MsgTimeout', - IbcCoreClientV1MsgCreateClient = 'ibc.core.client.v1.MsgCreateClient', - IbcCoreClientV1MsgUpdateClient = 'ibc.core.client.v1.MsgUpdateClient', - IbcCoreConnectionV1MsgConnectionOpenAck = 'ibc.core.connection.v1.MsgConnectionOpenAck', - IbcCoreConnectionV1MsgConnectionOpenConfirm = 'ibc.core.connection.v1.MsgConnectionOpenConfirm', - IbcCoreConnectionV1MsgConnectionOpenInit = 'ibc.core.connection.v1.MsgConnectionOpenInit', - IbcCoreConnectionV1MsgConnectionOpenTry = 'ibc.core.connection.v1.MsgConnectionOpenTry', -} - -export type CelestiaTrxMsg = - | CelestiaTrxMsgCelestiaQgbV1MsgRegisterEVMAddress - | CelestiaTrxMsgCelestiaBlobV1MsgPayForBlobs - | CelestiaTrxMsgCosmosAuthzV1beta1MsgExec - | CelestiaTrxMsgCosmosAuthzV1beta1MsgGrant - | CelestiaTrxMsgCosmosAuthzV1beta1MsgRevoke - | CelestiaTrxMsgCosmosBankV1beta1MsgMultiSend - | CelestiaTrxMsgCosmosBankV1beta1MsgSend - | CelestiaTrxMsgCosmosDistributionV1beta1MsgSetWithdrawAddress - | CelestiaTrxMsgCosmosDistributionV1beta1MsgWithdrawDelegatorReward - | CelestiaTrxMsgCosmosDistributionV1beta1MsgWithdrawValidatorCommission - | CelestiaTrxMsgCosmosFeegrantV1beta1MsgGrantAllowance - | CelestiaTrxMsgCosmosGovV1beta1MsgVote - | CelestiaTrxMsgCosmosSlashingV1beta1MsgUnjail - | CelestiaTrxMsgCosmosStakingV1beta1MsgBeginRedelegate - | CelestiaTrxMsgCosmosStakingV1beta1MsgCancelUnbondingDelegation - | CelestiaTrxMsgCosmosStakingV1beta1MsgCreateValidator - | CelestiaTrxMsgCosmosStakingV1beta1MsgDelegate - | CelestiaTrxMsgCosmosStakingV1beta1MsgEditValidator - | CelestiaTrxMsgCosmosStakingV1beta1MsgUndelegate - | CelestiaTrxMsgCosmosVestingV1beta1MsgCreateVestingAccount - | CelestiaTrxMsgIbcApplicationsTransferV1MsgTransfer - | CelestiaTrxMsgIbcCoreChannelV1MsgAcknowledgement - | CelestiaTrxMsgIbcCoreChannelV1MsgChannelOpenAck - | CelestiaTrxMsgIbcCoreChannelV1MsgChannelOpenConfirm - | CelestiaTrxMsgIbcCoreChannelV1MsgChannelOpenInit - | CelestiaTrxMsgIbcCoreChannelV1MsgChannelOpenTry - | CelestiaTrxMsgIbcCoreChannelV1MsgRecvPacket - | CelestiaTrxMsgIbcCoreChannelV1MsgTimeout - | CelestiaTrxMsgIbcCoreClientV1MsgCreateClient - | CelestiaTrxMsgIbcCoreClientV1MsgUpdateClient - | CelestiaTrxMsgIbcCoreConnectionV1MsgConnectionOpenAck - | CelestiaTrxMsgIbcCoreConnectionV1MsgConnectionOpenConfirm - | CelestiaTrxMsgIbcCoreConnectionV1MsgConnectionOpenInit - | CelestiaTrxMsgIbcCoreConnectionV1MsgConnectionOpenTry; - -// types for msg type:: /celestia.qgb.v1.MsgRegisterEVMAddress -export interface CelestiaTrxMsgCelestiaQgbV1MsgRegisterEVMAddress - extends IRangeMessage { - type: CelestiaTrxMsgTypes.CelestiaQgbV1MsgRegisterEVMAddress; - data: { - evmAddress: string; - validatorAddress: string; - }; -} - -// types for msg type:: /celestia.blob.v1.MsgPayForBlobs -export interface CelestiaTrxMsgCelestiaBlobV1MsgPayForBlobs - extends IRangeMessage { - type: CelestiaTrxMsgTypes.CelestiaBlobV1MsgPayForBlobs; - data: { - signer: string; - namespaces: string[]; - blobSizes: number[]; - shareCommitments: string[]; - shareVersions: number[]; - }; -} - -// types for msg type:: /cosmos.authz.v1beta1.MsgExec -export interface CelestiaTrxMsgCosmosAuthzV1beta1MsgExec extends IRangeMessage { - type: CelestiaTrxMsgTypes.CosmosAuthzV1beta1MsgExec; - data: { - grantee: string; - msgs: ( - | CelestiaTrxMsgCosmosAuthzV1beta1MsgExecDataMsgSend - | CelestiaTrxMsgCosmosAuthzV1beta1MsgExecDataMsgGrant - | CelestiaTrxMsgCosmosAuthzV1beta1MsgExecDataMsgGrantAllowance - | CelestiaTrxMsgCosmosAuthzV1beta1MsgExecDataMsgRevokeAllowance - | CelestiaTrxMsgCosmosAuthzV1beta1MsgExecDataMsgDelegate - | CelestiaTrxMsgCosmosAuthzV1beta1MsgExecDataMsgTransfer - | CelestiaTrxMsgCosmosAuthzV1beta1MsgExecDataMsgWithdrawDelegatorReward - | CelestiaTrxMsgCosmosAuthzV1beta1MsgExecDataMsgMsgWithdrawValidatorCommission - )[]; - }; -} - -interface CelestiaTrxMsgCosmosAuthzV1beta1MsgExecDataMsgSend { - '@type': '/cosmos.bank.v1beta1.MsgSend'; - fromAddress: string; - toAddress: string; - amount: { - denom: string; - amount: string; - }[]; -} - -interface CelestiaTrxMsgCosmosAuthzV1beta1MsgExecDataMsgGrant { - '@type': '/cosmos.authz.v1beta1.MsgGrant'; - granter: string; - grantee: string; - grant: { - authorization: { - '@type': string; - msg: string; - }; - }; -} - -interface CelestiaTrxMsgCosmosAuthzV1beta1MsgExecDataMsgGrantAllowance { - '@type': '/cosmos.feegrant.v1beta1.MsgGrantAllowance'; - granter: string; - grantee: string; - allowance: { - '@type': string; - allowance: { - '@type': string; - }; - allowedMessages: string[]; - }; -} - -interface CelestiaTrxMsgCosmosAuthzV1beta1MsgExecDataMsgRevokeAllowance { - '@type': '/cosmos.feegrant.v1beta1.MsgRevokeAllowance'; - granter: string; - grantee: string; -} - -interface CelestiaTrxMsgCosmosAuthzV1beta1MsgExecDataMsgDelegate { - '@type': '/cosmos.staking.v1beta1.MsgDelegate'; - delegatorAddress: string; - validatorAddress: string; - amount: { - denom: string; - amount: string; - }; -} - -interface CelestiaTrxMsgCosmosAuthzV1beta1MsgExecDataMsgTransfer { - '@type': '/ibc.applications.transfer.v1.MsgTransfer'; - sourcePort: string; - sourceChannel: string; - token: { - denom: string; - amount: string; - }; - sender: string; - receiver: string; - timeoutHeight: { - revisionNumber: string; - revisionHeight: string; - }; - memo: string; -} - -interface CelestiaTrxMsgCosmosAuthzV1beta1MsgExecDataMsgWithdrawDelegatorReward { - '@type': '/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward'; - delegatorAddress: string; - validatorAddress: string; -} - -interface CelestiaTrxMsgCosmosAuthzV1beta1MsgExecDataMsgMsgWithdrawValidatorCommission { - '@type': '/cosmos.distribution.v1beta1.MsgWithdrawValidatorCommission'; - validatorAddress: string; -} - -// types for msg type:: /cosmos.authz.v1beta1.MsgGrant -export interface CelestiaTrxMsgCosmosAuthzV1beta1MsgGrant - extends IRangeMessage { - type: CelestiaTrxMsgTypes.CosmosAuthzV1beta1MsgGrant; - data: { - granter: string; - grantee: string; - grant: - | CelestiaTrxMsgCosmosAuthzV1beta1MsgGrantDataGrantSendAuthorization - | CelestiaTrxMsgCosmosAuthzV1beta1MsgGrantDataGrantStakeAuthorization - | CelestiaTrxMsgCosmosAuthzV1beta1MsgGrantDataGrantGenericAuthorization; - }; -} - -interface CelestiaTrxMsgCosmosAuthzV1beta1MsgGrantDataGrantSendAuthorization { - authorization: { - '@type': '/cosmos.bank.v1beta1.SendAuthorization'; - spendLimit: { - denom: string; - amount: string; - }[]; - expiration?: string; - }; -} - -interface CelestiaTrxMsgCosmosAuthzV1beta1MsgGrantDataGrantStakeAuthorization { - authorization: { - '@type': '/cosmos.staking.v1beta1.StakeAuthorization'; - maxTokens?: { - denom: string; - amount: string; - }; - allowList: { - address: string[]; - }; - authorizationType: string; - }; - expiration: string; -} - -interface CelestiaTrxMsgCosmosAuthzV1beta1MsgGrantDataGrantGenericAuthorization { - authorization: { - '@type': '/cosmos.authz.v1beta1.GenericAuthorization'; - msg: string; - }; - expiration?: string; -} - -// types for msg type:: /cosmos.authz.v1beta1.MsgRevoke -export interface CelestiaTrxMsgCosmosAuthzV1beta1MsgRevoke - extends IRangeMessage { - type: CelestiaTrxMsgTypes.CosmosAuthzV1beta1MsgRevoke; - data: { - grantee: string; - granter: string; - msgTypeUrl: string; - }; -} - -// types for msg type:: /cosmos.bank.v1beta1.MsgMultiSend -export interface CelestiaTrxMsgCosmosBankV1beta1MsgMultiSend - extends IRangeMessage { - type: CelestiaTrxMsgTypes.CosmosBankV1beta1MsgMultiSend; - data: { - inputs: { - coins: { - denom: string; - amount: string; - }[]; - address: string; - }[]; - outputs: { - coins: { - denom: string; - amount: string; - }[]; - address: string; - }[]; - }; -} - -// types for msg type:: /cosmos.bank.v1beta1.MsgSend -export interface CelestiaTrxMsgCosmosBankV1beta1MsgSend extends IRangeMessage { - type: CelestiaTrxMsgTypes.CosmosBankV1beta1MsgSend; - data: { - amount: { - denom: string; - amount: string; - }[]; - toAddress: string; - fromAddress: string; - }; -} - -// types for msg type: /cosmos.distribution.v1beta1.MsgSetWithdrawAddress -export interface CelestiaTrxMsgCosmosDistributionV1beta1MsgSetWithdrawAddress - extends IRangeMessage { - type: CelestiaTrxMsgTypes.CosmosDistributionV1beta1MsgSetWithdrawAddress; - data: { - withdrawAddress: string; - delegatorAddress: string; - }; -} - -// types for msg type: /cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward -export interface CelestiaTrxMsgCosmosDistributionV1beta1MsgWithdrawDelegatorReward - extends IRangeMessage { - type: CelestiaTrxMsgTypes.CosmosDistributionV1beta1MsgWithdrawDelegatorReward; - data: { - delegatorAddress: string; - validatorAddress: string; - }; -} - -// types for msg type: /cosmos.distribution.v1beta1.MsgWithdrawValidatorCommission -export interface CelestiaTrxMsgCosmosDistributionV1beta1MsgWithdrawValidatorCommission - extends IRangeMessage { - type: CelestiaTrxMsgTypes.CosmosDistributionV1beta1MsgWithdrawValidatorCommission; - data: { - validatorAddress: string; - }; -} - -// types for msg type: /cosmos.feegrant.v1beta1.MsgGrantAllowance -export interface CelestiaTrxMsgCosmosFeegrantV1beta1MsgGrantAllowance - extends IRangeMessage { - type: CelestiaTrxMsgTypes.CosmosFeegrantV1beta1MsgGrantAllowance; - data: { - granter: string; - grantee: string; - allowance: CelestiaTrxMsgCosmosFeegrantV1beta1MsgGrantAllowanceAllowedMsgAllowance; - }; -} - -interface CelestiaTrxMsgCosmosFeegrantV1beta1MsgGrantAllowanceAllowedMsgAllowance { - '@type': '/cosmos.feegrant.v1beta1.AllowedMsgAllowance'; - allowance: { - '@type': string; - }; - allowedMessages: string[]; -} - -// types for msg type: /cosmos.gov.v1beta1.MsgVote -export interface CelestiaTrxMsgCosmosGovV1beta1MsgVote extends IRangeMessage { - type: CelestiaTrxMsgTypes.CosmosGovV1beta1MsgVote; - data: { - voter: string; - option: - | string - | 'VOTE_OPTION_YES' - | 'VOTE_OPTION_ABSTAIN' - | 'VOTE_OPTION_NO'; - proposalId: string; - }; -} - -// types for msg type: /cosmos.slashing.v1beta1.MsgUnjail -export interface CelestiaTrxMsgCosmosSlashingV1beta1MsgUnjail - extends IRangeMessage { - type: CelestiaTrxMsgTypes.CosmosSlashingV1beta1MsgUnjail; - data: { - validatorAddr: string; - }; -} - -// types for msg type: /cosmos.staking.v1beta1.MsgBeginRedelegate -export interface CelestiaTrxMsgCosmosStakingV1beta1MsgBeginRedelegate - extends IRangeMessage { - type: CelestiaTrxMsgTypes.CosmosStakingV1beta1MsgBeginRedelegate; - data: { - amount: { - denom: string; - amount: string; - }; - delegatorAddress: string; - validatorDstAddress: string; - validatorSrcAddress: string; - }; -} - -// types for msg type: /cosmos.staking.v1beta1.MsgCancelUnbondingDelegation -export interface CelestiaTrxMsgCosmosStakingV1beta1MsgCancelUnbondingDelegation - extends IRangeMessage { - type: CelestiaTrxMsgTypes.CosmosStakingV1beta1MsgCancelUnbondingDelegation; - data: { - amount: { - denom: string; - amount: string; - }; - creationHeight: string; - delegatorAddress: string; - validatorAddress: string; - }; -} - -// types for msg type: /cosmos.staking.v1beta1.MsgCreateValidator -export interface CelestiaTrxMsgCosmosStakingV1beta1MsgCreateValidator - extends IRangeMessage { - type: CelestiaTrxMsgTypes.CosmosStakingV1beta1MsgCreateValidator; - data: { - value: { - denom: string; - amount: string; - }; - pubkey: { - key: string; - '@type': string; - }; - commission: { - rate: string; - maxRate: string; - maxChangeRate: string; - }; - description: { - details?: string; - moniker?: string; - website?: string; - identity?: string; - securityContact?: string; - }; - delegatorAddress: string; - validatorAddress: string; - minSelfDelegation: string; - }; -} - -// types for msg type: /cosmos.staking.v1beta1.MsgDelegate -export interface CelestiaTrxMsgCosmosStakingV1beta1MsgDelegate - extends IRangeMessage { - type: CelestiaTrxMsgTypes.CosmosStakingV1beta1MsgDelegate; - data: { - amount: { - denom: string; - amount: string; - }; - delegatorAddress: string; - validatorAddress: string; - }; -} - -// types for msg type: /cosmos.staking.v1beta1.MsgEditValidator -export interface CelestiaTrxMsgCosmosStakingV1beta1MsgEditValidator - extends IRangeMessage { - type: CelestiaTrxMsgTypes.CosmosStakingV1beta1MsgEditValidator; - data: { - description: { - details?: string; - moniker?: string; - website?: string; - identity?: string; - securityContact?: string; - }; - commissionRate?: string; - validatorAddress: string; - minSelfDelegation?: string; - }; -} - -// types for msg type: /cosmos.staking.v1beta1.MsgUndelegate -export interface CelestiaTrxMsgCosmosStakingV1beta1MsgUndelegate - extends IRangeMessage { - type: CelestiaTrxMsgTypes.CosmosStakingV1beta1MsgUndelegate; - data: { - amount: { - denom: string; - amount: string; - }; - delegatorAddress: string; - validatorAddress: string; - }; -} - -// types for msg type: /cosmos.vesting.v1beta1.MsgCreateVestingAccount -export interface CelestiaTrxMsgCosmosVestingV1beta1MsgCreateVestingAccount - extends IRangeMessage { - type: CelestiaTrxMsgTypes.CosmosVestingV1beta1MsgCreateVestingAccount; - data: { - amount: { - denom: string; - amount: string; - }[]; - delayed?: boolean; - endTime: string; - toAddress: string; - fromAddress: string; - }; -} - -// types for msg type: /ibc.applications.transfer.v1.MsgTransfer -export interface CelestiaTrxMsgIbcApplicationsTransferV1MsgTransfer - extends IRangeMessage { - type: CelestiaTrxMsgTypes.IbcApplicationsTransferV1MsgTransfer; - data: { - memo?: string; - token: { - denom: string; - amount: string; - }; - sender: string; - receiver: string; - sourcePort: string; - sourceChannel: string; - timeoutHeight?: { - revisionHeight?: string; - revisionNumber?: string; - }; - timeoutTimestamp?: string; - }; -} - -// types for msg type: /ibc.core.channel.v1.MsgAcknowledgement -export interface CelestiaTrxMsgIbcCoreChannelV1MsgAcknowledgement - extends IRangeMessage { - type: CelestiaTrxMsgTypes.IbcCoreChannelV1MsgAcknowledgement; - data: { - packet: { - data: string; - sequence: string; - sourcePort: string; - sourceChannel: string; - timeoutHeight: { - revisionHeight?: string; - revisionNumber?: string; - }; - destinationPort: string; - destinationChannel: string; - timeoutTimestamp?: string; - }; - signer: string; - proofAcked: string; - proofHeight: { - revisionHeight: string; - revisionNumber: string; - }; - acknowledgement: string; - }; -} - -// types for msg type: /ibc.core.channel.v1.MsgChannelOpenAck -export interface CelestiaTrxMsgIbcCoreChannelV1MsgChannelOpenAck - extends IRangeMessage { - type: CelestiaTrxMsgTypes.IbcCoreChannelV1MsgChannelOpenAck; - data: { - portId: string; - signer: string; - proofTry: string; - channelId: string; - proofHeight: { - revisionHeight: string; - revisionNumber: string; - }; - counterpartyVersion: string; - counterpartyChannelId: string; - }; -} - -// types for msg type: /ibc.core.channel.v1.MsgChannelOpenConfirm -export interface CelestiaTrxMsgIbcCoreChannelV1MsgChannelOpenConfirm - extends IRangeMessage { - type: CelestiaTrxMsgTypes.IbcCoreChannelV1MsgChannelOpenConfirm; - data: { - portId: string; - signer: string; - proofAck: string; - channelId: string; - proofHeight: { - revisionHeight: string; - revisionNumber: string; - }; - }; -} - -// types for msg type: /ibc.core.channel.v1.MsgChannelOpenInit -export interface CelestiaTrxMsgIbcCoreChannelV1MsgChannelOpenInit - extends IRangeMessage { - type: CelestiaTrxMsgTypes.IbcCoreChannelV1MsgChannelOpenInit; - data: { - portId: string; - channel: { - state: string; - ordering: string; - counterparty: { - portId: string; - }; - connectionHops: string[]; - version: string; - }; - signer: string; - }; -} - -// types for msg type: /ibc.core.channel.v1.MsgChannelOpenTry -export interface CelestiaTrxMsgIbcCoreChannelV1MsgChannelOpenTry - extends IRangeMessage { - type: CelestiaTrxMsgTypes.IbcCoreChannelV1MsgChannelOpenTry; - data: { - portId: string; - signer: string; - channel: { - state: string; - version: string; - ordering: string; - counterparty: { - portId: string; - channelId: string; - }; - connectionHops: string[]; - }; - proofInit: string; - proofHeight: { - revisionHeight: string; - revisionNumber: string; - }; - counterpartyVersion: string; - }; -} - -// types for msg type: /ibc.core.channel.v1.MsgRecvPacket -export interface CelestiaTrxMsgIbcCoreChannelV1MsgRecvPacket - extends IRangeMessage { - type: CelestiaTrxMsgTypes.IbcCoreChannelV1MsgRecvPacket; - data: { - packet: { - data: string; - sequence: string; - sourcePort: string; - sourceChannel: string; - timeoutHeight: { - revisionHeight?: string; - revisionNumber?: string; - }; - destinationPort: string; - timeoutTimestamp?: string; - destinationChannel: string; - }; - signer: string; - proofHeight: { - revisionHeight: string; - revisionNumber: string; - }; - proofCommitment: string; - }; -} - -// types for msg type: /ibc.core.channel.v1.MsgTimeout -export interface CelestiaTrxMsgIbcCoreChannelV1MsgTimeout - extends IRangeMessage { - type: CelestiaTrxMsgTypes.IbcCoreChannelV1MsgTimeout; - data: { - packet: { - data: string; - sequence: string; - sourcePort: string; - sourceChannel: string; - timeoutHeight: { - revisionHeight?: string; - revisionNumber?: string; - }; - destinationPort: string; - timeoutTimestamp?: string; - destinationChannel: string; - }; - signer: string; - proofHeight: { - revisionHeight: string; - revisionNumber: string; - }; - proofUnreceived: string; - nextSequenceRecv: string; - }; -} - -// types for msg type: /ibc.core.client.v1.MsgCreateClient -export interface CelestiaTrxMsgIbcCoreClientV1MsgCreateClient - extends IRangeMessage { - type: CelestiaTrxMsgTypes.IbcCoreClientV1MsgCreateClient; - data: { - signer: string; - clientState: { - '@type': string; - chainId: string; - proofSpecs: { - leafSpec: { - hash: string; - length: string; - prefix: string; - prehashValue: string; - }; - innerSpec: { - hash: string; - childSize: number; - childOrder: number[]; - maxPrefixLength: number; - minPrefixLength: number; - }; - }[]; - trustLevel: { - numerator: string; - denominator: string; - }; - upgradePath: string[]; - frozenHeight: Record; - latestHeight: { - revisionHeight: string; - revisionNumber: string; - }; - maxClockDrift: string; - trustingPeriod: string; - unbondingPeriod: string; - allowUpdateAfterExpiry: boolean; - allowUpdateAfterMisbehaviour: boolean; - }; - consensusState: { - root: { - hash: string; - }; - '@type': string; - timestamp: string; - nextValidatorsHash: string; - }; - }; -} - -// types for msg type: /ibc.core.client.v1.MsgUpdateClient -export interface CelestiaTrxMsgIbcCoreClientV1MsgUpdateClient - extends IRangeMessage { - type: CelestiaTrxMsgTypes.IbcCoreClientV1MsgUpdateClient; - data: { - clientId: string; - clientMessage: { - '@type': string; - signedHeader: { - header: { - version: { - block: string; - app?: string; - }; - chainId: string; - height: string; - time: string; - lastBlockId: { - hash: string; - partSetHeader: { - total: number; - hash: string; - }; - }; - lastCommitHash: string; - dataHash: string; - validatorsHash: string; - nextValidatorsHash: string; - consensusHash: string; - appHash: string; - lastResultsHash: string; - evidenceHash: string; - proposerAddress: string; - }; - commit: { - height: string; - round?: number; - blockId: { - hash: string; - partSetHeader: { - total: number; - hash: string; - }; - }; - signatures: { - blockIdFlag: string; - validatorAddress?: string; - timestamp?: string; - signature?: string; - }[]; - }; - }; - validatorSet: { - validators: { - address: string; - pubKey: { - ed25519: string; - }; - votingPower: string; - proposerPriority?: string; - }[]; - proposer: { - address: string; - pubKey: { - ed25519: string; - }; - votingPower: string; - proposerPriority?: string; - }; - totalVotingPower?: string; - }; - trustedHeight: { - revisionNumber?: string; - revisionHeight: string; - }; - trustedValidators: { - validators: { - address: string; - pubKey: { - ed25519: string; - }; - votingPower: string; - proposerPriority?: string; - }[]; - proposer: { - address: string; - pubKey: { - ed25519: string; - }; - votingPower: string; - proposerPriority?: string; - }; - totalVotingPower?: string; - }; - }; - signer: string; - }; -} - -// types for msg type: /ibc.core.connection.v1.MsgConnectionOpenAck -export interface CelestiaTrxMsgIbcCoreConnectionV1MsgConnectionOpenAck - extends IRangeMessage { - type: CelestiaTrxMsgTypes.IbcCoreConnectionV1MsgConnectionOpenAck; - data: { - signer: string; - version: { - features: string[]; - identifier: string; - }; - proofTry: string; - clientState: { - '@type': string; - chainId: string; - proofSpecs: { - leafSpec: { - hash: string; - length: string; - prefix: string; - prehashValue: string; - }; - innerSpec: { - hash: string; - childSize: number; - childOrder: number[]; - maxPrefixLength: number; - minPrefixLength: number; - }; - }[]; - trustLevel: { - numerator: string; - denominator: string; - }; - upgradePath: string[]; - frozenHeight: Record; - latestHeight: { - revisionHeight: string; - }; - maxClockDrift: string; - trustingPeriod: string; - unbondingPeriod: string; - allowUpdateAfterExpiry: boolean; - allowUpdateAfterMisbehaviour: boolean; - }; - proofClient: string; - proofHeight: { - revisionHeight: string; - revisionNumber: string; - }; - connectionId: string; - proofConsensus: string; - consensusHeight: { - revisionHeight: string; - }; - counterpartyConnectionId: string; - }; -} - -// types for msg type: /ibc.core.connection.v1.MsgConnectionOpenConfirm -export interface CelestiaTrxMsgIbcCoreConnectionV1MsgConnectionOpenConfirm - extends IRangeMessage { - type: CelestiaTrxMsgTypes.IbcCoreConnectionV1MsgConnectionOpenConfirm; - data: { - signer: string; - proofAck: string; - proofHeight: { - revisionHeight: string; - revisionNumber: string; - }; - connectionId: string; - }; -} - -// types for msg type: /ibc.core.connection.v1.MsgConnectionOpenInit -export interface CelestiaTrxMsgIbcCoreConnectionV1MsgConnectionOpenInit - extends IRangeMessage { - type: CelestiaTrxMsgTypes.IbcCoreConnectionV1MsgConnectionOpenInit; - data: { - clientId: string; - counterparty: { - clientId: string; - prefix: { - keyPrefix: string; - }; - }; - version?: { - features: string[]; - identifier: string; - }; - signer: string; - }; -} - -// types for msg type: /ibc.core.connection.v1.MsgConnectionOpenTry -export interface CelestiaTrxMsgIbcCoreConnectionV1MsgConnectionOpenTry - extends IRangeMessage { - type: CelestiaTrxMsgTypes.IbcCoreConnectionV1MsgConnectionOpenTry; - data: { - signer: string; - clientId: string; - proofInit: string; - clientState: { - '@type': string; - chainId: string; - proofSpecs: { - leafSpec: { - hash: string; - length: string; - prefix: string; - prehashValue: string; - }; - innerSpec: { - hash: string; - childSize: number; - childOrder: number[]; - maxPrefixLength: number; - minPrefixLength: number; - }; - }[]; - trustLevel: { - numerator: string; - denominator: string; - }; - upgradePath: string[]; - frozenHeight: Record; - latestHeight: { - revisionHeight: string; - }; - maxClockDrift: string; - trustingPeriod: string; - unbondingPeriod: string; - allowUpdateAfterExpiry: boolean; - allowUpdateAfterMisbehaviour: boolean; - }; - proofClient: string; - proofHeight: { - revisionHeight: string; - revisionNumber: string; - }; - counterparty: { - prefix: { - keyPrefix: string; - }; - clientId: string; - connectionId: string; - }; - proofConsensus: string; - consensusHeight: { - revisionHeight: string; - }; - counterpartyVersions: { - features: string[]; - identifier: string; - }[]; - }; -} diff --git a/src/types/chain/cosmoshub-4/IRangeBlockCosmosHub4Trx.ts b/src/types/chain/cosmoshub-4/IRangeBlockCosmosHub4Trx.ts deleted file mode 100644 index 3385c5fb..00000000 --- a/src/types/chain/cosmoshub-4/IRangeBlockCosmosHub4Trx.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { IRangeTransaction } from '../IRangeTransaction'; -import { CosmosHub4TrxMsg } from './IRangeBlockCosmosHub4TrxMsg'; - -export interface CosmosHub4Trx extends IRangeTransaction { - messages: CosmosHub4TrxMsg[]; -} diff --git a/src/types/chain/cosmoshub-4/IRangeBlockCosmosHub4TrxMsg.ts b/src/types/chain/cosmoshub-4/IRangeBlockCosmosHub4TrxMsg.ts deleted file mode 100644 index 90defda4..00000000 --- a/src/types/chain/cosmoshub-4/IRangeBlockCosmosHub4TrxMsg.ts +++ /dev/null @@ -1,980 +0,0 @@ -import { IRangeMessage } from '../IRangeMessage'; - -export type CosmosHub4TrxMsg = - | CosmosHub4TrxMsgCosmosAuthzV1beta1MsgExec - | CosmosHub4TrxMsgCosmosAuthzV1beta1MsgGrant - | CosmosHub4TrxMsgCosmosAuthzV1beta1MsgRevoke - | CosmosHub4TrxMsgCosmosBankV1beta1MsgMultiSend - | CosmosHub4TrxMsgCosmosBankV1beta1MsgSend - | CosmosHub4TrxMsgCosmosDistributionV1beta1MsgSetWithdrawAddress - | CosmosHub4TrxMsgCosmosDistributionV1beta1MsgWithdrawDelegatorReward - | CosmosHub4TrxMsgWithdrawValidatorCommission - | CosmosHub4TrxMsgCosmosFeegrantV1beta1MsgGrantAllowance - | CosmosHub4TrxMsgCosmosGovV1beta1MsgDeposit - | CosmosHub4TrxMsgCosmosGovV1beta1MsgSubmitProposal - | CosmosHub4TrxMsgCosmosGovV1beta1MsgVote - | CosmosHub4TrxMsgCosmosGovV1beta1MsgVoteWeighted - | CosmosHub4TrxMsgCosmosSlashingV1beta1MsgUnjail - | CosmosHub4TrxMsgCosmosStakingV1beta1MsgBeginRedelegate - | CosmosHub4TrxMsgCosmosStakingV1beta1MsgCancelUnbondingDelegation - | CosmosHub4TrxMsgCosmosStakingV1beta1MsgCreateValidator - | CosmosHub4TrxMsgCosmosStakingV1beta1MsgDelegate - | CosmosHub4TrxMsgCosmosStakingV1beta1MsgEditValidator - | CosmosHub4TrxMsgCosmosStakingV1beta1MsgUndelegate - | CosmosHub4TrxMsgIbcApplicationsTransferV1MsgTransfer - | CosmosHub4TrxMsgIbcCoreChannelV1MsgAcknowledgement - | CosmosHub4TrxMsgIbcCoreChannelV1MsgChannelCloseConfirm - | CosmosHub4TrxMsgIbcCoreChannelV1MsgChannelOpenConfirm - | CosmosHub4TrxMsgIbcCoreChannelV1MsgChannelOpenTry - | CosmosHub4TrxMsgIbcCoreChannelV1MsgRecvPacket - | CosmosHub4TrxMsgIbcCoreChannelV1MsgTimeout - | CosmosHub4TrxMsgIbcCoreClientV1MsgCreateClient - | CosmosHub4TrxMsgIbcCoreClientV1MsgSubmitMisbehaviour - | CosmosHub4TrxMsgIbcCoreClientV1MsgUpdateClient; - -export enum CosmosHub4TrxMsgTypes { - CosmosAuthzV1beta1MsgExec = 'cosmos.authz.v1beta1.MsgExec', - CosmosAuthzV1beta1MsgGrant = 'cosmos.authz.v1beta1.MsgGrant', - CosmosAuthzV1beta1MsgRevoke = 'cosmos.authz.v1beta1.MsgRevoke', - CosmosBankV1beta1MsgMultiSend = 'cosmos.bank.v1beta1.MsgMultiSend', - CosmosBankV1beta1MsgSend = 'cosmos.bank.v1beta1.MsgSend', - CosmosDistributionV1beta1MsgSetWithdrawAddress = 'cosmos.distribution.v1beta1.MsgSetWithdrawAddress', - CosmosDistributionV1beta1MsgWithdrawDelegatorReward = 'cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward', - CosmosDistributionV1beta1MsgWithdrawValidatorCommission = 'cosmos.distribution.v1beta1.MsgWithdrawValidatorCommission', - CosmosFeegrantV1beta1MsgGrantAllowance = 'cosmos.feegrant.v1beta1.MsgGrantAllowance', - CosmosGovV1beta1MsgDeposit = 'cosmos.gov.v1beta1.MsgDeposit', - CosmosGovV1beta1MsgSubmitProposal = 'cosmos.gov.v1beta1.MsgSubmitProposal', - CosmosGovV1beta1MsgVote = 'cosmos.gov.v1beta1.MsgVote', - CosmosGovV1beta1MsgVoteWeighted = 'cosmos.gov.v1beta1.MsgVoteWeighted', - CosmosSlashingV1beta1MsgUnjail = 'cosmos.slashing.v1beta1.MsgUnjail', - CosmosStakingV1beta1MsgBeginRedelegate = 'cosmos.staking.v1beta1.MsgBeginRedelegate', - CosmosStakingV1beta1MsgCancelUnbondingDelegation = 'cosmos.staking.v1beta1.MsgCancelUnbondingDelegation', - CosmosStakingV1beta1MsgCreateValidator = 'cosmos.staking.v1beta1.MsgCreateValidator', - CosmosStakingV1beta1MsgDelegate = 'cosmos.staking.v1beta1.MsgDelegate', - CosmosStakingV1beta1MsgEditValidator = 'cosmos.staking.v1beta1.MsgEditValidator', - CosmosStakingV1beta1MsgUndelegate = 'cosmos.staking.v1beta1.MsgUndelegate', - IbcApplicationsTransferV1MsgTransfer = 'ibc.applications.transfer.v1.MsgTransfer', - IbcCoreChannelV1MsgAcknowledgement = 'ibc.core.channel.v1.MsgAcknowledgement', - IbcCoreChannelV1MsgChannelCloseConfirm = 'ibc.core.channel.v1.MsgChannelCloseConfirm', - IbcCoreChannelV1MsgChannelOpenConfirm = 'ibc.core.channel.v1.MsgChannelOpenConfirm', - IbcCoreChannelV1MsgChannelOpenTry = 'ibc.core.channel.v1.MsgChannelOpenTry', - IbcCoreChannelV1MsgRecvPacket = 'ibc.core.channel.v1.MsgRecvPacket', - IbcCoreChannelV1MsgTimeout = 'ibc.core.channel.v1.MsgTimeout', - IbcCoreClientV1MsgCreateClient = 'ibc.core.client.v1.MsgCreateClient', - IbcCoreClientV1MsgSubmitMisbehaviour = 'ibc.core.client.v1.MsgSubmitMisbehaviour', - IbcCoreClientV1MsgUpdateClient = 'ibc.core.client.v1.MsgUpdateClient', -} - -// types for mgs type:: /cosmos.authz.v1beta1.MsgExec -export interface CosmosHub4TrxMsgCosmosAuthzV1beta1MsgExec - extends IRangeMessage { - type: CosmosHub4TrxMsgTypes.CosmosAuthzV1beta1MsgExec; - data: { - grantee: string; - msgs: ( - | CosmosHub4TrxMsgCosmosAuthzV1beta1MsgExecDataMsgsTypeMsgSend - | CosmosHub4TrxMsgCosmosAuthzV1beta1MsgExecDataMsgsTypeMsgDelegate - | CosmosHub4TrxMsgCosmosAuthzV1beta1MsgExecDataMsgsTypeMsgUndelegate - | CosmosHub4TrxMsgCosmosAuthzV1beta1MsgExecDataMsgsTypeMsgWithdrawDelegatorReward - | CosmosHub4TrxMsgCosmosAuthzV1beta1MsgExecDataMsgsTypeMsgSetWithdrawAddress - | CosmosHub4TrxMsgCosmosAuthzV1beta1MsgExecDataMsgsTypeMsgMsgWithdrawValidatorCommission - | CosmosHub4TrxMsgCosmosAuthzV1beta1MsgExecDataMsgsTypeMsgVote - | CosmosHub4TrxMsgCosmosAuthzV1beta1MsgExecDataMsgsTypeMsgGrant - | CosmosHub4TrxMsgCosmosAuthzV1beta1MsgExecDataMsgsTypeMsgRevoke - )[]; - }; -} - -interface CosmosHub4TrxMsgCosmosAuthzV1beta1MsgExecDataMsgsTypeMsgSend { - '@type': '/cosmos.bank.v1beta1.MsgSend'; - fromAddress: string; - toAddress: string; - amount: { - denom: string; - amount: string; - }[]; -} - -interface CosmosHub4TrxMsgCosmosAuthzV1beta1MsgExecDataMsgsTypeMsgDelegate { - '@type': '/cosmos.staking.v1beta1.MsgDelegate'; - delegatorAddress: string; - validatorAddress: string; - amount: { - denom: string; - amount: string; - }; -} - -interface CosmosHub4TrxMsgCosmosAuthzV1beta1MsgExecDataMsgsTypeMsgUndelegate { - '@type': '/cosmos.staking.v1beta1.MsgUndelegate'; - delegatorAddress: string; - validatorAddress: string; - amount: { - denom: string; - amount: string; - }; -} - -interface CosmosHub4TrxMsgCosmosAuthzV1beta1MsgExecDataMsgsTypeMsgWithdrawDelegatorReward { - '@type': '/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward'; - delegatorAddress: string; - validatorAddress: string; -} - -interface CosmosHub4TrxMsgCosmosAuthzV1beta1MsgExecDataMsgsTypeMsgSetWithdrawAddress { - '@type': '/cosmos.distribution.v1beta1.MsgSetWithdrawAddress'; - delegatorAddress: string; - withdrawAddress: string; -} - -interface CosmosHub4TrxMsgCosmosAuthzV1beta1MsgExecDataMsgsTypeMsgMsgWithdrawValidatorCommission { - '@type': '/cosmos.distribution.v1beta1.MsgWithdrawValidatorCommission'; - validatorAddress: string; -} - -interface CosmosHub4TrxMsgCosmosAuthzV1beta1MsgExecDataMsgsTypeMsgVote { - '@type': '/cosmos.gov.v1beta1.MsgVote' | '/cosmos.gov.v1.MsgVote'; - proposalId: string; - voter: string; - option: string; -} - -interface CosmosHub4TrxMsgCosmosAuthzV1beta1MsgExecDataMsgsTypeMsgGrant { - '@type': '/cosmos.authz.v1beta1.MsgGrant'; - granter: string; - grantee: string; - grant: { - authorization: { - '@type': string; - msg: string; - }; - expiration: string; - }; -} - -interface CosmosHub4TrxMsgCosmosAuthzV1beta1MsgExecDataMsgsTypeMsgRevoke { - '@type': '/cosmos.authz.v1beta1.MsgRevoke'; - granter: string; - grantee: string; - msgTypeUrl: string; -} - -// types for msg type:: /cosmos.authz.v1beta1.MsgGrant -export interface CosmosHub4TrxMsgCosmosAuthzV1beta1MsgGrant - extends IRangeMessage { - type: CosmosHub4TrxMsgTypes.CosmosAuthzV1beta1MsgGrant; - data: { - granter: string; - grantee: string; - grant: - | CosmosHub4TrxMsgCosmosAuthzV1beta1MsgGrantDataGrantStakeAuthorization - | CosmosHub4TrxMsgCosmosAuthzV1beta1MsgGrantDataGrantGenericAuthorization - | CosmosHub4TrxMsgCosmosAuthzV1beta1MsgGrantDataGrantSendAuthorization; - }; -} - -interface CosmosHub4TrxMsgCosmosAuthzV1beta1MsgGrantDataGrantStakeAuthorization { - authorization: { - '@type': '/cosmos.staking.v1beta1.StakeAuthorization'; - authorizationType: string; - allowList?: { - address: string[]; - }; - maxTokens?: { - denom: string; - amount: string; - }; - }; - expiration?: string; -} - -interface CosmosHub4TrxMsgCosmosAuthzV1beta1MsgGrantDataGrantGenericAuthorization { - authorization: { - '@type': '/cosmos.authz.v1beta1.GenericAuthorization'; - msg: string; - }; - expiration?: string; -} - -interface CosmosHub4TrxMsgCosmosAuthzV1beta1MsgGrantDataGrantSendAuthorization { - authorization: { - '@type': '/cosmos.bank.v1beta1.SendAuthorization'; - spendLimit: { denom: string; amount: string }[]; - }; - expiration: string; -} - -// types for msg type:: /cosmos.authz.v1beta1.MsgRevoke -export interface CosmosHub4TrxMsgCosmosAuthzV1beta1MsgRevoke - extends IRangeMessage { - type: CosmosHub4TrxMsgTypes.CosmosAuthzV1beta1MsgRevoke; - data: { - grantee: string; - granter: string; - msgTypeUrl: string; - }; -} - -// types for msg type:: /cosmos.bank.v1beta1.MsgMultiSend -export interface CosmosHub4TrxMsgCosmosBankV1beta1MsgMultiSend - extends IRangeMessage { - type: CosmosHub4TrxMsgTypes.CosmosBankV1beta1MsgMultiSend; - data: { - inputs: { - coins: { - denom: string; - amount: string; - }[]; - address: string; - }[]; - outputs: { - coins: { - denom: string; - amount: string; - }[]; - address: string; - }[]; - }; -} - -// types for msg type:: /cosmos.bank.v1beta1.MsgSend -export interface CosmosHub4TrxMsgCosmosBankV1beta1MsgSend - extends IRangeMessage { - type: CosmosHub4TrxMsgTypes.CosmosBankV1beta1MsgSend; - data: { - amount: { - denom: string; - amount: string; - }[]; - toAddress: string; - fromAddress: string; - }; -} - -// types for mgs type:: /cosmos.distribution.v1beta1.MsgSetWithdrawAddress -export interface CosmosHub4TrxMsgCosmosDistributionV1beta1MsgSetWithdrawAddress - extends IRangeMessage { - type: CosmosHub4TrxMsgTypes.CosmosDistributionV1beta1MsgSetWithdrawAddress; - data: { - withdrawAddress: string; - delegatorAddress: string; - }; -} - -// types for msg type:: /cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward -export interface CosmosHub4TrxMsgCosmosDistributionV1beta1MsgWithdrawDelegatorReward - extends IRangeMessage { - type: CosmosHub4TrxMsgTypes.CosmosDistributionV1beta1MsgWithdrawDelegatorReward; - data: { - delegatorAddress: string; - validatorAddress: string; - }; -} - -// types for msg type:: /cosmos.distribution.v1beta1.MsgWithdrawValidatorCommission -export interface CosmosHub4TrxMsgWithdrawValidatorCommission - extends IRangeMessage { - type: CosmosHub4TrxMsgTypes.CosmosDistributionV1beta1MsgWithdrawValidatorCommission; - data: { - validatorAddress: string; - }; -} - -// types for msg type:: /cosmos.feegrant.v1beta1.MsgGrantAllowance -export interface CosmosHub4TrxMsgCosmosFeegrantV1beta1MsgGrantAllowance - extends IRangeMessage { - type: CosmosHub4TrxMsgTypes.CosmosFeegrantV1beta1MsgGrantAllowance; - data: { - granter: string; - grantee: string; - allowance: - | CosmosHub4TrxMsgCosmosFeegrantV1beta1MsgGrantAllowanceDataBasicAllowance - | CosmosHub4TrxMsgCosmosFeegrantV1beta1MsgGrantAllowanceDataPeriodicAllowance; - }; -} - -interface CosmosHub4TrxMsgCosmosFeegrantV1beta1MsgGrantAllowanceDataBasicAllowance { - '@type': '/cosmos.feegrant.v1beta1.BasicAllowance'; - expiration?: string; - spendLimit: { - denom: string; - amount: string; - }[]; -} - -interface CosmosHub4TrxMsgCosmosFeegrantV1beta1MsgGrantAllowanceDataPeriodicAllowance { - '@type': '/cosmos.feegrant.v1beta1.PeriodicAllowance'; - period: string; - periodSpendLimit: { - denom: string; - amount: string; - }[]; - periodCanSpend: { - denom: string; - amount: string; - }[]; - periodReset: string; -} - -// types for msg type:: /cosmos.gov.v1beta1.MsgDeposit -export interface CosmosHub4TrxMsgCosmosGovV1beta1MsgDeposit - extends IRangeMessage { - type: CosmosHub4TrxMsgTypes.CosmosGovV1beta1MsgDeposit; - data: { - amount: { - denom: string; - amount: string; - }[]; - depositor: string; - proposalId: string; - }; -} - -// types for msg type:: /cosmos.gov.v1beta1.MsgSubmitProposal -export interface CosmosHub4TrxMsgCosmosGovV1beta1MsgSubmitProposal - extends IRangeMessage { - type: CosmosHub4TrxMsgTypes.CosmosGovV1beta1MsgSubmitProposal; - data: { - content: - | CosmosHub4TrxMsgCosmosGovV1beta1MsgSubmitProposalDataContentTypeTextProposal - | CosmosHub4TrxMsgCosmosGovV1beta1MsgSubmitProposalDataContentTypeSoftwareUpgradeProposal - | CosmosHub4TrxMsgCosmosGovV1beta1MsgSubmitProposalDataContentTypeClientUpdateProposal; - initialDeposit: { - denom: string; - amount: string; - }[]; - proposer: string; - }; -} - -interface CosmosHub4TrxMsgCosmosGovV1beta1MsgSubmitProposalDataContentTypeTextProposal { - '@type': '/cosmos.gov.v1beta1.TextProposal'; - title: string; - description: string; -} - -interface CosmosHub4TrxMsgCosmosGovV1beta1MsgSubmitProposalDataContentTypeSoftwareUpgradeProposal { - '@type': '/cosmos.upgrade.v1beta1.SoftwareUpgradeProposal'; - title: string; - description: string; - plan: { - info: string; - name: string; - height: string; - }; -} - -interface CosmosHub4TrxMsgCosmosGovV1beta1MsgSubmitProposalDataContentTypeClientUpdateProposal { - '@type': '/ibc.core.client.v1.ClientUpdateProposal'; - title: string; - description: string; - subjectClientId: string; - substituteClientId: string; -} - -// types for msg type:: /cosmos.gov.v1beta1.MsgVote -export interface CosmosHub4TrxMsgCosmosGovV1beta1MsgVote extends IRangeMessage { - type: CosmosHub4TrxMsgTypes.CosmosGovV1beta1MsgVote; - data: { - voter: string; - option: string; - proposalId: string; - }; -} - -// types for msg type:: /cosmos.gov.v1beta1.MsgVoteWeighted -export interface CosmosHub4TrxMsgCosmosGovV1beta1MsgVoteWeighted - extends IRangeMessage { - type: CosmosHub4TrxMsgTypes.CosmosGovV1beta1MsgVoteWeighted; - data: { - voter: string; - options: { - option: string; - weight: string; - }[]; - proposalId: string; - }; -} - -// types for msg type:: /cosmos.slashing.v1beta1.MsgUnjail -export interface CosmosHub4TrxMsgCosmosSlashingV1beta1MsgUnjail - extends IRangeMessage { - type: CosmosHub4TrxMsgTypes.CosmosSlashingV1beta1MsgUnjail; - data: { - validatorAddr: string; - }; -} - -// types for msg type:: /cosmos.staking.v1beta1.MsgBeginRedelegate -export interface CosmosHub4TrxMsgCosmosStakingV1beta1MsgBeginRedelegate - extends IRangeMessage { - type: CosmosHub4TrxMsgTypes.CosmosStakingV1beta1MsgBeginRedelegate; - data: { - amount: { - denom: string; - amount: string; - }; - delegatorAddress: string; - validatorDstAddress: string; - validatorSrcAddress: string; - }; -} - -// types for msg type:: /cosmos.staking.v1beta1.MsgCancelUnbondingDelegation -export interface CosmosHub4TrxMsgCosmosStakingV1beta1MsgCancelUnbondingDelegation - extends IRangeMessage { - type: CosmosHub4TrxMsgTypes.CosmosStakingV1beta1MsgCancelUnbondingDelegation; - data: { - amount: { - denom: string; - amount: string; - }; - creationHeight: string; - delegatorAddress: string; - validatorAddress: string; - }; -} - -// types for msg type:: /cosmos.staking.v1beta1.MsgCreateValidator -export interface CosmosHub4TrxMsgCosmosStakingV1beta1MsgCreateValidator - extends IRangeMessage { - type: CosmosHub4TrxMsgTypes.CosmosStakingV1beta1MsgCreateValidator; - data: { - description: { - moniker?: string; - identity?: string; - website?: string; - details?: string; - securityContact?: string; - }; - commission: { - rate: string; - maxRate: string; - maxChangeRate: string; - }; - minSelfDelegation: string; - delegatorAddress: string; - validatorAddress: string; - pubkey: { - '@type': string; - key: string; - }; - value: { - denom: string; - amount: string; - }; - }; -} - -// types for msg type:: /cosmos.staking.v1beta1.MsgDelegate -export interface CosmosHub4TrxMsgCosmosStakingV1beta1MsgDelegate - extends IRangeMessage { - type: CosmosHub4TrxMsgTypes.CosmosStakingV1beta1MsgDelegate; - data: { - amount: { - denom: string; - amount: string; - }; - delegatorAddress: string; - validatorAddress: string; - }; -} - -// types for msg type:: /cosmos.staking.v1beta1.MsgEditValidator -export interface CosmosHub4TrxMsgCosmosStakingV1beta1MsgEditValidator - extends IRangeMessage { - type: CosmosHub4TrxMsgTypes.CosmosStakingV1beta1MsgEditValidator; - data: { - description: { - moniker: string; - identity?: string; - website?: string; - securityContact?: string; - details?: string; - }; - validatorAddress: string; - commissionRate?: string; - minSelfDelegation?: string; - }; -} - -// types for msg type:: /cosmos.staking.v1beta1.MsgUndelegate -export interface CosmosHub4TrxMsgCosmosStakingV1beta1MsgUndelegate - extends IRangeMessage { - type: CosmosHub4TrxMsgTypes.CosmosStakingV1beta1MsgUndelegate; - data: { - amount: { - denom: string; - amount: string; - }; - delegatorAddress: string; - validatorAddress: string; - }; -} - -// types for msg type:: /ibc.applications.transfer.v1.MsgTransfer -export interface CosmosHub4TrxMsgIbcApplicationsTransferV1MsgTransfer - extends IRangeMessage { - type: CosmosHub4TrxMsgTypes.IbcApplicationsTransferV1MsgTransfer; - data: { - sourcePort: string; - sourceChannel: string; - token: { - denom: string; - amount: string; - }; - sender: string; - receiver: string; - timeoutHeight?: { - revisionNumber?: string; - revisionHeight?: string; - }; - timeoutTimestamp?: string; - memo?: string; - }; -} - -// types for msg type:: /ibc.core.channel.v1.MsgAcknowledgement -export interface CosmosHub4TrxMsgIbcCoreChannelV1MsgAcknowledgement - extends IRangeMessage { - type: CosmosHub4TrxMsgTypes.IbcCoreChannelV1MsgAcknowledgement; - data: { - packet: { - sequence: string; - sourcePort: string; - sourceChannel: string; - destinationPort: string; - destinationChannel: string; - data: string; - timeoutHeight: { - revisionNumber?: string; - revisionHeight?: string; - }; - timeoutTimestamp?: string; - }; - acknowledgement: string; - proofAcked: string; - proofHeight: { - revisionNumber?: string; - revisionHeight?: string; - }; - signer: string; - }; -} - -// types for msg type:: /ibc.core.channel.v1.MsgChannelCloseConfirm -export interface CosmosHub4TrxMsgIbcCoreChannelV1MsgChannelCloseConfirm - extends IRangeMessage { - type: CosmosHub4TrxMsgTypes.IbcCoreChannelV1MsgChannelCloseConfirm; - data: { - portId: string; - signer: string; - channelId: string; - proofInit: string; - proofHeight: { - revisionHeight: string; - revisionNumber: string; - }; - }; -} - -// types for msg type:: /ibc.core.channel.v1.MsgChannelOpenConfirm -export interface CosmosHub4TrxMsgIbcCoreChannelV1MsgChannelOpenConfirm - extends IRangeMessage { - type: CosmosHub4TrxMsgTypes.IbcCoreChannelV1MsgChannelOpenConfirm; - data: { - portId: string; - channelId: string; - proofAck: string; - proofHeight: { - revisionHeight: string; - revisionNumber?: string; - }; - signer: string; - }; -} - -// types for mgs type:: /ibc.core.channel.v1.MsgChannelOpenTry -export interface CosmosHub4TrxMsgIbcCoreChannelV1MsgChannelOpenTry - extends IRangeMessage { - type: CosmosHub4TrxMsgTypes.IbcCoreChannelV1MsgChannelOpenTry; - data: { - portId: string; - signer: string; - channel: { - state: string; - version: string; - ordering: string; - counterparty: { - portId: string; - channelId: string; - }; - connectionHops: string[]; - }; - proofInit: string; - proofHeight: { - revisionHeight: string; - revisionNumber?: string; - }; - counterpartyVersion: string; - }; -} - -// types for mgs type:: /ibc.core.channel.v1.MsgRecvPacket -export interface CosmosHub4TrxMsgIbcCoreChannelV1MsgRecvPacket - extends IRangeMessage { - type: CosmosHub4TrxMsgTypes.IbcCoreChannelV1MsgRecvPacket; - data: { - packet: { - sequence: string; - sourcePort: string; - sourceChannel: string; - destinationPort: string; - destinationChannel: string; - data: string; - timeoutHeight?: { - revisionNumber?: string; - revisionHeight?: string; - }; - timeoutTimestamp?: string; - }; - proofCommitment: string; - proofHeight: { - revisionNumber?: string; - revisionHeight?: string; - }; - signer: string; - }; -} - -// types for mgs type:: /ibc.core.channel.v1.MsgTimeout -export interface CosmosHub4TrxMsgIbcCoreChannelV1MsgTimeout - extends IRangeMessage { - type: CosmosHub4TrxMsgTypes.IbcCoreChannelV1MsgTimeout; - data: { - packet: { - sequence: string; - sourcePort: string; - sourceChannel: string; - destinationPort: string; - destinationChannel: string; - data: string; - timeoutHeight?: { - revisionNumber?: string; - revisionHeight?: string; - }; - timeoutTimestamp?: string; - }; - proofUnreceived: string; - proofHeight: { - revisionNumber?: string; - revisionHeight?: string; - }; - nextSequenceRecv: string; - signer: string; - }; -} - -// types for mgs type:: /ibc.core.client.v1.MsgCreateClient -export interface CosmosHub4TrxMsgIbcCoreClientV1MsgCreateClient - extends IRangeMessage { - type: CosmosHub4TrxMsgTypes.IbcCoreClientV1MsgCreateClient; - data: { - clientState: { - '@type': string; - chainId: string; - trustLevel: { - numerator: string; - denominator: string; - }; - trustingPeriod: string; - unbondingPeriod: string; - maxClockDrift: string; - frozenHeight: { - revisionNumber?: string; - revisionHeight?: string; - }; - latestHeight: { - revisionNumber?: string; - revisionHeight?: string; - }; - proofSpecs: { - leafSpec: { - hash: string; - prehashValue: string; - length: string; - prefix: string; - }; - innerSpec: { - childOrder: number[]; - childSize: number; - minPrefixLength: number; - maxPrefixLength: number; - hash: string; - }; - }[]; - upgradePath: string[]; - allowUpdateAfterExpiry: boolean; - allowUpdateAfterMisbehaviour: boolean; - }; - consensusState: { - '@type': string; - timestamp: string; - root: { - hash: string; - }; - nextValidatorsHash: string; - }; - signer: string; - }; -} - -// types for mgs type:: /ibc.core.client.v1.MsgSubmitMisbehaviour -export interface CosmosHub4TrxMsgIbcCoreClientV1MsgSubmitMisbehaviour - extends IRangeMessage { - type: CosmosHub4TrxMsgTypes.IbcCoreClientV1MsgSubmitMisbehaviour; - data: { - clientId: string; - misbehaviour: { - '@type': string; - clientId: string; - header1: { - signedHeader: { - header: { - version: { - block: string; - }; - chainId: string; - height: string; - time: string; - lastBlockId: { - hash: string; - partSetHeader: { - total: number; - hash: string; - }; - }; - lastCommitHash: string; - dataHash: string; - validatorsHash: string; - nextValidatorsHash: string; - consensusHash: string; - appHash: string; - lastResultsHash: string; - evidenceHash: string; - proposerAddress: string; - }; - commit: { - height: string; - blockId: { - hash: string; - partSetHeader: { - total: number; - hash: string; - }; - }; - signatures: { - blockIdFlag: string; - validatorAddress?: string; - timestamp: string; - signature?: string; - }[]; - }; - }; - validatorSet: { - validators: { - address: string; - pubKey: { - ed25519: string; - }; - votingPower: string; - }[]; - proposer: { - address: string; - pubKey: { - ed25519: string; - }; - votingPower: string; - }; - totalVotingPower: string; - }; - trustedHeight: { - revisionHeight: string; - }; - trustedValidators: { - validators: { - address: string; - pubKey: { - ed25519: string; - }; - votingPower: string; - }[]; - proposer: { - address: string; - pubKey: { - ed25519: string; - }; - votingPower: string; - }; - totalVotingPower: string; - }; - }; - header2: { - signedHeader: { - validators: { - address: string; - pubKey: { - ed25519: string; - }; - votingPower: string; - }[]; - proposer: { - address: string; - pubKey: { - ed25519: string; - }; - votingPower: string; - }; - totalVotingPower: string; - }; - validatorSet: { - validators: { - address: string; - pubKey: { - ed25519: string; - }; - votingPower: string; - }[]; - proposer: { - address: string; - pubKey: { - ed25519: string; - }; - votingPower: string; - }; - totalVotingPower: string; - }; - trustedHeight: { - revisionHeight: string; - }; - trustedValidators: { - validators: { - address: string; - pubKey: { - ed25519: string; - }; - votingPower: string; - }[]; - proposer: { - address: string; - pubKey: { - ed25519: string; - }; - votingPower: string; - }; - totalVotingPower: string; - }; - }; - }; - signer: string; - }; -} - -// types for mgs type:: /ibc.core.client.v1.MsgUpdateClient -export interface CosmosHub4TrxMsgIbcCoreClientV1MsgUpdateClient - extends IRangeMessage { - type: CosmosHub4TrxMsgTypes.IbcCoreClientV1MsgUpdateClient; - data: { - clientId: string; - clientMessage: { - '@type': string; - signedHeader: { - header: { - version: { - block: string; - app?: string; - }; - chainId: string; - height: string; - time: string; - lastBlockId: { - hash: string; - partSetHeader: { - total: number; - hash: string; - }; - }; - lastCommitHash: string; - dataHash: string; - validatorsHash: string; - nextValidatorsHash: string; - consensusHash: string; - appHash: string; - lastResultsHash: string; - evidenceHash: string; - proposerAddress: string; - }; - commit: { - height: string; - round?: string; - blockId: { - hash: string; - partSetHeader: { - total: number; - hash: string; - }; - }; - signatures: { - blockIdFlag: string; - timestamp: string; - validatorAddress?: string; - signature?: string; - }[]; - }; - }; - validatorSet: { - validators: { - address: string; - pubKey: { - ed25519: string; - }; - votingPower: string; - proposerPriority?: string; - }[]; - proposer: { - address: string; - pubKey: { - ed25519: string; - }; - votingPower: string; - proposerPriority?: string; - }; - totalVotingPower?: string; - }; - trustedHeight: { - revisionNumber?: string; - revisionHeight: string; - }; - trustedValidators: { - validators: { - address: string; - pubKey: { - ed25519: string; - }; - votingPower: string; - proposerPriority?: string; - }[]; - proposer: { - address: string; - pubKey: { - ed25519: string; - }; - votingPower: string; - proposerPriority?: string; - }; - totalVotingPower?: string; - }; - }; - signer: string; - }; -} diff --git a/src/types/chain/dydx-mainnet-1/IRangeBlockDydxMainnet1Trx.ts b/src/types/chain/dydx-mainnet-1/IRangeBlockDydxMainnet1Trx.ts deleted file mode 100644 index 57826914..00000000 --- a/src/types/chain/dydx-mainnet-1/IRangeBlockDydxMainnet1Trx.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { IRangeTransaction } from '../IRangeTransaction'; -import { DydxMainnet1TrxMsg } from './IRangeBlockDydxMainnet1TrxMsg'; - -export interface DydxMainnet1Trx extends IRangeTransaction { - messages: DydxMainnet1TrxMsg[]; -} diff --git a/src/types/chain/dydx-mainnet-1/IRangeBlockDydxMainnet1TrxMsg.ts b/src/types/chain/dydx-mainnet-1/IRangeBlockDydxMainnet1TrxMsg.ts deleted file mode 100644 index 306db601..00000000 --- a/src/types/chain/dydx-mainnet-1/IRangeBlockDydxMainnet1TrxMsg.ts +++ /dev/null @@ -1,993 +0,0 @@ -import { IRangeMessage } from '../IRangeMessage'; - -export type DydxMainnet1TrxMsg = - | DydxMainnet1TrxMsgCosmosBankV1beta1MsgMultiSend - | DydxMainnet1TrxMsgCosmosBankV1beta1MsgSend - | DydxMainnet1TrxMsgCosmosDistributionV1beta1MsgWithdrawDelegatorReward - | DydxMainnet1TrxMsgCosmosDistributionV1beta1MsgWithdrawValidatorCommission - | DydxMainnet1TrxMsgCosmosGovV1beta1MsgVote - | DydxMainnet1TrxMsgCosmosGovV1MsgSubmitProposal - | DydxMainnet1TrxMsgCosmosGovV1MsgVote - | DydxMainnet1TrxMsgCosmosSlashingV1beta1MsgUnjail - | DydxMainnet1TrxMsgCosmosStakingV1beta1MsgBeginRedelegate - | DydxMainnet1TrxMsgCosmosStakingV1beta1MsgCancelUnbondingDelegation - | DydxMainnet1TrxMsgCosmosStakingV1beta1MsgCreateValidator - | DydxMainnet1TrxMsgCosmosStakingV1beta1MsgDelegate - | DydxMainnet1TrxMsgCosmosStakingV1beta1MsgEditValidator - | DydxMainnet1TrxMsgCosmosStakingV1beta1MsgUndelegate - | DydxMainnet1TrxMsgDydxprotocolBridgeMsgAcknowledgeBridges - | DydxMainnet1TrxMsgDydxprotocolClobMsgCancelOrder - | DydxMainnet1TrxMsgDydxprotocolClobMsgPlaceOrder - | DydxMainnet1TrxMsgDydxprotocolClobMsgProposedOperations - | DydxMainnet1TrxMsgDydxprotocolPerpetualsMsgAddPremiumVotes - | DydxMainnet1TrxMsgDydxprotocolPricesMsgUpdateMarketPrices - | DydxMainnet1TrxMsgDydxprotocolSendingMsgCreateTransfer - | DydxMainnet1TrxMsgDydxprotocolSendingMsgDepositToSubaccount - | DydxMainnet1TrxMsgDydxprotocolSendingMsgWithdrawFromSubaccount - | DydxMainnet1TrxMsgIbcApplicationsTransferV1MsgTransfer - | DydxMainnet1TrxMsgIbcCoreChannelV1MsgAcknowledgement - | DydxMainnet1TrxMsgIbcCoreChannelV1MsgChannelOpenAck - | DydxMainnet1TrxMsgIbcCoreChannelV1MsgChannelOpenConfirm - | DydxMainnet1TrxMsgIbcCoreChannelV1MsgChannelOpenInit - | DydxMainnet1TrxMsgIbcCoreChannelV1MsgChannelOpenTry - | DydxMainnet1TrxMsgIbcCoreChannelV1MsgRecvPacket - | DydxMainnet1TrxMsgIbcCoreChannelV1MsgTimeout - | DydxMainnet1TrxMsgIbcCoreClientV1MsgCreateClient - | DydxMainnet1TrxMsgIbcCoreClientV1MsgUpdateClient - | DydxMainnet1TrxMsgIbcCoreConnectionV1MsgConnectionOpenAck - | DydxMainnet1TrxMsgIbcCoreConnectionV1MsgConnectionOpenConfirm - | DydxMainnet1TrxMsgIbcCoreConnectionV1MsgConnectionOpenInit - | DydxMainnet1TrxMsgIbcCoreConnectionV1MsgConnectionOpenTry; - -enum DydxMainnet1TrxMsgTypes { - CosmosBankV1beta1MsgMultiSend = 'cosmos.bank.v1beta1.MsgMultiSend', - CosmosBankV1beta1MsgSend = 'cosmos.bank.v1beta1.MsgSend', - CosmosDistributionV1beta1MsgWithdrawDelegatorReward = 'cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward', - CosmosDistributionV1beta1MsgWithdrawValidatorCommission = 'cosmos.distribution.v1beta1.MsgWithdrawValidatorCommission', - CosmosGovV1beta1MsgVote = 'cosmos.gov.v1beta1.MsgVote', - CosmosGovV1MsgSubmitProposal = 'cosmos.gov.v1.MsgSubmitProposal', - CosmosGovV1MsgVote = 'cosmos.gov.v1.MsgVote', - CosmosSlashingV1beta1MsgUnjail = 'cosmos.slashing.v1beta1.MsgUnjail', - CosmosStakingV1beta1MsgBeginRedelegate = 'cosmos.staking.v1beta1.MsgBeginRedelegate', - CosmosStakingV1beta1MsgCancelUnbondingDelegation = 'cosmos.staking.v1beta1.MsgCancelUnbondingDelegation', - CosmosStakingV1beta1MsgCreateValidator = 'cosmos.staking.v1beta1.MsgCreateValidator', - CosmosStakingV1beta1MsgDelegate = 'cosmos.staking.v1beta1.MsgDelegate', - CosmosStakingV1beta1MsgEditValidator = 'cosmos.staking.v1beta1.MsgEditValidator', - CosmosStakingV1beta1MsgUndelegate = 'cosmos.staking.v1beta1.MsgUndelegate', - DydxprotocolBridgeMsgAcknowledgeBridges = 'dydxprotocol.bridge.MsgAcknowledgeBridges', - DydxprotocolClobMsgCancelOrder = 'dydxprotocol.clob.MsgCancelOrder', - DydxprotocolClobMsgPlaceOrder = 'dydxprotocol.clob.MsgPlaceOrder', - DydxprotocolClobMsgProposedOperations = 'dydxprotocol.clob.MsgProposedOperations', - DydxprotocolPerpetualsMsgAddPremiumVotes = 'dydxprotocol.perpetuals.MsgAddPremiumVotes', - DydxprotocolPricesMsgUpdateMarketPrices = 'dydxprotocol.prices.MsgUpdateMarketPrices', - DydxprotocolSendingMsgCreateTransfer = 'dydxprotocol.sending.MsgCreateTransfer', - DydxprotocolSendingMsgDepositToSubaccount = 'dydxprotocol.sending.MsgDepositToSubaccount', - DydxprotocolSendingMsgWithdrawFromSubaccount = 'dydxprotocol.sending.MsgWithdrawFromSubaccount', - IbcApplicationsTransferV1MsgTransfer = 'ibc.applications.transfer.v1.MsgTransfer', - IbcCoreChannelV1MsgAcknowledgement = 'ibc.core.channel.v1.MsgAcknowledgement', - IbcCoreChannelV1MsgChannelOpenAck = 'ibc.core.channel.v1.MsgChannelOpenAck', - IbcCoreChannelV1MsgChannelOpenConfirm = 'ibc.core.channel.v1.MsgChannelOpenConfirm', - IbcCoreChannelV1MsgChannelOpenInit = 'ibc.core.channel.v1.MsgChannelOpenInit', - IbcCoreChannelV1MsgChannelOpenTry = 'ibc.core.channel.v1.MsgChannelOpenTry', - IbcCoreChannelV1MsgRecvPacket = 'ibc.core.channel.v1.MsgRecvPacket', - IbcCoreChannelV1MsgTimeout = 'ibc.core.channel.v1.MsgTimeout', - IbcCoreClientV1MsgCreateClient = 'ibc.core.client.v1.MsgCreateClient', - IbcCoreClientV1MsgUpdateClient = 'ibc.core.client.v1.MsgUpdateClient', - IbcCoreConnectionV1MsgConnectionOpenAck = 'ibc.core.connection.v1.MsgConnectionOpenAck', - IbcCoreConnectionV1MsgConnectionOpenConfirm = 'ibc.core.connection.v1.MsgConnectionOpenConfirm', - IbcCoreConnectionV1MsgConnectionOpenInit = 'ibc.core.connection.v1.MsgConnectionOpenInit', - IbcCoreConnectionV1MsgConnectionOpenTry = 'ibc.core.connection.v1.MsgConnectionOpenTry', -} - -// types for mgs type:: /cosmos.bank.v1beta1.MsgMultiSend -export interface DydxMainnet1TrxMsgCosmosBankV1beta1MsgMultiSend - extends IRangeMessage { - type: DydxMainnet1TrxMsgTypes.CosmosBankV1beta1MsgMultiSend; - data: { - inputs: { - coins: { - denom: string; - amount: string; - }[]; - address: string; - }[]; - outputs: { - coins: { - denom: string; - amount: string; - }[]; - address: string; - }[]; - }; -} - -// types for mgs type:: /cosmos.bank.v1beta1.MsgSend -export interface DydxMainnet1TrxMsgCosmosBankV1beta1MsgSend - extends IRangeMessage { - type: DydxMainnet1TrxMsgTypes.CosmosBankV1beta1MsgSend; - data: { - amount: { - denom: string; - amount: string; - }[]; - toAddress: string; - fromAddress: string; - }; -} - -// types for mgs type:: /cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward -export interface DydxMainnet1TrxMsgCosmosDistributionV1beta1MsgWithdrawDelegatorReward - extends IRangeMessage { - type: DydxMainnet1TrxMsgTypes.CosmosDistributionV1beta1MsgWithdrawDelegatorReward; - data: { - delegatorAddress: string; - validatorAddress: string; - }; -} - -// types for mgs type:: /cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward -export interface DydxMainnet1TrxMsgCosmosDistributionV1beta1MsgWithdrawValidatorCommission - extends IRangeMessage { - type: DydxMainnet1TrxMsgTypes.CosmosDistributionV1beta1MsgWithdrawValidatorCommission; - data: { - validatorAddress: string; - }; -} - -// types for mgs type:: /cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward -export interface DydxMainnet1TrxMsgCosmosGovV1beta1MsgVote - extends IRangeMessage { - type: DydxMainnet1TrxMsgTypes.CosmosGovV1beta1MsgVote; - data: { - voter: string; - option: string; - proposalId: string; - }; -} - -// types for mgs type:: /cosmos.gov.v1.MsgSubmitProposal -export interface DydxMainnet1TrxMsgCosmosGovV1MsgSubmitProposal - extends IRangeMessage { - type: DydxMainnet1TrxMsgTypes.CosmosGovV1MsgSubmitProposal; - data: { - title: string; - summary: string; - messages: { - '@type': string; - params?: { - id: number; - pair?: string; - exponent?: number; - minExchanges?: number; - minPriceChangePpm?: number; - exchangeConfigJson?: string; - ticker?: string; - marketId?: number; - liquidityTier?: number; - atomicResolution?: number; - }; - authority: string; - clobPair?: { - id: number; - status: string; - subticksPerTick: number; - stepBaseQuantums: string; - perpetualClobMetadata: { - perpetualId: number; - }; - quantumConversionExponent: number; - }; - msg?: { - '@type': string; - clobPair: { - id: number; - status: string; - subticksPerTick: number; - stepBaseQuantums: string; - perpetualClobMetadata: { - perpetualId: number; - }; - quantumConversionExponent: number; - }; - authority: string; - }; - delayBlocks?: number; - }[]; - proposer: string; - initialDeposit: { - denom: string; - amount: string; - }[]; - }; -} - -// types for mgs type:: /cosmos.gov.v1.MsgVote -export interface DydxMainnet1TrxMsgCosmosGovV1MsgVote extends IRangeMessage { - type: DydxMainnet1TrxMsgTypes.CosmosGovV1MsgVote; - data: { - voter: string; - option: string; - proposalId: string; - }; -} - -// types for mgs type:: /cosmos.slashing.v1beta1.MsgUnjail -export interface DydxMainnet1TrxMsgCosmosSlashingV1beta1MsgUnjail - extends IRangeMessage { - type: DydxMainnet1TrxMsgTypes.CosmosSlashingV1beta1MsgUnjail; - data: { - validatorAddr: string; - }; -} - -// types for mgs type:: /cosmos.staking.v1beta1.MsgBeginRedelegate -export interface DydxMainnet1TrxMsgCosmosStakingV1beta1MsgBeginRedelegate - extends IRangeMessage { - type: DydxMainnet1TrxMsgTypes.CosmosStakingV1beta1MsgBeginRedelegate; - data: { - amount: { - denom: string; - amount: string; - }; - delegatorAddress: string; - validatorDstAddress: string; - validatorSrcAddress: string; - }; -} - -// types for mgs type:: /cosmos.staking.v1beta1.MsgCancelUnbondingDelegation -export interface DydxMainnet1TrxMsgCosmosStakingV1beta1MsgCancelUnbondingDelegation - extends IRangeMessage { - type: DydxMainnet1TrxMsgTypes.CosmosStakingV1beta1MsgCancelUnbondingDelegation; - data: { - amount: { - denom: string; - amount: string; - }; - creationHeight: string; - delegatorAddress: string; - validatorAddress: string; - }; -} - -// types for mgs type:: /cosmos.staking.v1beta1.MsgCreateValidator -export interface DydxMainnet1TrxMsgCosmosStakingV1beta1MsgCreateValidator - extends IRangeMessage { - type: DydxMainnet1TrxMsgTypes.CosmosStakingV1beta1MsgCreateValidator; - data: { - value: { - denom: string; - amount: string; - }; - pubkey: { - key: string; - '@type': string; - }; - commission: { - rate: string; - maxRate: string; - maxChangeRate: string; - }; - description: { - details?: string; - moniker?: string; - website?: string; - identity?: string; - securityContact?: string; - }; - delegatorAddress: string; - validatorAddress: string; - minSelfDelegation: string; - }; -} - -// types for mgs type:: /cosmos.staking.v1beta1.MsgDelegate -export interface DydxMainnet1TrxMsgCosmosStakingV1beta1MsgDelegate - extends IRangeMessage { - type: DydxMainnet1TrxMsgTypes.CosmosStakingV1beta1MsgDelegate; - data: { - amount: { - denom: string; - amount: string; - }; - delegatorAddress: string; - validatorAddress: string; - }; -} - -// types for mgs type:: /cosmos.staking.v1beta1.MsgEditValidator -export interface DydxMainnet1TrxMsgCosmosStakingV1beta1MsgEditValidator - extends IRangeMessage { - type: DydxMainnet1TrxMsgTypes.CosmosStakingV1beta1MsgEditValidator; - data: { - description: { - details: string; - moniker: string; - website: string; - identity: string; - securityContact: string; - }; - commissionRate?: string; - validatorAddress: string; - minSelfDelegation?: string; - }; -} - -// types for mgs type:: /cosmos.staking.v1beta1.MsgUndelegate -export interface DydxMainnet1TrxMsgCosmosStakingV1beta1MsgUndelegate - extends IRangeMessage { - type: DydxMainnet1TrxMsgTypes.CosmosStakingV1beta1MsgUndelegate; - data: { - amount: { - denom: string; - amount: string; - }; - delegatorAddress: string; - validatorAddress: string; - }; -} - -// types for mgs type:: /dydxprotocol.bridge.MsgAcknowledgeBridges -export interface DydxMainnet1TrxMsgDydxprotocolBridgeMsgAcknowledgeBridges - extends IRangeMessage { - type: DydxMainnet1TrxMsgTypes.DydxprotocolBridgeMsgAcknowledgeBridges; - data: { - events?: { - id: number; - coin: { - denom: string; - amount: string; - }; - address: string; - ethBlockHeight: string; - }[]; - }; -} - -// types for mgs type:: /dydxprotocol.clob.MsgCancelOrder -export interface DydxMainnet1TrxMsgDydxprotocolClobMsgCancelOrder - extends IRangeMessage { - type: DydxMainnet1TrxMsgTypes.DydxprotocolClobMsgCancelOrder; - data: { - orderId: { - clientId?: number; - clobPairId?: number; - orderFlags: number; - subaccountId: { - owner: string; - }; - }; - goodTilBlockTime: number; - }; -} - -// types for mgs type:: /dydxprotocol.clob.MsgPlaceOrder -export interface DydxMainnet1TrxMsgDydxprotocolClobMsgPlaceOrder - extends IRangeMessage { - type: DydxMainnet1TrxMsgTypes.DydxprotocolClobMsgPlaceOrder; - data: { - order: { - side: string; - orderId: { - clientId?: number; - clobPairId?: number; - orderFlags: number; - subaccountId: { - owner: string; - number?: number; - }; - }; - quantums: string; - subticks: string; - timeInForce?: string; - conditionType?: string; - clientMetadata?: number; - goodTilBlockTime: number; - conditionalOrderTriggerSubticks?: string; - }; - }; -} - -// types for mgs type:: /dydxprotocol.clob.MsgProposedOperations -export interface DydxMainnet1TrxMsgDydxprotocolClobMsgProposedOperations - extends IRangeMessage { - type: DydxMainnet1TrxMsgTypes.DydxprotocolClobMsgProposedOperations; - data: { - operationsQueue?: { - shortTermOrderPlacement?: string; - match?: { - matchOrders: { - fills: { - fillAmount: string; - makerOrderId: { - clientId: number; - clobPairId?: number; - subaccountId: { - owner: string; - number?: number; - }; - orderFlags?: number; - }; - }[]; - takerOrderId: { - clientId: number; - clobPairId?: number; - orderFlags?: number; - subaccountId: { - owner: string; - number?: number; - }; - }; - }; - }; - }[]; - }; -} - -// types for mgs type:: /dydxprotocol.perpetuals.MsgAddPremiumVotes -export interface DydxMainnet1TrxMsgDydxprotocolPerpetualsMsgAddPremiumVotes - extends IRangeMessage { - type: DydxMainnet1TrxMsgTypes.DydxprotocolPerpetualsMsgAddPremiumVotes; - data: { - votes: { - premiumPpm: number; - perpetualId?: number; - }[]; - }; -} - -// types for mgs type:: /dydxprotocol.prices.MsgUpdateMarketPrices -export interface DydxMainnet1TrxMsgDydxprotocolPricesMsgUpdateMarketPrices - extends IRangeMessage { - type: DydxMainnet1TrxMsgTypes.DydxprotocolPricesMsgUpdateMarketPrices; - data: { - marketPriceUpdates?: { - price: string; - marketId: number; - }[]; - }; -} - -// types for mgs type:: /dydxprotocol.sending.MsgCreateTransfer -export interface DydxMainnet1TrxMsgDydxprotocolSendingMsgCreateTransfer - extends IRangeMessage { - type: DydxMainnet1TrxMsgTypes.DydxprotocolSendingMsgCreateTransfer; - data: { - transfer: { - amount: string; - sender: { - owner: string; - number?: number; - }; - recipient: { - owner: string; - number?: number; - }; - }; - }; -} - -// types for mgs type:: /dydxprotocol.sending.MsgDepositToSubaccount -export interface DydxMainnet1TrxMsgDydxprotocolSendingMsgDepositToSubaccount - extends IRangeMessage { - type: DydxMainnet1TrxMsgTypes.DydxprotocolSendingMsgDepositToSubaccount; - data: { - sender: string; - quantums: string; - recipient: { - owner: string; - number?: number; - }; - }; -} - -// types for mgs type:: /dydxprotocol.sending.MsgWithdrawFromSubaccount -export interface DydxMainnet1TrxMsgDydxprotocolSendingMsgWithdrawFromSubaccount - extends IRangeMessage { - type: DydxMainnet1TrxMsgTypes.DydxprotocolSendingMsgWithdrawFromSubaccount; - data: { - sender: { - owner: string; - number?: number; - }; - quantums: string; - recipient: string; - }; -} - -// types for mgs type:: /ibc.applications.transfer.v1.MsgTransfer -export interface DydxMainnet1TrxMsgIbcApplicationsTransferV1MsgTransfer - extends IRangeMessage { - type: DydxMainnet1TrxMsgTypes.IbcApplicationsTransferV1MsgTransfer; - data: { - memo?: string; - token: { - denom: string; - amount: string; - }; - sender: string; - receiver: string; - sourcePort: string; - sourceChannel: string; - timeoutHeight: - | string - | { - revisionHeight?: string; - revisionNumber?: string; - }; - timeoutTimestamp?: string; - }; -} - -// types for mgs type:: /ibc.core.channel.v1.MsgAcknowledgement -export interface DydxMainnet1TrxMsgIbcCoreChannelV1MsgAcknowledgement - extends IRangeMessage { - type: DydxMainnet1TrxMsgTypes.IbcCoreChannelV1MsgAcknowledgement; - data: { - packet: { - data: string; - sequence: string; - sourcePort: string; - sourceChannel: string; - timeoutHeight: { - revisionHeight?: string; - revisionNumber?: string; - }; - destinationPort: string; - timeoutTimestamp?: string; - destinationChannel: string; - }; - signer: string; - proofAcked: string; - proofHeight: { - revisionHeight: string; - revisionNumber: string; - }; - acknowledgement: string; - }; -} - -// types for mgs type:: /ibc.core.channel.v1.MsgChannelOpenAck -export interface DydxMainnet1TrxMsgIbcCoreChannelV1MsgChannelOpenAck - extends IRangeMessage { - type: DydxMainnet1TrxMsgTypes.IbcCoreChannelV1MsgChannelOpenAck; - data: { - portId: string; - signer: string; - proofTry: string; - channelId: string; - proofHeight: { - revisionHeight: string; - revisionNumber: string; - }; - counterpartyVersion: string; - counterpartyChannelId: string; - }; -} - -// types for mgs type:: /ibc.core.channel.v1.MsgChannelOpenConfirm -export interface DydxMainnet1TrxMsgIbcCoreChannelV1MsgChannelOpenConfirm - extends IRangeMessage { - type: DydxMainnet1TrxMsgTypes.IbcCoreChannelV1MsgChannelOpenConfirm; - data: { - portId: string; - signer: string; - proofAck: string; - channelId: string; - proofHeight: { - revisionHeight: string; - revisionNumber: string; - }; - }; -} - -// types for mgs type:: /ibc.core.channel.v1.MsgChannelOpenInit -export interface DydxMainnet1TrxMsgIbcCoreChannelV1MsgChannelOpenInit - extends IRangeMessage { - type: DydxMainnet1TrxMsgTypes.IbcCoreChannelV1MsgChannelOpenInit; - data: { - portId: string; - signer: string; - channel: { - state: string; - version: string; - ordering: string; - counterparty: { - portId: string; - }; - connectionHops: string[]; - }; - }; -} - -// types for mgs type:: /ibc.core.channel.v1.MsgChannelOpenTry -export interface DydxMainnet1TrxMsgIbcCoreChannelV1MsgChannelOpenTry - extends IRangeMessage { - type: DydxMainnet1TrxMsgTypes.IbcCoreChannelV1MsgChannelOpenTry; - data: { - portId: string; - signer: string; - channel: { - state: string; - version: string; - ordering: string; - counterparty: { - portId: string; - channelId: string; - }; - connectionHops: string[]; - }; - proofInit: string; - proofHeight: { - revisionHeight: string; - revisionNumber: string; - }; - counterpartyVersion: string; - }; -} - -// types for mgs type:: /ibc.core.channel.v1.MsgRecvPacket -export interface DydxMainnet1TrxMsgIbcCoreChannelV1MsgRecvPacket - extends IRangeMessage { - type: DydxMainnet1TrxMsgTypes.IbcCoreChannelV1MsgRecvPacket; - data: { - packet: { - data: string; - sequence: string; - sourcePort: string; - sourceChannel: string; - timeoutHeight: { - revisionHeight?: string; - revisionNumber?: string; - }; - destinationPort: string; - timeoutTimestamp: string; - destinationChannel: string; - }; - signer: string; - proofHeight: { - revisionHeight: string; - revisionNumber: string; - }; - proofCommitment: string; - }; -} - -// types for mgs type:: /ibc.core.channel.v1.MsgTimeout -export interface DydxMainnet1TrxMsgIbcCoreChannelV1MsgTimeout - extends IRangeMessage { - type: DydxMainnet1TrxMsgTypes.IbcCoreChannelV1MsgTimeout; - data: { - packet: { - data: string; - sequence: string; - sourcePort: string; - sourceChannel: string; - timeoutHeight: { - revisionHeight?: string; - revisionNumber?: string; - }; - destinationPort: string; - timeoutTimestamp: string; - destinationChannel: string; - }; - signer: string; - proofHeight: { - revisionHeight: string; - revisionNumber: string; - }; - proofUnreceived: string; - nextSequenceRecv: string; - }; -} - -// types for mgs type:: /ibc.core.client.v1.MsgCreateClient -export interface DydxMainnet1TrxMsgIbcCoreClientV1MsgCreateClient - extends IRangeMessage { - type: DydxMainnet1TrxMsgTypes.IbcCoreClientV1MsgCreateClient; - data: { - signer: string; - clientState: { - '@type': string; - chainId: string; - proofSpecs: { - leafSpec: { - hash: string; - length: string; - prefix: string; - prehashValue: string; - }; - innerSpec: { - hash: string; - childSize: number; - childOrder: number[]; - maxPrefixLength: number; - minPrefixLength: number; - }; - }[]; - trustLevel: { - numerator: string; - denominator: string; - }; - upgradePath: string[]; - frozenHeight: Record; - latestHeight: { - revisionHeight: string; - revisionNumber: string; - }; - maxClockDrift: string; - trustingPeriod: string; - unbondingPeriod: string; - allowUpdateAfterExpiry: boolean; - allowUpdateAfterMisbehaviour: boolean; - }; - consensusState: { - root: { - hash: string; - }; - '@type': string; - timestamp: string; - nextValidatorsHash: string; - }; - }; -} - -// types for mgs type:: /ibc.core.client.v1.MsgUpdateClient -export interface DydxMainnet1TrxMsgIbcCoreClientV1MsgUpdateClient - extends IRangeMessage { - type: DydxMainnet1TrxMsgTypes.IbcCoreClientV1MsgUpdateClient; - data: { - signer: string; - clientId: string; - clientMessage: { - '@type': string; - signedHeader: { - commit: { - round?: number; - height: string; - blockId: { - hash: string; - partSetHeader: { - hash: string; - total: number; - }; - }; - signatures: { - signature?: string; - timestamp: string; - blockIdFlag: string; - validatorAddress?: string; - }[]; - }; - header: { - time: string; - height: string; - appHash: string; - chainId: string; - version: { - app?: string; - block: string; - }; - dataHash: string; - lastBlockId: { - hash: string; - partSetHeader: { - hash: string; - total: number; - }; - }; - evidenceHash: string; - consensusHash: string; - lastCommitHash: string; - validatorsHash: string; - lastResultsHash: string; - proposerAddress: string; - nextValidatorsHash: string; - }; - }; - validatorSet: { - proposer: { - pubKey: { - ed25519: string; - }; - address: string; - votingPower: string; - proposerPriority?: string; - }; - validators: { - pubKey: { - ed25519: string; - }; - address: string; - votingPower: string; - proposerPriority?: string; - }[]; - totalVotingPower: string; - }; - trustedHeight: { - revisionHeight: string; - revisionNumber: string; - }; - trustedValidators: { - proposer: { - pubKey: { - ed25519: string; - }; - address: string; - votingPower: string; - proposerPriority?: string; - }; - validators: { - pubKey: { - ed25519: string; - }; - address: string; - votingPower: string; - proposerPriority?: string; - }[]; - totalVotingPower?: string; - }; - }; - }; -} - -// types for mgs type:: /ibc.core.connection.v1.MsgConnectionOpenAck -export interface DydxMainnet1TrxMsgIbcCoreConnectionV1MsgConnectionOpenAck - extends IRangeMessage { - type: DydxMainnet1TrxMsgTypes.IbcCoreConnectionV1MsgConnectionOpenAck; - data: { - signer: string; - version: { - features: string[]; - identifier: string; - }; - proofTry: string; - clientState: { - '@type': string; - chainId: string; - proofSpecs: { - leafSpec: { - hash: string; - length: string; - prefix: string; - prehashValue: string; - }; - innerSpec: { - hash: string; - childSize: number; - childOrder: number[]; - maxPrefixLength: number; - minPrefixLength: number; - }; - }[]; - trustLevel: { - numerator: string; - denominator: string; - }; - upgradePath: string[]; - frozenHeight: Record; - latestHeight: { - revisionHeight: string; - revisionNumber: string; - }; - maxClockDrift: string; - trustingPeriod: string; - unbondingPeriod: string; - allowUpdateAfterExpiry: boolean; - allowUpdateAfterMisbehaviour: boolean; - }; - proofClient: string; - proofHeight: { - revisionHeight: string; - revisionNumber: string; - }; - connectionId: string; - proofConsensus: string; - consensusHeight: { - revisionHeight: string; - revisionNumber: string; - }; - counterpartyConnectionId: string; - }; -} - -// types for mgs type:: /ibc.core.connection.v1.MsgConnectionOpenConfirm -export interface DydxMainnet1TrxMsgIbcCoreConnectionV1MsgConnectionOpenConfirm - extends IRangeMessage { - type: DydxMainnet1TrxMsgTypes.IbcCoreConnectionV1MsgConnectionOpenConfirm; - data: { - signer: string; - proofAck: string; - proofHeight: { - revisionHeight: string; - revisionNumber: string; - }; - connectionId: string; - }; -} - -// types for mgs type:: /ibc.core.connection.v1.MsgConnectionOpenInit -export interface DydxMainnet1TrxMsgIbcCoreConnectionV1MsgConnectionOpenInit - extends IRangeMessage { - type: DydxMainnet1TrxMsgTypes.IbcCoreConnectionV1MsgConnectionOpenInit; - data: { - signer: string; - version: { - features: string[]; - identifier: string; - }; - clientId: string; - counterparty: { - prefix: { - keyPrefix: string; - }; - clientId: string; - }; - }; -} - -// types for mgs type:: /ibc.core.connection.v1.MsgConnectionOpenTry -export interface DydxMainnet1TrxMsgIbcCoreConnectionV1MsgConnectionOpenTry - extends IRangeMessage { - type: DydxMainnet1TrxMsgTypes.IbcCoreConnectionV1MsgConnectionOpenTry; - data: { - signer: string; - clientId: string; - proofInit: string; - clientState: { - '@type': string; - chainId: string; - proofSpecs: { - leafSpec: { - hash: string; - length: string; - prefix: string; - prehashValue: string; - }; - innerSpec: { - hash: string; - childSize: number; - childOrder: number[]; - maxPrefixLength: number; - minPrefixLength: number; - }; - }[]; - trustLevel: { - numerator: string; - denominator: string; - }; - upgradePath: string[]; - frozenHeight: Record; - latestHeight: { - revisionHeight: string; - revisionNumber: string; - }; - maxClockDrift: string; - trustingPeriod: string; - unbondingPeriod: string; - allowUpdateAfterExpiry: boolean; - allowUpdateAfterMisbehaviour: boolean; - }; - proofClient: string; - proofHeight: { - revisionHeight: string; - revisionNumber: string; - }; - counterparty: { - prefix: { - keyPrefix: string; - }; - clientId: string; - connectionId: string; - }; - proofConsensus: string; - consensusHeight: { - revisionHeight: string; - revisionNumber: string; - }; - counterpartyVersions: { - features: string[]; - identifier: string; - }[]; - }; -} diff --git a/src/types/chain/grand-1/IRangeBlockGrand1Trx.ts b/src/types/chain/grand-1/IRangeBlockGrand1Trx.ts deleted file mode 100644 index 0304bb10..00000000 --- a/src/types/chain/grand-1/IRangeBlockGrand1Trx.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { IRangeTransaction } from '../IRangeTransaction'; -import { Grand1TrxMsg } from './IRangeBlockGrand1TrxMsg'; - -export interface Grand1Trx extends IRangeTransaction { - messages: Grand1TrxMsg[]; -} diff --git a/src/types/chain/grand-1/IRangeBlockGrand1TrxMsg.ts b/src/types/chain/grand-1/IRangeBlockGrand1TrxMsg.ts deleted file mode 100644 index 8564cfff..00000000 --- a/src/types/chain/grand-1/IRangeBlockGrand1TrxMsg.ts +++ /dev/null @@ -1,568 +0,0 @@ -import { IRangeMessage } from '../IRangeMessage'; - -export type Grand1TrxMsg = - | Grand1TrxMsgIbcCoreClientV1MsgUpdateClient - | Grand1TrxMsgIbcApplicationsTransferV1MsgTransfer - | Grand1TrxMsgCircleCctpV1MsgReceiveMessage - | Grand1TrxMsgIbcCoreConnectionV1MsgConnectionOpenAck - | Grand1TrxMsgIbcCoreChannelV1MsgChannelOpenInit - | Grand1TrxMsgCircleCctpV1MsgRemoveRemoteTokenMessenger - | Grand1TrxMsgCircleCctpV1MsgSendMessage - | Grand1TrxMsgCircleCctpV1MsgReplaceDepositForBurn - | Grand1TrxMsgCircleCctpV1MsgDepositForBurn - | Grand1TrxMsgIbcCoreConnectionV1MsgConnectionOpenInit - | Grand1TrxMsgIbcCoreChannelV1MsgRecvPacket - | Grand1TrxMsgIbcCoreChannelV1MsgChannelOpenAck - | Grand1TrxMsgCircleCctpV1MsgLinkTokenPair - | Grand1TrxMsgCosmosBankV1beta1MsgSend - | Grand1TrxMsgIbcCoreChannelV1MsgAcknowledgement - | Grand1TrxMsgIbcCoreChannelV1MsgTimeout - | Grand1TrxMsgCosmosAuthzV1beta1MsgExec - | Grand1TrxMsgCircleCctpV1MsgAddRemoteTokenMessenger - | Grand1TrxMsgNobleFiatTokenFactoryMsgBurn - | Grand1TrxMsgNobleFiatTokenFactoryMsgMint - | Grand1TrxMsgIbcCoreClientV1MsgCreateClient; - -export enum Grand1TrxMsgTypes { - IbcCoreClientV1MsgUpdateClient = 'ibc.core.client.v1.MsgUpdateClient', - IbcApplicationsTransferV1MsgTransfer = 'ibc.applications.transfer.v1.MsgTransfer', - CircleCctpV1MsgReceiveMessage = 'circle.cctp.v1.MsgReceiveMessage', - IbcCoreConnectionV1MsgConnectionOpenAck = 'ibc.core.connection.v1.MsgConnectionOpenAck', - IbcCoreChannelV1MsgChannelOpenInit = 'ibc.core.channel.v1.MsgChannelOpenInit', - CircleCctpV1MsgRemoveRemoteTokenMessenger = 'circle.cctp.v1.MsgRemoveRemoteTokenMessenger', - CircleCctpV1MsgSendMessage = 'circle.cctp.v1.MsgSendMessage', - CircleCctpV1MsgReplaceDepositForBurn = 'circle.cctp.v1.MsgReplaceDepositForBurn', - CircleCctpV1MsgDepositForBurn = 'circle.cctp.v1.MsgDepositForBurn', - IbcCoreConnectionV1MsgConnectionOpenInit = 'ibc.core.connection.v1.MsgConnectionOpenInit', - IbcCoreChannelV1MsgRecvPacket = 'ibc.core.channel.v1.MsgRecvPacket', - IbcCoreChannelV1MsgChannelOpenAck = 'ibc.core.channel.v1.MsgChannelOpenAck', - CircleCctpV1MsgLinkTokenPair = 'circle.cctp.v1.MsgLinkTokenPair', - CosmosBankV1beta1MsgSend = 'cosmos.bank.v1beta1.MsgSend', - IbcCoreChannelV1MsgAcknowledgement = 'ibc.core.channel.v1.MsgAcknowledgement', - IbcCoreChannelV1MsgTimeout = 'ibc.core.channel.v1.MsgTimeout', - CosmosAuthzV1beta1MsgExec = 'cosmos.authz.v1beta1.MsgExec', - CircleCctpV1MsgAddRemoteTokenMessenger = 'circle.cctp.v1.MsgAddRemoteTokenMessenger', - NobleFiatTokenFactoryMsgBurn = 'noble.fiattokenfactory.MsgBurn', - NobleFiatTokenFactoryMsgMint = 'noble.fiattokenfactory.MsgMint', - IbcCoreClientV1MsgCreateClient = 'ibc.core.client.v1.MsgCreateClient', -} - -// types for mgs type:: /ibc.core.client.v1.MsgUpdateClient -export interface Grand1TrxMsgIbcCoreClientV1MsgUpdateClient - extends IRangeMessage { - type: Grand1TrxMsgTypes.IbcCoreClientV1MsgUpdateClient; - data: { - '@type': string; - signer: string; - client_id: string; - client_message: { - '@type': string; - signed_header: { - commit: { - round: number; - height: string; - block_id: { - hash: string; - part_set_header: { - hash: string; - total: number; - }; - }; - signatures: { - signature: string; - timestamp: string; - block_id_flag: string; - validator_address: string; - }[]; - }; - header: { - time: string; - height: string; - version: { - app: string; - block: string; - }; - app_hash: string; - chain_id: string; - data_hash: string; - evidence_hash: string; - last_block_id: { - hash: string; - part_set_header: { - hash: string; - total: number; - }; - }; - consensus_hash: string; - validators_hash: string; - last_commit_hash: string; - proposer_address: string; - last_results_hash: string; - next_validators_hash: string; - }; - }; - validator_set: { - proposer: { - address: string; - pub_key: { - ed25519: string; - }; - voting_power: string; - proposer_priority: string; - }; - validators: { - address: string; - pub_key: { - ed25519: string; - }; - voting_power: string; - proposer_priority: string; - }[]; - total_voting_power: string; - }; - trusted_height: { - revision_height: string; - revision_number: string; - }; - trusted_validators: { - proposer: { - address: string; - pub_key: { - ed25519: string; - }; - voting_power: string; - proposer_priority: string; - }; - validators: { - address: string; - pub_key: { - ed25519: string; - }; - voting_power: string; - proposer_priority: string; - }[]; - total_voting_power: string; - }; - }; - }; -} - -// types for mgs type:: /ibc.applications.transfer.v1.MsgTransfer -export interface Grand1TrxMsgIbcApplicationsTransferV1MsgTransfer - extends IRangeMessage { - type: Grand1TrxMsgTypes.IbcApplicationsTransferV1MsgTransfer; - data: { - token: { - denom: string; - amount: string; - }; - sender: string; - receiver: string; - sourcePort: string; - sourceChannel: string; - timeoutHeight: { - revisionHeight: string; - revisionNumber: string; - }; - timeoutTimestamp: string; - }; -} - -// types for mgs type:: /circle.cctp.v1.MsgReceiveMessage -export interface Grand1TrxMsgCircleCctpV1MsgReceiveMessage - extends IRangeMessage { - type: Grand1TrxMsgTypes.CircleCctpV1MsgReceiveMessage; - data: { - from: string; - message: string; - attestation: string; - }; -} - -// types for mgs type:: /ibc.core.connection.v1.MsgConnectionOpenAck -export interface Grand1TrxMsgIbcCoreConnectionV1MsgConnectionOpenAck - extends IRangeMessage { - type: Grand1TrxMsgTypes.IbcCoreConnectionV1MsgConnectionOpenAck; - data: { - '@type': string; - signer: string; - version: { - features: string[]; - identifier: string; - }; - proof_try: string; - client_state: { - '@type': string; - chain_id: string; - proof_specs: { - leaf_spec: { - hash: string; - length: string; - prefix: string; - prehash_key: string; - prehash_value: string; - }; - max_depth: number; - min_depth: number; - inner_spec: { - hash: string; - child_size: number; - child_order: number[]; - empty_child?: unknown; - max_prefix_length: number; - min_prefix_length: number; - }; - prehash_key_before_comparison: boolean; - }[]; - trust_level: { - numerator: string; - denominator: string; - }; - upgrade_path: string[]; - frozen_height: { - revision_height: string; - revision_number: string; - }; - latest_height: { - revision_height: string; - revision_number: string; - }; - max_clock_drift: string; - trusting_period: string; - unbonding_period: string; - allow_update_after_expiry: boolean; - allow_update_after_misbehaviour: boolean; - }; - proof_client: string; - proof_height: { - revision_height: string; - revision_number: string; - }; - connection_id: string; - proof_consensus: string; - consensus_height: { - revision_height: string; - revision_number: string; - }; - counterparty_connection_id: string; - host_consensus_state_proof?: unknown; - }; -} - -// types for mgs type:: /ibc.core.channel.v1.MsgChannelOpenInit -export interface Grand1TrxMsgIbcCoreChannelV1MsgChannelOpenInit - extends IRangeMessage { - type: Grand1TrxMsgTypes.IbcCoreChannelV1MsgChannelOpenInit; - data: { - portId: string; - signer: string; - channel: { - state: string; - version: string; - ordering: string; - counterparty: { - portId: string; - }; - connectionHops: string[]; - }; - }; -} - -// types for mgs type:: /circle.cctp.v1.MsgRemoveRemoteTokenMessenger -export interface Grand1TrxMsgCircleCctpV1MsgRemoveRemoteTokenMessenger - extends IRangeMessage { - type: Grand1TrxMsgTypes.CircleCctpV1MsgRemoveRemoteTokenMessenger; - data: { - from: string; - domainId: number; - }; -} - -// types for mgs type:: /circle.cctp.v1.MsgSendMessage -export interface Grand1TrxMsgCircleCctpV1MsgSendMessage extends IRangeMessage { - type: Grand1TrxMsgTypes.CircleCctpV1MsgSendMessage; - data: { - from: string; - recipient: string; - messageBody: string; - }; -} - -// types for mgs type:: /circle.cctp.v1.MsgReplaceDepositForBurn -export interface Grand1TrxMsgCircleCctpV1MsgReplaceDepositForBurn - extends IRangeMessage { - type: Grand1TrxMsgTypes.CircleCctpV1MsgReplaceDepositForBurn; - data: { - from: string; - originalMessage: string; - newMintRecipient: string; - originalAttestation: string; - newDestinationCaller: string; - }; -} - -// types for mgs type:: /circle.cctp.v1.MsgDepositForBurn -export interface Grand1TrxMsgCircleCctpV1MsgDepositForBurn - extends IRangeMessage { - type: Grand1TrxMsgTypes.CircleCctpV1MsgDepositForBurn; - data: { - from: string; - amount: string; - burnToken: string; - mintRecipient: string; - }; -} - -// types for mgs type:: /ibc.core.connection.v1.MsgConnectionOpenInit -export interface Grand1TrxMsgIbcCoreConnectionV1MsgConnectionOpenInit - extends IRangeMessage { - type: Grand1TrxMsgTypes.IbcCoreConnectionV1MsgConnectionOpenInit; - data: { - signer: string; - clientId: string; - counterparty: { - prefix: { - keyPrefix: string; - }; - clientId: string; - }; - }; -} - -// types for mgs type:: /ibc.core.channel.v1.MsgRecvPacket -export interface Grand1TrxMsgIbcCoreChannelV1MsgRecvPacket - extends IRangeMessage { - type: Grand1TrxMsgTypes.IbcCoreChannelV1MsgRecvPacket; - data: { - packet: { - data: string; - sequence: string; - sourcePort: string; - sourceChannel: string; - timeoutHeight: Record; // todo: couldn't find value in db - destinationPort: string; - timeoutTimestamp: string; - destinationChannel: string; - }; - signer: string; - proofHeight: { - revisionHeight: string; - revisionNumber: string; - }; - proofCommitment: string; - }; -} - -// types for mgs type:: /ibc.core.channel.v1.MsgChannelOpenAck -export interface Grand1TrxMsgIbcCoreChannelV1MsgChannelOpenAck - extends IRangeMessage { - type: Grand1TrxMsgTypes.IbcCoreChannelV1MsgChannelOpenAck; - data: { - portId: string; - signer: string; - proofTry: string; - channelId: string; - proofHeight: { - revisionHeight: string; - revisionNumber: string; - }; - counterpartyVersion: string; - counterpartyChannelId: string; - }; -} - -// types for mgs type:: /circle.cctp.v1.MsgLinkTokenPair -export interface Grand1TrxMsgCircleCctpV1MsgLinkTokenPair - extends IRangeMessage { - type: Grand1TrxMsgTypes.CircleCctpV1MsgLinkTokenPair; - data: { - from: string; - localToken: string; - remoteToken: string; - remoteDomain: number; - }; -} - -// types for mgs type:: /cosmos.bank.v1beta1.MsgSend -export interface Grand1TrxMsgCosmosBankV1beta1MsgSend extends IRangeMessage { - type: Grand1TrxMsgTypes.CosmosBankV1beta1MsgSend; - data: { - amount: { - denom: string; - amount: string; - }[]; - toAddress: string; - fromAddress: string; - }; -} - -// types for mgs type:: /ibc.core.channel.v1.MsgAcknowledgement -export interface Grand1TrxMsgIbcCoreChannelV1MsgAcknowledgement - extends IRangeMessage { - type: Grand1TrxMsgTypes.IbcCoreChannelV1MsgAcknowledgement; - data: { - packet: { - data: string; - sequence: string; - sourcePort: string; - sourceChannel: string; - timeoutHeight: { - revisionHeight: string; - revisionNumber: string; - }; - destinationPort: string; - timeoutTimestamp: string; - destinationChannel: string; - }; - signer: string; - proofAcked: string; - proofHeight: { - revisionHeight: string; - revisionNumber: string; - }; - acknowledgement: string; - }; -} - -// types for mgs type:: /ibc.core.channel.v1.MsgTimeout -export interface Grand1TrxMsgIbcCoreChannelV1MsgTimeout extends IRangeMessage { - type: Grand1TrxMsgTypes.IbcCoreChannelV1MsgTimeout; - data: { - packet: { - data: string; - sequence: string; - sourcePort: string; - sourceChannel: string; - timeoutHeight: { - revisionHeight: string; - revisionNumber: string; - }; - destinationPort: string; - timeoutTimestamp: string; - destinationChannel: string; - }; - signer: string; - proofHeight: { - revisionHeight: string; - revisionNumber: string; - }; - proofUnreceived: string; - nextSequenceRecv: string; - }; -} - -// types for mgs type:: /cosmos.authz.v1beta1.MsgExec -export interface Grand1TrxMsgCosmosAuthzV1beta1MsgExec extends IRangeMessage { - type: Grand1TrxMsgTypes.CosmosAuthzV1beta1MsgExec; - data: { - msgs: { - '@type': string; - amount: { - denom: string; - amount: string; - }[]; - to_address: string; - from_address: string; - }[]; - '@type': string; - grantee: string; - }; -} - -// types for mgs type:: /circle.cctp.v1.MsgAddRemoteTokenMessenger -export interface Grand1TrxMsgCircleCctpV1MsgAddRemoteTokenMessenger - extends IRangeMessage { - type: Grand1TrxMsgTypes.CircleCctpV1MsgAddRemoteTokenMessenger; - data: { - from: string; - address: string; - domainId: number; - }; -} - -// types for mgs type:: /noble.fiattokenfactory.MsgBurn -export interface Grand1TrxMsgNobleFiatTokenFactoryMsgBurn - extends IRangeMessage { - type: Grand1TrxMsgTypes.NobleFiatTokenFactoryMsgBurn; - data: { - from: string; - amount: { - denom: string; - amount: string; - }; - }; -} - -// types for mgs type:: /noble.fiattokenfactory.MsgMint -export interface Grand1TrxMsgNobleFiatTokenFactoryMsgMint - extends IRangeMessage { - type: Grand1TrxMsgTypes.NobleFiatTokenFactoryMsgMint; - data: { - from: string; - amount: { - denom: string; - amount: string; - }; - address: string; - }; -} - -// types for mgs type:: /ibc.core.client.v1.MsgCreateClient -export interface Grand1TrxMsgIbcCoreClientV1MsgCreateClient - extends IRangeMessage { - type: Grand1TrxMsgTypes.IbcCoreClientV1MsgCreateClient; - data: { - '@type': string; - signer: string; - client_state: { - '@type': string; - chain_id: string; - proof_specs: { - leaf_spec: { - hash: string; - length: string; - prefix: string; - prehash_key: string; - prehash_value: string; - }; - max_depth: number; - min_depth: number; - inner_spec: { - hash: string; - child_size: number; - child_order: number[]; - empty_child?: unknown; - max_prefix_length: number; - min_prefix_length: number; - }; - prehash_key_before_comparison: boolean; - }[]; - trust_level: { - numerator: string; - denominator: string; - }; - upgrade_path: string[]; - frozen_height: { - revision_height: string; - revision_number: string; - }; - latest_height: { - revision_height: string; - revision_number: string; - }; - max_clock_drift: string; - trusting_period: string; - unbonding_period: string; - allow_update_after_expiry: boolean; - allow_update_after_misbehaviour: boolean; - }; - consensus_state: { - root: { - hash: string; - }; - '@type': string; - timestamp: string; - next_validators_hash: string; - }; - }; -} diff --git a/src/types/chain/mocha-4/IRangeBlockMocha4Trx.ts b/src/types/chain/mocha-4/IRangeBlockMocha4Trx.ts deleted file mode 100644 index 6571d67b..00000000 --- a/src/types/chain/mocha-4/IRangeBlockMocha4Trx.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { IRangeTransaction } from '../IRangeTransaction'; -import { Mocha4TrxMsg } from './IRangeBlockMocha4TrxMsg'; - -export interface Mocha4Trx extends IRangeTransaction { - messages: Mocha4TrxMsg[]; -} diff --git a/src/types/chain/mocha-4/IRangeBlockMocha4TrxMsg.ts b/src/types/chain/mocha-4/IRangeBlockMocha4TrxMsg.ts deleted file mode 100644 index 78954aaa..00000000 --- a/src/types/chain/mocha-4/IRangeBlockMocha4TrxMsg.ts +++ /dev/null @@ -1,618 +0,0 @@ -import { IRangeMessage } from '../IRangeMessage'; - -enum Mocha4TrxMsgTypes { - CosmosAuthzV1beta1MsgExec = 'cosmos.authz.v1beta1.MsgExec', - CosmosAuthzV1beta1MsgGrant = 'cosmos.authz.v1beta1.MsgGrant', - CosmosBankV1beta1MsgSend = 'cosmos.bank.v1beta1.MsgSend', - CosmosDistributionV1beta1MsgSetWithdrawAddress = 'cosmos.distribution.v1beta1.MsgSetWithdrawAddress', - CosmosDistributionV1beta1MsgWithdrawDelegatorReward = 'cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward', - CosmosDistributionV1beta1MsgWithdrawValidatorCommission = 'cosmos.distribution.v1beta1.MsgWithdrawValidatorCommission', - CosmosFeeGrantV1beta1MsgGrantAllowance = 'cosmos.feegrant.v1beta1.MsgGrantAllowance', - CosmosSlashingV1beta1MsgUnjail = 'cosmos.slashing.v1beta1.MsgUnjail', - CosmosStakingV1beta1MsgBeginRedelegate = 'cosmos.staking.v1beta1.MsgBeginRedelegate', - CosmosStakingV1beta1MsgCreateValidator = 'cosmos.staking.v1beta1.MsgCreateValidator', - CosmosStakingV1beta1MsgDelegate = 'cosmos.staking.v1beta1.MsgDelegate', - CosmosStakingV1beta1MsgEditValidator = 'cosmos.staking.v1beta1.MsgEditValidator', - CosmosStakingV1beta1MsgUndelegate = 'cosmos.staking.v1beta1.MsgUndelegate', - CosmosVestingV1beta1MsgCreateVestingAccount = 'cosmos.vesting.v1beta1.MsgCreateVestingAccount', - IbcApplicationsTransferV1MsgTransfer = 'ibc.applications.transfer.v1.MsgTransfer', - IbcCoreChannelV1MsgAcknowledgement = 'ibc.core.channel.v1.MsgAcknowledgement', - IbcCoreChannelV1MsgChannelOpenConfirm = 'ibc.core.channel.v1.MsgChannelOpenConfirm', - IbcCoreChannelV1MsgChannelOpenTry = 'ibc.core.channel.v1.MsgChannelOpenTry', - IbcCoreClientV1MsgCreateClient = 'ibc.core.client.v1.MsgCreateClient', - IbcCoreClientV1MsgUpdateClient = 'ibc.core.client.v1.MsgUpdateClient', - IbcCoreConnectionV1MsgConnectionOpenConfirm = 'ibc.core.connection.v1.MsgConnectionOpenConfirm', - IbcCoreConnectionV1MsgConnectionOpenInit = 'ibc.core.connection.v1.MsgConnectionOpenInit', - IbcCoreConnectionV1MsgConnectionOpenTry = 'ibc.core.connection.v1.MsgConnectionOpenTry', -} - -export type Mocha4TrxMsg = - | Mocha4TrxMsgCosmosAuthzV1beta1MsgExec - | Mocha4TrxMsgCosmosAuthzV1beta1MsgGrant - | Mocha4TrxMsgCosmosBankV1beta1MsgSend - | Mocha4TrxMsgCosmosDistributionV1beta1MsgSetWithdrawAddress - | Mocha4TrxMsgCosmosDistributionV1beta1MsgWithdrawDelegatorReward - | Mocha4TrxMsgCosmosDistributionV1beta1MsgWithdrawValidatorCommission - | Mocha4TrxMsgCosmosFeeGrantV1beta1MsgGrantAllowance - | Mocha4TrxMsgCosmosSlashingV1beta1MsgUnjail - | Mocha4TrxMsgCosmosStakingV1beta1MsgBeginRedelegate - | Mocha4TrxMsgCosmosStakingV1beta1MsgCreateValidator - | Mocha4TrxMsgCosmosStakingV1beta1MsgDelegate - | Mocha4TrxMsgCosmosStakingV1beta1MsgEditValidator - | Mocha4TrxMsgCosmosStakingV1beta1MsgUndelegate - | Mocha4TrxMsgCosmosVestingV1beta1MsgCreateVestingAccount - | Mocha4TrxMsgIbcApplicationsTransferV1MsgTransfer - | Mocha4TrxMsgIbcCoreChannelV1MsgAcknowledgement - | Mocha4TrxMsgIbcCoreChannelV1MsgChannelOpenConfirm - | Mocha4TrxMsgIbcCoreChannelV1MsgChannelOpenTry - | Mocha4TrxMsgIbcCoreClientV1MsgCreateClient - | Mocha4TrxMsgIbcCoreClientV1MsgUpdateClient - | Mocha4TrxMsgIbcCoreConnectionV1MsgConnectionOpenConfirm - | Mocha4TrxMsgConnectionOpenInit - | Mocha4TrxMsgConnectionOpenTry; - -// types for msg type:: /cosmos.authz.v1beta1.MsgExec -export interface Mocha4TrxMsgCosmosAuthzV1beta1MsgExec extends IRangeMessage { - type: Mocha4TrxMsgTypes.CosmosAuthzV1beta1MsgExec; - data: { - msgs: { - '@type': string; - delegator_address: string; - validator_address: string; - }[]; - '@type': string; - grantee: string; - }; -} - -// types for msg type:: /cosmos.authz.v1beta1.MsgGrant -export interface Mocha4TrxMsgCosmosAuthzV1beta1MsgGrant extends IRangeMessage { - type: Mocha4TrxMsgTypes.CosmosAuthzV1beta1MsgGrant; - data: { - '@type': string; - grant: { - expiration: string; - authorization: { - msg: string; - '@type': string; - }; - }; - grantee: string; - granter: string; - }; -} - -// types for msg type:: /cosmos.bank.v1beta1.MsgSend -export interface Mocha4TrxMsgCosmosBankV1beta1MsgSend extends IRangeMessage { - type: Mocha4TrxMsgTypes.CosmosBankV1beta1MsgSend; - data: { - amount: Array<{ - denom: string; - amount: string; - }>; - toAddress: string; - fromAddress: string; - }; -} - -// types for msg type:: /cosmos.distribution.v1beta1.MsgSetWithdrawAddress -export interface Mocha4TrxMsgCosmosDistributionV1beta1MsgSetWithdrawAddress - extends IRangeMessage { - type: Mocha4TrxMsgTypes.CosmosDistributionV1beta1MsgSetWithdrawAddress; - data: { - withdrawAddress: string; - delegatorAddress: string; - }; -} - -// types for msg type:: /cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward -export interface Mocha4TrxMsgCosmosDistributionV1beta1MsgWithdrawDelegatorReward - extends IRangeMessage { - type: Mocha4TrxMsgTypes.CosmosDistributionV1beta1MsgWithdrawDelegatorReward; - data: { - delegatorAddress: string; - validatorAddress: string; - }; -} - -// types for msg type:: /cosmos.distribution.v1beta1.MsgWithdrawValidatorCommission -export interface Mocha4TrxMsgCosmosDistributionV1beta1MsgWithdrawValidatorCommission - extends IRangeMessage { - type: Mocha4TrxMsgTypes.CosmosDistributionV1beta1MsgWithdrawValidatorCommission; - data: { - validatorAddress: string; - }; -} - -// types for msg type:: /cosmos.feegrant.v1beta1.MsgGrantAllowance -export interface Mocha4TrxMsgCosmosFeeGrantV1beta1MsgGrantAllowance - extends IRangeMessage { - type: Mocha4TrxMsgTypes.CosmosFeeGrantV1beta1MsgGrantAllowance; - data: { - '@type': string; - grantee: string; - granter: string; - allowance: { - '@type': string; - expiration: string | null; - spend_limit: string[]; - }; - }; -} - -// types for msg type:: /cosmos.slashing.v1beta1.MsgUnjail -export interface Mocha4TrxMsgCosmosSlashingV1beta1MsgUnjail - extends IRangeMessage { - type: Mocha4TrxMsgTypes.CosmosSlashingV1beta1MsgUnjail; - data: { - validatorAddr: string; - }; -} - -// types for msg type:: /cosmos.staking.v1beta1.MsgBeginRedelegate -export interface Mocha4TrxMsgCosmosStakingV1beta1MsgBeginRedelegate - extends IRangeMessage { - type: Mocha4TrxMsgTypes.CosmosStakingV1beta1MsgBeginRedelegate; - data: { - amount: { - denom: string; - amount: string; - }; - delegatorAddress: string; - validatorDstAddress: string; - validatorSrcAddress: string; - }; -} - -// types for msg type:: /cosmos.staking.v1beta1.MsgCreateValidator -export interface Mocha4TrxMsgCosmosStakingV1beta1MsgCreateValidator - extends IRangeMessage { - type: Mocha4TrxMsgTypes.CosmosStakingV1beta1MsgCreateValidator; - data: { - '@type': string; - value: { - denom: string; - amount: string; - }; - pubkey: { - key: string; - '@type': string; - }; - commission: { - rate: string; - max_rate: string; - max_change_rate: string; - }; - description: { - details: string; - moniker: string; - website: string; - identity: string; - security_contact: string; - }; - delegator_address: string; - validator_address: string; - min_self_delegation: string; - }; -} - -// types for msg type:: /cosmos.staking.v1beta1.MsgDelegate -export interface Mocha4TrxMsgCosmosStakingV1beta1MsgDelegate - extends IRangeMessage { - type: Mocha4TrxMsgTypes.CosmosStakingV1beta1MsgDelegate; - data: { - amount: { - denom: string; - amount: string; - }; - delegatorAddress: string; - validatorAddress: string; - }; -} - -// types for msg type:: /cosmos.staking.v1beta1.MsgEditValidator -export interface Mocha4TrxMsgCosmosStakingV1beta1MsgEditValidator - extends IRangeMessage { - type: Mocha4TrxMsgTypes.CosmosStakingV1beta1MsgEditValidator; - data: { - description: { - details: string; - moniker: string; - website: string; - identity: string; - securityContact: string; - }; - validatorAddress: string; - }; -} - -// types for msg type:: /cosmos.staking.v1beta1.MsgUndelegate -export interface Mocha4TrxMsgCosmosStakingV1beta1MsgUndelegate - extends IRangeMessage { - type: Mocha4TrxMsgTypes.CosmosStakingV1beta1MsgUndelegate; - data: { - amount: { - denom: string; - amount: string; - }; - delegatorAddress: string; - validatorAddress: string; - }; -} - -// types for msg type:: /cosmos.vesting.v1beta1.MsgCreateVestingAccount -export interface Mocha4TrxMsgCosmosVestingV1beta1MsgCreateVestingAccount - extends IRangeMessage { - type: Mocha4TrxMsgTypes.CosmosVestingV1beta1MsgCreateVestingAccount; - data: { - amount: { - denom: string; - amount: string; - }[]; - endTime: string; - toAddress: string; - fromAddress: string; - }; -} - -// types for msg type:: /ibc.applications.transfer.v1.MsgTransfer -export interface Mocha4TrxMsgIbcApplicationsTransferV1MsgTransfer - extends IRangeMessage { - type: Mocha4TrxMsgTypes.IbcApplicationsTransferV1MsgTransfer; - data: { - memo: string; - token: { - denom: string; - amount: string; - }; - sender: string; - receiver: string; - sourcePort: string; - sourceChannel: string; - timeoutHeight: { - revisionHeight: string; - }; - }; -} - -// types for msg type:: /ibc.core.channel.v1.MsgAcknowledgement -export interface Mocha4TrxMsgIbcCoreChannelV1MsgAcknowledgement - extends IRangeMessage { - type: Mocha4TrxMsgTypes.IbcCoreChannelV1MsgAcknowledgement; - data: { - packet: { - data: string; - sequence: string; - sourcePort: string; - sourceChannel: string; - timeoutHeight: { - revisionHeight: string; - revisionNumber: string; - }; - destinationPort: string; - destinationChannel: string; - }; - signer: string; - proofAcked: string; - proofHeight: { - revisionHeight: string; - revisionNumber: string; - }; - acknowledgement: string; - }; -} - -// types for msg type:: /ibc.core.channel.v1.MsgChannelOpenConfirm -export interface Mocha4TrxMsgIbcCoreChannelV1MsgChannelOpenConfirm - extends IRangeMessage { - type: Mocha4TrxMsgTypes.IbcCoreChannelV1MsgChannelOpenConfirm; - data: { - portId: string; - signer: string; - proofAck: string; - channelId: string; - proofHeight: { - revisionHeight: string; - revisionNumber: string; - }; - counterpartyVersion: string; - }; -} - -// types for msg type:: /ibc.core.channel.v1.MsgChannelOpenTry -export interface Mocha4TrxMsgIbcCoreChannelV1MsgChannelOpenTry - extends IRangeMessage { - type: Mocha4TrxMsgTypes.IbcCoreChannelV1MsgChannelOpenTry; - data: { - portId: string; - signer: string; - channel: { - state: string; - version: string; - ordering: string; - counterparty: { - portId: string; - channelId: string; - }; - connectionHops: string[]; - }; - proofInit: string; - proofHeight: { - revisionHeight: string; - revisionNumber: string; - }; - counterpartyVersion: string; - }; -} - -// types for msg type:: /ibc.core.client.v1.MsgCreateClient -export interface Mocha4TrxMsgIbcCoreClientV1MsgCreateClient - extends IRangeMessage { - type: Mocha4TrxMsgTypes.IbcCoreClientV1MsgCreateClient; - data: { - '@type': string; - signer: string; - client_state: { - '@type': string; - chain_id: string; - proof_specs: { - leaf_spec: { - hash: string; - length: string; - prefix: string; - prehash_key: string; - prehash_value: string; - }; - max_depth: number; - min_depth: number; - inner_spec: { - hash: string; - child_size: number; - child_order: number[]; - empty_child: null; - max_prefix_length: number; - min_prefix_length: number; - }; - prehash_key_before_comparison: boolean; - }[]; - trust_level: { - numerator: string; - denominator: string; - }; - upgrade_path: string[]; - frozen_height: { - revision_height: string; - revision_number: string; - }; - latest_height: { - revision_height: string; - revision_number: string; - }; - max_clock_drift: string; - trusting_period: string; - unbonding_period: string; - allow_update_after_expiry: boolean; - allow_update_after_misbehaviour: boolean; - }; - consensus_state: { - root: { - hash: string; - }; - '@type': string; - timestamp: string; - next_validators_hash: string; - }; - }; -} - -// types for msg type:: /ibc.core.client.v1.MsgUpdateClient -export interface Mocha4TrxMsgIbcCoreClientV1MsgUpdateClient - extends IRangeMessage { - type: Mocha4TrxMsgTypes.IbcCoreClientV1MsgUpdateClient; - data: { - '@type': string; - signer: string; - client_id: string; - client_message: { - '@type': string; - signed_header: { - commit: { - round: number; - height: string; - block_id: { - hash: string; - part_set_header: { - hash: string; - total: number; - }; - }; - signatures: { - signature: string; - timestamp: string; - block_id_flag: string; - validator_address: string; - }[]; - }; - header: { - time: string; - height: string; - version: { - app: string; - block: string; - }; - app_hash: string; - chain_id: string; - data_hash: string; - evidence_hash: string; - last_block_id: { - hash: string; - part_set_header: { - hash: string; - total: number; - }; - }; - consensus_hash: string; - validators_hash: string; - last_commit_hash: string; - proposer_address: string; - last_results_hash: string; - next_validators_hash: string; - }; - }; - validator_set: { - proposer: { - address: string; - pub_key: { - ed25519: string; - }; - voting_power: string; - proposer_priority: string; - }; - validators: { - address: string; - pub_key: { - ed25519: string; - }; - voting_power: string; - proposer_priority: string; - }[]; - total_voting_power: string; - }; - trusted_height: { - revision_height: string; - revision_number: string; - }; - trusted_validators: { - proposer: { - address: string; - pub_key: { - ed25519: string; - }; - voting_power: string; - proposer_priority: string; - }; - validators: { - address: string; - pub_key: { - ed25519: string; - }; - voting_power: string; - proposer_priority: string; - }[]; - total_voting_power: string; - }; - }; - }; -} - -// types for msg type:: /ibc.core.connection.v1.MsgConnectionOpenConfirm -export interface Mocha4TrxMsgIbcCoreConnectionV1MsgConnectionOpenConfirm - extends IRangeMessage { - type: Mocha4TrxMsgTypes.IbcCoreConnectionV1MsgConnectionOpenConfirm; - data: { - signer: string; - proofAck: string; - proofHeight: { - revisionHeight: string; - revisionNumber: string; - }; - connectionId: string; - }; -} - -// types for msg type:: /ibc.core.connection.v1.MsgConnectionOpenInit -export interface Mocha4TrxMsgConnectionOpenInit extends IRangeMessage { - type: Mocha4TrxMsgTypes.IbcCoreConnectionV1MsgConnectionOpenInit; - data: { - '@type': string; - signer: string; - version: { - features: string[]; - identifier: string; - }; - clientId: string; - counterparty: { - prefix: { - keyPrefix: string; - }; - clientId: string; - }; - }; -} - -// types for msg type:: /ibc.core.connection.v1.MsgConnectionOpenTry -export interface Mocha4TrxMsgConnectionOpenTry extends IRangeMessage { - type: Mocha4TrxMsgTypes.IbcCoreConnectionV1MsgConnectionOpenTry; - data: { - '@type': string; - signer: string; - client_id: string; - proof_init: string; - client_state: { - '@type': string; - chain_id: string; - proof_specs: { - leaf_spec: { - hash: string; - length: string; - prefix: string; - prehash_key: string; - prehash_value: string; - }; - max_depth: number; - min_depth: number; - inner_spec: { - hash: string; - child_size: number; - child_order: number[]; - empty_child: null; - max_prefix_length: number; - min_prefix_length: number; - }; - prehash_key_before_comparison: boolean; - }[]; - trust_level: { - numerator: string; - denominator: string; - }; - upgrade_path: string[]; - frozen_height: { - revision_height: string; - revision_number: string; - }; - latest_height: { - revision_height: string; - revision_number: string; - }; - max_clock_drift: string; - trusting_period: string; - unbonding_period: string; - allow_update_after_expiry: boolean; - allow_update_after_misbehaviour: boolean; - }; - counterparty: { - prefix: { - keyPrefix: string; - }; - client_id: string; - connection_id: string; - }; - delay_period: string; - proof_client: string; - proof_height: { - revision_height: string; - revision_number: string; - }; - proof_consensus: string; - consensus_height: { - revision_height: string; - revision_number: string; - }; - counterparty_versions: { - features: string[]; - identifier: string; - }[]; - previous_connection_id: string; - host_consensus_state_proof: null; - }; -} diff --git a/src/types/chain/neutron-1/IRangeBlockNeutron1Trx.ts b/src/types/chain/neutron-1/IRangeBlockNeutron1Trx.ts deleted file mode 100644 index c02387cc..00000000 --- a/src/types/chain/neutron-1/IRangeBlockNeutron1Trx.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { IRangeTransaction } from '../IRangeTransaction'; -import { Neutron1TrxMsg } from './IRangeBlockNeutron1TrxMsg'; - -export interface Neutron1Trx extends IRangeTransaction { - messages: Neutron1TrxMsg[]; -} diff --git a/src/types/chain/neutron-1/IRangeBlockNeutron1TrxMsg.ts b/src/types/chain/neutron-1/IRangeBlockNeutron1TrxMsg.ts deleted file mode 100644 index 5b946b64..00000000 --- a/src/types/chain/neutron-1/IRangeBlockNeutron1TrxMsg.ts +++ /dev/null @@ -1,407 +0,0 @@ -import { IRangeMessage } from '../IRangeMessage'; - -export enum Neutron1TrxMsgTypes { - CosmosBankV1beta1MsgSend = 'cosmos.bank.v1beta1.MsgSend', - CosmwasmWasmV1MsgExecuteContract = 'cosmwasm.wasm.v1.MsgExecuteContract', - CosmwasmWasmV1MsgInstantiateContract = 'cosmwasm.wasm.v1.MsgInstantiateContract', - CosmwasmWasmV1MsgInstantiateContract2 = 'cosmwasm.wasm.v1.MsgInstantiateContract2', - CosmwasmWasmV1MsgMigrateContract = 'cosmwasm.wasm.v1.MsgMigrateContract', - CosmwasmWasmV1MsgStoreCode = 'cosmwasm.wasm.v1.MsgStoreCode', - IbcApplicationsTransferV1MsgTransfer = 'ibc.applications.transfer.v1.MsgTransfer', - IbcCoreChannelV1MsgAcknowledgement = 'ibc.core.channel.v1.MsgAcknowledgement', - IbcCoreChannelV1MsgRecvPacket = 'ibc.core.channel.v1.MsgRecvPacket', - IbcCoreChannelV1MsgTimeout = 'ibc.core.channel.v1.MsgTimeout', - IbcCoreClientV1MsgCreateClient = 'ibc.core.client.v1.MsgCreateClient', - IbcCoreClientV1MsgUpdateClient = 'ibc.core.client.v1.MsgUpdateClient', - OsmosisTokenFactoryV1beta1MsgCreateDenom = 'osmosis.tokenfactory.v1beta1.MsgCreateDenom', - OsmosisTokenfactoryV1beta1MsgMint = 'osmosis.tokenfactory.v1beta1.MsgMint', - CosmwasmWasmV1MsgUpdateAdmin = 'cosmwasm.wasm.v1.MsgUpdateAdmin', -} - -export type Neutron1TrxMsg = - | Neutron1TrxMsgCosmosBankV1beta1MsgSend - | Neutron1TrxMsgCosmwasmWasmV1MsgExecuteContract - | Neutron1TrxMsgCosmwasmWasmV1MsgInstantiateContract - | Neutron1TrxMsgCosmwasmWasmV1MsgInstantiateContract2 - | Neutron1TrxMsgCosmwasmWasmV1MsgMigrateContract - | Neutron1TrxMsgCosmwasmWasmV1MsgStoreCode - | Neutron1TrxMsgIbcApplicationsTransferV1MsgTransfer - | Neutron1TrxMsgIbcCoreChannelV1MsgAcknowledgement - | Neutron1TrxMsgIbcCoreChannelV1MsgRecvPacket - | Neutron1TrxMsgIbcCoreChannelV1MsgTimeout - | Neutron1TrxMsgIbcCoreClientV1MsgCreateClient - | Neutron1TrxMsgIbcCoreClientV1MsgUpdateClient - | Neutron1TrxMsgOsmosisTokenFactoryV1beta1MsgCreateDenom - | Neutron1TrxMsgOsmosisTokenfactoryV1beta1MsgMint - | Neutron1TrxMsgCosmwasmWasmV1MsgUpdateAdmin; - -// types for msg type:: /cosmos.bank.v1beta1.MsgSend -export interface Neutron1TrxMsgCosmosBankV1beta1MsgSend extends IRangeMessage { - type: Neutron1TrxMsgTypes.CosmosBankV1beta1MsgSend; - data: { - amount: { denom: string; amount: string }[]; - toAddress: string; - fromAddress: string; - }; -} - -// types for msg type:: /cosmwasm.wasm.v1.MsgExecuteContract -export interface Neutron1TrxMsgCosmwasmWasmV1MsgExecuteContract - extends IRangeMessage { - type: Neutron1TrxMsgTypes.CosmwasmWasmV1MsgExecuteContract; - data: { - sender: string; - contract: string; - msg: Record; - funds?: { - denom: string; - amount: string; - }[]; - }; -} - -// types for msg type:: /cosmwasm.wasm.v1.MsgInstantiateContract -export interface Neutron1TrxMsgCosmwasmWasmV1MsgInstantiateContract - extends IRangeMessage { - type: Neutron1TrxMsgTypes.CosmwasmWasmV1MsgInstantiateContract; - data: { - admin?: string; - label: string; - codeId: string; - sender: string; - msg: Record; - }; -} - -// types for msg type:: /cosmwasm.wasm.v1.MsgInstantiateContract2 -export interface Neutron1TrxMsgCosmwasmWasmV1MsgInstantiateContract2 - extends IRangeMessage { - type: Neutron1TrxMsgTypes.CosmwasmWasmV1MsgInstantiateContract2; - data: { - sender: string; - admin?: string; - codeId: string; - label: string; - msg: string; - salt: string; - }; -} - -// types for msg type:: /cosmwasm.wasm.v1.MsgMigrateContract -export interface Neutron1TrxMsgCosmwasmWasmV1MsgMigrateContract - extends IRangeMessage { - type: Neutron1TrxMsgTypes.CosmwasmWasmV1MsgMigrateContract; - data: { - msg: string; - codeId: string; - sender: string; - contract: string; - }; -} - -// types for msg type:: /cosmwasm.wasm.v1.MsgStoreCode -export interface Neutron1TrxMsgCosmwasmWasmV1MsgStoreCode - extends IRangeMessage { - type: Neutron1TrxMsgTypes.CosmwasmWasmV1MsgStoreCode; - data: { - sender: string; - wasmByteCode: string; - instantiatePermission?: { - permission: string; - addresses: string[]; - }; - }; -} - -// types for msg type:: /ibc.applications.transfer.v1.MsgTransfer -export interface Neutron1TrxMsgIbcApplicationsTransferV1MsgTransfer - extends IRangeMessage { - type: Neutron1TrxMsgTypes.IbcApplicationsTransferV1MsgTransfer; - data: { - sourcePort: string; - sourceChannel: string; - token: { - denom: string; - amount: string; - }; - sender: string; - receiver: string; - timeoutHeight?: { - revisionHeight?: string; - revisionNumber?: string; - }; - timeoutTimestamp?: string; - memo?: string; - }; -} - -// types for msg type:: /ibc.core.channel.v1.MsgAcknowledgement -export interface Neutron1TrxMsgIbcCoreChannelV1MsgAcknowledgement - extends IRangeMessage { - type: Neutron1TrxMsgTypes.IbcCoreChannelV1MsgAcknowledgement; - data: { - packet: { - sequence: string; - sourcePort: string; - sourceChannel: string; - destinationPort: string; - destinationChannel: string; - data: string; - timeoutHeight?: { - revisionHeight?: string; - revisionNumber?: string; - }; - timeoutTimestamp?: string; - }; - acknowledgement: string; - proofAcked: string; - proofHeight: { - revisionHeight: string; - revisionNumber?: string; - }; - signer: string; - }; -} - -// types for mgs type:: ibc.core.channel.v1.MsgRecvPacket -export interface Neutron1TrxMsgIbcCoreChannelV1MsgRecvPacket - extends IRangeMessage { - type: Neutron1TrxMsgTypes.IbcCoreChannelV1MsgRecvPacket; - data: { - packet: { - sequence: string; - sourcePort: string; - sourceChannel: string; - destinationPort: string; - destinationChannel: string; - data: string; - timeoutHeight?: { - revisionHeight?: string; - revisionNumber?: string; - }; - timeoutTimestamp?: string; - }; - proofCommitment: string; - proofHeight: { - revisionHeight: string; - revisionNumber?: string; - }; - signer: string; - }; -} - -// types for mgs type:: /ibc.core.channel.v1.MsgTimeout -export interface Neutron1TrxMsgIbcCoreChannelV1MsgTimeout - extends IRangeMessage { - type: Neutron1TrxMsgTypes.IbcCoreChannelV1MsgTimeout; - data: { - packet: { - data: string; - sequence: string; - sourcePort: string; - sourceChannel: string; - destinationPort: string; - destinationChannel: string; - timeoutHeight?: { - revisionHeight?: string; - revisionNumber?: string; - }; - timeoutTimestamp?: string; - }; - signer: string; - proofHeight: { - revisionHeight?: string; - revisionNumber?: string; - }; - proofUnreceived: string; - nextSequenceRecv: string; - }; -} - -// types for mgs type:: /ibc.core.client.v1.MsgCreateClient -export interface Neutron1TrxMsgIbcCoreClientV1MsgCreateClient - extends IRangeMessage { - type: Neutron1TrxMsgTypes.IbcCoreClientV1MsgCreateClient; - data: { - clientState: { - '@type': string; - chainId: string; - trustLevel: { - numerator: string; - denominator: string; - }; - trustingPeriod: string; - unbondingPeriod: string; - maxClockDrift: string; - frozenHeight?: { - revisionHeight?: string; - revisionNumber?: string; - }; - latestHeight: { - revisionNumber: string; - revisionHeight: string; - }; - proofSpecs: { - leafSpec: { - hash: string; - prehashValue: string; - length: string; - prefix: string; - }; - innerSpec: { - childOrder: number[]; - childSize: number; - minPrefixLength: number; - maxPrefixLength: number; - hash: string; - }; - }[]; - upgradePath: string[]; - allowUpdateAfterExpiry: boolean; - allowUpdateAfterMisbehaviour: boolean; - }; - consensusState: { - '@type': string; - timestamp: string; - root: { - hash: string; - }; - nextValidatorsHash: string; - }; - signer: string; - }; -} - -// types for mgs type:: ibc.core.client.v1.MsgUpdateClient -export interface Neutron1TrxMsgIbcCoreClientV1MsgUpdateClient - extends IRangeMessage { - type: Neutron1TrxMsgTypes.IbcCoreClientV1MsgUpdateClient; - data: { - clientId: string; - clientMessage: { - '@type': string; - signedHeader: { - header: { - version: { - block: string; - app?: string; - }; - chainId: string; - height: string; - time: string; - lastBlockId: { - hash: string; - partSetHeader: { - total: number; - hash: string; - }; - }; - lastCommitHash: string; - dataHash: string; - validatorsHash: string; - nextValidatorsHash: string; - consensusHash: string; - appHash: string; - lastResultsHash: string; - evidenceHash: string; - proposerAddress: string; - }; - commit: { - height: string; - round?: number; - blockId: { - hash: string; - partSetHeader: { - total: number; - hash: string; - }; - }; - signatures: { - blockIdFlag: string; - validatorAddress?: string; - timestamp?: string; - signature?: string; - }[]; - }; - }; - validatorSet: { - validators: { - address: string; - pubKey: { - ed25519: string; - }; - votingPower: string; - proposerPriority?: string; - }[]; - proposer: { - address: string; - pubKey: { - ed25519: string; - }; - votingPower: string; - proposerPriority?: string; - }; - totalVotingPower?: string; - }; - trustedHeight: { - revisionNumber?: string; - revisionHeight: string; - }; - trustedValidators: { - validators: { - address: string; - pubKey: { - ed25519: string; - }; - votingPower: string; - proposerPriority?: string; - }[]; - proposer: { - address: string; - pubKey: { - ed25519: string; - }; - votingPower: string; - proposerPriority?: string; - }; - totalVotingPower?: string; - }; - }; - signer: string; - }; -} - -// types for mgs type:: /osmosis.tokenfactory.v1beta1.MsgCreateDenom -export interface Neutron1TrxMsgOsmosisTokenFactoryV1beta1MsgCreateDenom - extends IRangeMessage { - type: Neutron1TrxMsgTypes.OsmosisTokenFactoryV1beta1MsgCreateDenom; - data: { - sender: string; - subdenom: string; - }; -} - -// types for mgs type:: /osmosis.tokenfactory.v1beta1.MsgMint -export interface Neutron1TrxMsgOsmosisTokenfactoryV1beta1MsgMint - extends IRangeMessage { - type: Neutron1TrxMsgTypes.OsmosisTokenfactoryV1beta1MsgMint; - data: { - sender: string; - amount: { - denom: string; - amount: string; - }; - mintToAddress?: string; - }; -} - -// types for mgs type:: /cosmwasm.wasm.v1.MsgUpdateAdmin -export interface Neutron1TrxMsgCosmwasmWasmV1MsgUpdateAdmin - extends IRangeMessage { - type: Neutron1TrxMsgTypes.CosmwasmWasmV1MsgUpdateAdmin; - data: { - sender: string; - contract: string; - newAdmin: string; - }; -} diff --git a/src/types/chain/noble-1/IRangeBlockNoble1Trx.ts b/src/types/chain/noble-1/IRangeBlockNoble1Trx.ts deleted file mode 100644 index 0c996d4e..00000000 --- a/src/types/chain/noble-1/IRangeBlockNoble1Trx.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { IRangeTransaction } from '../IRangeTransaction'; -import { Noble1TrxMsg } from './IRangeBlockNoble1TrxMsg'; - -export interface Noble1Trx extends IRangeTransaction { - messages: Noble1TrxMsg[]; -} diff --git a/src/types/chain/noble-1/IRangeBlockNoble1TrxMsg.ts b/src/types/chain/noble-1/IRangeBlockNoble1TrxMsg.ts deleted file mode 100644 index da0162e5..00000000 --- a/src/types/chain/noble-1/IRangeBlockNoble1TrxMsg.ts +++ /dev/null @@ -1,643 +0,0 @@ -import { IRangeMessage } from '../IRangeMessage'; - -export enum Noble1TrxMsgTypes { - IbcCoreConnectionV1MsgConnectionOpenConfirm = 'ibc.core.connection.v1.MsgConnectionOpenConfirm', - NobleFiatTokenFactoryMsgBurn = 'noble.fiattokenfactory.MsgBurn', - IbcCoreChannelV1MsgTimeout = 'ibc.core.channel.v1.MsgTimeout', - CosmosAuthzV1beta1MsgExec = 'cosmos.authz.v1beta1.MsgExec', - IbcCoreChannelV1MsgRecvPacket = 'ibc.core.channel.v1.MsgRecvPacket', - IbcCoreConnectionV1MsgConnectionOpenAck = 'ibc.core.connection.v1.MsgConnectionOpenAck', - CosmosFeegrantV1beta1MsgGrantAllowance = 'cosmos.feegrant.v1beta1.MsgGrantAllowance', - IbcCoreChannelV1MsgChannelOpenInit = 'ibc.core.channel.v1.MsgChannelOpenInit', - IbcCoreConnectionV1MsgConnectionOpenTry = 'ibc.core.connection.v1.MsgConnectionOpenTry', - IbcCoreConnectionV1MsgConnectionOpenInit = 'ibc.core.connection.v1.MsgConnectionOpenInit', - IbcApplicationsTransferV1MsgTransfer = 'ibc.applications.transfer.v1.MsgTransfer', - CosmosBankV1beta1MsgSend = 'cosmos.bank.v1beta1.MsgSend', - IbcCoreChannelV1MsgChannelOpenAck = 'ibc.core.channel.v1.MsgChannelOpenAck', - NobleFiatTokenFactoryMsgMint = 'noble.fiattokenfactory.MsgMint', - IbcCoreChannelV1MsgChannelOpenTry = 'ibc.core.channel.v1.MsgChannelOpenTry', - IbcCoreChannelV1MsgChannelOpenConfirm = 'ibc.core.channel.v1.MsgChannelOpenConfirm', - IbcCoreChannelV1MsgAcknowledgement = 'ibc.core.channel.v1.MsgAcknowledgement', - CosmosAuthzV1beta1MsgGrant = 'cosmos.authz.v1beta1.MsgGrant', - IbcCoreClientV1MsgCreateClient = 'ibc.core.client.v1.MsgCreateClient', - CosmosFeegrantV1beta1MsgRevokeAllowance = 'cosmos.feegrant.v1beta1.MsgRevokeAllowance', - IbcCoreClientV1MsgUpdateClient = 'ibc.core.client.v1.MsgUpdateClient', -} - -export type Noble1TrxMsg = - | Noble1TrxMsgIbcCoreConnectionV1MsgConnectionOpenConfirm - | Noble1TrxMsgNobleFiatTokenFactoryMsgBurn - | Noble1TrxMsgIbcCoreChannelV1MsgTimeout - | Noble1TrxMsgCosmosAuthzV1beta1MsgExec - | Noble1TrxMsgIbcCoreChannelV1MsgRecvPacket - | Noble1TrxMsgIbcCoreConnectionV1MsgConnectionOpenAck - | Noble1TrxMsgCosmosFeegrantV1beta1MsgGrantAllowance - | Noble1TrxMsgTypeMsgChannelOpenInit - | Noble1TrxMsgIbcCoreConnectionV1MsgConnectionOpenTry - | Noble1TrxMsgIbcCoreConnectionV1MsgConnectionOpenInit - | Noble1TrxMsgIbcApplicationsTransferV1MsgTransfer - | Noble1TrxMsgCosmosBankV1beta1MsgSend - | Noble1TrxMsgIbcCoreChannelV1MsgChannelOpenAck - | Noble1TrxMsgNobleFiatTokenFactoryMsgMint - | Noble1TrxMsgIbcCoreChannelOpenTry - | Noble1TrxMsgIbcCoreChannelOpenConfirm - | Noble1TrxMsgIbcCoreChannelV1MsgAcknowledgement - | Noble1TrxMsgCosmosAuthzMsgGrant - | Noble1TrxMsgIbcCoreClientV1MsgCreateClient - | Noble1TrxMsgCosmosFeegrantV1beta1MsgRevokeAllowance - | Noble1TrxMsgIbcCoreClientV1MsgUpdateClient; - -// types for msg type:: /ibc.core.connection.v1.MsgConnectionOpenConfirm -export interface Noble1TrxMsgIbcCoreConnectionV1MsgConnectionOpenConfirm - extends IRangeMessage { - type: Noble1TrxMsgTypes.IbcCoreConnectionV1MsgConnectionOpenConfirm; - data: { - signer: string; - proofAck: string; - proofHeight: { - revisionHeight: string; - revisionNumber: string; - }; - connectionId: string; - }; -} - -// types for msg type:: /noble.fiattokenfactory.MsgBurn -export interface Noble1TrxMsgNobleFiatTokenFactoryMsgBurn - extends IRangeMessage { - type: Noble1TrxMsgTypes.NobleFiatTokenFactoryMsgBurn; - data: { - from: string; - amount: { - denom: string; - amount: string; - }; - }; -} - -// types for msg type:: /ibc.core.channel.v1.MsgTimeout -export interface Noble1TrxMsgIbcCoreChannelV1MsgTimeout extends IRangeMessage { - type: Noble1TrxMsgTypes.IbcCoreChannelV1MsgTimeout; - data: { - packet: { - sequence: string; - sourcePort: string; - sourceChannel: string; - destinationPort: string; - destinationChannel: string; - data: string; - timeoutHeight?: { - revisionNumber?: string; - revisionHeight?: string; - }; - timeoutTimestamp?: string; - }; - proofUnreceived: string; - proofHeight: { - revisionNumber?: string; - revisionHeight: string; - }; - nextSequenceRecv: string; - signer: string; - }; -} - -// types for msg type:: /cosmos.authz.v1beta1.MsgExec -export interface Noble1TrxMsgCosmosAuthzV1beta1MsgExec extends IRangeMessage { - type: Noble1TrxMsgTypes.CosmosAuthzV1beta1MsgExec; - data: { - grantee: string; - msgs: Noble1TrxMsgCosmosAuthzV1beta1MsgExecDataMsgSend[]; - }; -} - -interface Noble1TrxMsgCosmosAuthzV1beta1MsgExecDataMsgSend { - '@type': '/cosmos.bank.v1beta1.MsgSend'; - fromAddress: string; - toAddress: string; - amount: { - denom: string; - amount: string; - }[]; -} - -// types for msg type:: /ibc.core.channel.v1.MsgRecvPacket -export interface Noble1TrxMsgIbcCoreChannelV1MsgRecvPacket - extends IRangeMessage { - type: Noble1TrxMsgTypes.IbcCoreChannelV1MsgRecvPacket; - data: { - packet: { - sequence: string; - sourcePort: string; - sourceChannel: string; - destinationPort: string; - destinationChannel: string; - data: string; - timeoutHeight?: { - revisionNumber?: string; - revisionHeight?: string; - }; - timeoutTimestamp?: string; - }; - proofCommitment: string; - proofHeight: { - revisionNumber?: string; - revisionHeight: string; - }; - signer: string; - }; -} - -// types for msg type:: /ibc.core.connection.v1.MsgConnectionOpenAck -export interface Noble1TrxMsgIbcCoreConnectionV1MsgConnectionOpenAck - extends IRangeMessage { - type: Noble1TrxMsgTypes.IbcCoreConnectionV1MsgConnectionOpenAck; - data: { - connectionId: string; - counterpartyConnectionId: string; - version: { - identifier: string; - features: string[]; - }; - clientState: { - '@type': string; - chainId: string; - trustLevel: { - numerator: string; - denominator: string; - }; - trustingPeriod: string; - unbondingPeriod: string; - maxClockDrift: string; - frozenHeight: { - revisionNumber?: string; - revisionHeight?: string; - }; - latestHeight: { - revisionNumber?: string; - revisionHeight: string; - }; - proofSpecs: { - leafSpec: { - hash: string; - prehashValue: string; - length: string; - prefix: string; - }; - innerSpec: { - childOrder: number[]; - childSize: number; - minPrefixLength: number; - maxPrefixLength: number; - hash: string; - }; - }[]; - upgradePath: string[]; - allowUpdateAfterExpiry: boolean; - allowUpdateAfterMisbehaviour: boolean; - }; - proofHeight: { - revisionNumber: string; - revisionHeight: string; - }; - proofTry: string; - proofClient: string; - proofConsensus: string; - consensusHeight: { - revisionNumber: string; - revisionHeight: string; - }; - signer: string; - }; -} - -// types for msg type:: /cosmos.feegrant.v1beta1.MsgGrantAllowance -export interface Noble1TrxMsgCosmosFeegrantV1beta1MsgGrantAllowance - extends IRangeMessage { - type: Noble1TrxMsgTypes.CosmosFeegrantV1beta1MsgGrantAllowance; - data: { - granter: string; - grantee: string; - allowance: Noble1TrxMsgCosmosFeegrantV1beta1MsgGrantAllowanceAllowedMsgAllowance; - }; -} - -interface Noble1TrxMsgCosmosFeegrantV1beta1MsgGrantAllowanceAllowedMsgAllowance { - '@type': '/cosmos.feegrant.v1beta1.AllowedMsgAllowance'; - allowance: { - '@type': string; - }; - allowedMessages: string[]; -} - -// types for msg type:: /ibc.core.channel.v1.MsgChannelOpenInit -export interface Noble1TrxMsgTypeMsgChannelOpenInit extends IRangeMessage { - type: Noble1TrxMsgTypes.IbcCoreChannelV1MsgChannelOpenInit; - data: { - portId: string; - signer: string; - channel: { - state: string; - version: string; - ordering: string; - counterparty: { - portId: string; - }; - connectionHops: string[]; - }; - }; -} - -// types for msg type:: /ibc.core.connection.v1.MsgConnectionOpenTry -export interface Noble1TrxMsgIbcCoreConnectionV1MsgConnectionOpenTry - extends IRangeMessage { - type: Noble1TrxMsgTypes.IbcCoreConnectionV1MsgConnectionOpenTry; - data: { - clientId: string; - clientState: { - '@type': string; - chainId: string; - trustLevel: { - numerator: string; - denominator: string; - }; - trustingPeriod: string; - unbondingPeriod: string; - maxClockDrift: string; - frozenHeight: { - revisionNumber?: string; - revisionHeight?: string; - }; - latestHeight: { - revisionNumber: string; - revisionHeight: string; - }; - proofSpecs: { - leafSpec: { - hash: string; - prehashValue: string; - length: string; - prefix: string; - }; - innerSpec: { - childOrder: number[]; - childSize: number; - minPrefixLength: number; - maxPrefixLength: number; - hash: string; - }; - }[]; - upgradePath: string[]; - allowUpdateAfterExpiry: boolean; - allowUpdateAfterMisbehaviour: boolean; - }; - counterparty: { - clientId: string; - connectionId: string; - prefix: { - keyPrefix: string; - }; - }; - counterpartyVersions: { - identifier: string; - features: string[]; - }[]; - proofHeight: { - revisionNumber: string; - revisionHeight: string; - }; - proofInit: string; - proofClient: string; - proofConsensus: string; - consensusHeight: { - revisionNumber: string; - revisionHeight: string; - }; - signer: string; - }; -} - -// types for msg type:: /ibc.core.connection.v1.MsgConnectionOpenInit -export interface Noble1TrxMsgIbcCoreConnectionV1MsgConnectionOpenInit - extends IRangeMessage { - type: Noble1TrxMsgTypes.IbcCoreConnectionV1MsgConnectionOpenInit; - data: { - clientId: string; - counterparty: { - clientId: string; - prefix: { - keyPrefix: string; - }; - }; - signer: string; - }; -} - -// types for msg type:: /ibc.applications.transfer.v1.MsgTransfer -export interface Noble1TrxMsgIbcApplicationsTransferV1MsgTransfer - extends IRangeMessage { - type: Noble1TrxMsgTypes.IbcApplicationsTransferV1MsgTransfer; - data: { - sourcePort: string; - sourceChannel: string; - token: { - denom: string; - amount: string; - }; - sender: string; - receiver: string; - timeoutHeight?: { - revisionHeight?: string; - revisionNumber?: string; - }; - timeoutTimestamp?: string; - memo?: string; - }; -} - -// types for msg type:: /cosmos.bank.v1beta1.MsgSend -export interface Noble1TrxMsgCosmosBankV1beta1MsgSend extends IRangeMessage { - type: Noble1TrxMsgTypes.CosmosBankV1beta1MsgSend; - data: { - amount: { denom: string; amount: string }[]; - toAddress: string; - fromAddress: string; - }; -} - -// types for msg type:: /ibc.core.channel.v1.MsgChannelOpenAck -export interface Noble1TrxMsgIbcCoreChannelV1MsgChannelOpenAck - extends IRangeMessage { - type: Noble1TrxMsgTypes.IbcCoreChannelV1MsgChannelOpenAck; - data: { - portId: string; - signer: string; - proofTry: string; - channelId: string; - proofHeight: { - revisionHeight: string; - revisionNumber?: string; - }; - counterpartyVersion: string; - counterpartyChannelId: string; - }; -} - -// types for msg type:: /noble.fiattokenfactory.MsgMint -export interface Noble1TrxMsgNobleFiatTokenFactoryMsgMint - extends IRangeMessage { - type: Noble1TrxMsgTypes.NobleFiatTokenFactoryMsgMint; - data: { - from: string; - amount: { denom: string; amount: string }; - address: string; - }; -} - -// types for msg type:: /ibc.core.channel.v1.MsgChannelOpenTry -export interface Noble1TrxMsgIbcCoreChannelOpenTry extends IRangeMessage { - type: Noble1TrxMsgTypes.IbcCoreChannelV1MsgChannelOpenTry; - data: { - portId: string; - signer: string; - channel: { - state: string; - version: string; - ordering: string; - counterparty: { - portId: string; - channelId: string; - }; - connectionHops: string[]; - }; - proofInit: string; - proofHeight: { - revisionHeight: string; - revisionNumber: string; - }; - counterpartyVersion: string; - }; -} - -// types for msg type:: /ibc.core.channel.v1.MsgChannelOpenConfirm -export interface Noble1TrxMsgIbcCoreChannelOpenConfirm extends IRangeMessage { - type: Noble1TrxMsgTypes.IbcCoreChannelV1MsgChannelOpenConfirm; - data: { - portId: string; - signer: string; - proofAck: string; - channelId: string; - proofHeight: { - revisionHeight: string; - revisionNumber: string; - }; - }; -} - -// types for msg type:: /ibc.core.channel.v1.MsgAcknowledgement -export interface Noble1TrxMsgIbcCoreChannelV1MsgAcknowledgement - extends IRangeMessage { - type: Noble1TrxMsgTypes.IbcCoreChannelV1MsgAcknowledgement; - data: { - packet: { - sequence: string; - sourcePort: string; - sourceChannel: string; - destinationPort: string; - destinationChannel: string; - data: string; - timeoutHeight?: { - revisionNumber?: string; - revisionHeight?: string; - }; - timeoutTimestamp?: string; - }; - acknowledgement: string; - proofAcked: string; - proofHeight: { - revisionNumber?: string; - revisionHeight: string; - }; - signer: string; - }; -} - -// types for msg type:: /cosmos.authz.v1beta1.MsgGrant -export interface Noble1TrxMsgCosmosAuthzMsgGrant extends IRangeMessage { - type: Noble1TrxMsgTypes.CosmosAuthzV1beta1MsgGrant; - data: { - '@type': string; - grant: { - expiration: string; - authorization: { - msg: string; - '@type': string; - }; - }; - grantee: string; - granter: string; - }; -} - -// types for msg type:: /ibc.core.client.v1.MsgCreateClient -export interface Noble1TrxMsgIbcCoreClientV1MsgCreateClient - extends IRangeMessage { - type: Noble1TrxMsgTypes.IbcCoreClientV1MsgCreateClient; - data: { - clientState: { - '@type': string; - chainId: string; - trustLevel: { - numerator: string; - denominator: string; - }; - trustingPeriod: string; - unbondingPeriod: string; - maxClockDrift: string; - frozenHeight?: { - revisionNumber?: string; - revisionHeight?: string; - }; - latestHeight: { - revisionNumber?: string; - revisionHeight: string; - }; - proofSpecs: { - leafSpec: { - hash: string; - prehashValue: string; - length: string; - prefix: string; - }; - innerSpec: { - childOrder: number[]; - childSize: number; - minPrefixLength: number; - maxPrefixLength: number; - hash: string; - }; - }[]; - upgradePath: string[]; - allowUpdateAfterExpiry: boolean; - allowUpdateAfterMisbehaviour: boolean; - }; - consensusState: { - '@type': string; - timestamp: string; - root: { - hash: string; - }; - nextValidatorsHash: string; - }; - signer: string; - }; -} - -// types for mgs type:: /cosmos.feegrant.v1beta1.MsgRevokeAllowance -export interface Noble1TrxMsgCosmosFeegrantV1beta1MsgRevokeAllowance - extends IRangeMessage { - type: Noble1TrxMsgTypes.CosmosFeegrantV1beta1MsgRevokeAllowance; - data: { - grantee: string; - granter: string; - }; -} - -// types for mgs type:: /ibc.core.client.v1.MsgUpdateClient -export interface Noble1TrxMsgIbcCoreClientV1MsgUpdateClient - extends IRangeMessage { - type: Noble1TrxMsgTypes.IbcCoreClientV1MsgUpdateClient; - data: { - clientId: string; - clientMessage: { - '@type': string; - signedHeader: { - header: { - version: { - block: string; - app?: string; - }; - chainId: string; - height: string; - time: string; - lastBlockId: { - hash: string; - partSetHeader: { - total: number; - hash: string; - }; - }; - lastCommitHash: string; - dataHash: string; - validatorsHash: string; - nextValidatorsHash: string; - consensusHash: string; - appHash: string; - lastResultsHash: string; - evidenceHash: string; - proposerAddress: string; - }; - commit: { - height: string; - round?: number; - blockId: { - hash: string; - partSetHeader: { - total: number; - hash: string; - }; - }; - signatures: { - blockIdFlag: string; - validatorAddress?: string; - timestamp: string; - signature?: string; - }[]; - }; - }; - validatorSet: { - validators: { - address: string; - pubKey: { - ed25519: string; - }; - votingPower: string; - proposerPriority?: string; - }[]; - proposer: { - address: string; - pubKey: { - ed25519: string; - }; - votingPower: string; - proposerPriority?: string; - }; - totalVotingPower?: string; - }; - trustedHeight: { - revisionNumber?: string; - revisionHeight: string; - }; - trustedValidators: { - validators: { - address: string; - pubKey: { - ed25519: string; - }; - votingPower: string; - proposerPriority?: string; - }[]; - proposer: { - address: string; - pubKey: { - ed25519: string; - }; - votingPower: string; - proposerPriority?: string; - }; - totalVotingPower?: string; - }; - }; - signer: string; - }; -} diff --git a/src/types/chain/osmo-test-5/IRangeBlockOsmoTest5Trx.ts b/src/types/chain/osmo-test-5/IRangeBlockOsmoTest5Trx.ts deleted file mode 100644 index ac108b67..00000000 --- a/src/types/chain/osmo-test-5/IRangeBlockOsmoTest5Trx.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { IRangeTransaction } from '../IRangeTransaction'; -import { OsmoTest5TrxMsg } from './IRangeBlockOsmoTest5TrxMsg'; - -export interface OsmoTest5Trx extends IRangeTransaction { - messages: OsmoTest5TrxMsg[]; -} diff --git a/src/types/chain/osmo-test-5/IRangeBlockOsmoTest5TrxMsg.ts b/src/types/chain/osmo-test-5/IRangeBlockOsmoTest5TrxMsg.ts deleted file mode 100644 index 19a9e8f9..00000000 --- a/src/types/chain/osmo-test-5/IRangeBlockOsmoTest5TrxMsg.ts +++ /dev/null @@ -1,872 +0,0 @@ -import { IRangeMessage } from '../IRangeMessage'; - -enum OsmoTest5TrxMsgTypes { - CosmosBankV1beta1MsgSend = 'cosmos.bank.v1beta1.MsgSend', - CosmosDistributionV1beta1MsgWithdrawDelegatorReward = 'cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward', - CosmosGovV1beta1MsgSubmitProposal = 'cosmos.gov.v1beta1.MsgSubmitProposal', - CosmosGovV1beta1MsgVote = 'cosmos.gov.v1beta1.MsgVote', - CosmosSlashingV1beta1MsgUnjail = 'cosmos.slashing.v1beta1.MsgUnjail', - CosmosStakingV1beta1MsgBeginRedelegate = 'cosmos.staking.v1beta1.MsgBeginRedelegate', - CosmosStakingV1beta1MsgCreateValidator = 'cosmos.staking.v1beta1.MsgCreateValidator', - CosmosStakingV1beta1MsgDelegate = 'cosmos.staking.v1beta1.MsgDelegate', - CosmosStakingV1beta1MsgUndelegate = 'cosmos.staking.v1beta1.MsgUndelegate', - CosmosWasmV1MsgExecuteContract = 'cosmwasm.wasm.v1.MsgExecuteContract', - CosmosWasmV1MsgInstantiateContract = 'cosmwasm.wasm.v1.MsgInstantiateContract', - CosmosWasmV1MsgMigrateContract = 'cosmwasm.wasm.v1.MsgMigrateContract', - CosmWasmWasmV1MsgStoreCode = 'cosmwasm.wasm.v1.MsgStoreCode', - IbcApplicationsTransferV1MsgTransfer = 'ibc.applications.transfer.v1.MsgTransfer', - IbcCoreChannelV1MsgAcknowledgement = 'ibc.core.channel.v1.MsgAcknowledgement', - IbcCoreChannelV1MsgChannelCloseConfirm = 'ibc.core.channel.v1.MsgChannelCloseConfirm', - IbcCoreChannelV1MsgChannelOpenAck = 'ibc.core.channel.v1.MsgChannelOpenAck', - IbcCoreChannelV1MsgChannelOpenConfirm = 'ibc.core.channel.v1.MsgChannelOpenConfirm', - IbcCoreChannelV1MsgChannelOpenInit = 'ibc.core.channel.v1.MsgChannelOpenInit', - IbcCoreChannelV1MsgChannelOpenTry = 'ibc.core.channel.v1.MsgChannelOpenTry', - IbcCoreChannelV1MsgRecvPacket = 'ibc.core.channel.v1.MsgRecvPacket', - IbcCoreChannelV1MsgTimeout = 'ibc.core.channel.v1.MsgTimeout', - IbcCoreClientV1MsgCreateClient = 'ibc.core.client.v1.MsgCreateClient', - IbcCoreClientV1MsgUpdateClient = 'ibc.core.client.v1.MsgUpdateClient', - IbcCoreConnectionV1MsgConnectionOpenAck = 'ibc.core.connection.v1.MsgConnectionOpenAck', - IbcCoreConnectionV1MsgConnectionOpenConfirm = 'ibc.core.connection.v1.MsgConnectionOpenConfirm', - IbcCoreConnectionV1MsgConnectionOpenInit = 'ibc.core.connection.v1.MsgConnectionOpenInit', - IbcCoreConnectionV1MsgConnectionOpenTry = 'ibc.core.connection.v1.MsgConnectionOpenTry', - OsmosisConcentratedLiquidityPoolModelConcentratedV1beta1MsgCreateConcentratedPool = 'osmosis.concentratedliquidity.poolmodel.concentrated.v1beta1.MsgCreateConcentratedPool', - OsmosisConcentratedLiquidityV1Beta1MsgCollectIncentives = 'osmosis.concentratedliquidity.v1beta1.MsgCollectIncentives', - OsmosisCosmwasmPoolV1Beta1MsgCreateCosmWasmPool = 'osmosis.cosmwasmpool.v1beta1.MsgCreateCosmWasmPool', - OsmosisGammV1Beta1MsgJoinPool = 'osmosis.gamm.v1beta1.MsgJoinPool', - OsmosisGammV1beta1MsgSwapExactAmountIn = 'osmosis.gamm.v1beta1.MsgSwapExactAmountIn', - OsmosisPoolManagerV1beta1MsgSwapExactAmountIn = 'osmosis.poolmanager.v1beta1.MsgSwapExactAmountIn', - OsmosisTokenFactoryV1beta1MsgCreateDenom = 'osmosis.tokenfactory.v1beta1.MsgCreateDenom', - OsmosisTokenFactoryV1beta1MsgMint = 'osmosis.tokenfactory.v1beta1.MsgMint', - OsmosisValsetprefV1beta1MsgDelegateToValidatorSet = 'osmosis.valsetpref.v1beta1.MsgDelegateToValidatorSet', - OsmosisValsetprefV1beta1MsgSetValidatorSetPreference = 'osmosis.valsetpref.v1beta1.MsgSetValidatorSetPreference', -} - -export type OsmoTest5TrxMsg = - | OsmoTest5TrxMsgCosmosBankV1beta1MsgSend - | OsmoTest5TrxMsgCosmosDistributionV1beta1MsgWithdrawDelegatorReward - | OsmoTest5TrxMsgCosmosGovV1beta1MsgSubmitProposal - | OsmoTest5TrxMsgCosmosGovV1beta1MsgVote - | OsmoTest5TrxMsgCosmosSlashingV1beta1MsgUnjail - | OsmoTest5TrxMsgCosmosStakingV1beta1MsgBeginRedelegate - | OsmoTest5TrxMsgCosmosStakingV1beta1MsgCreateValidator - | OsmoTest5TrxMsgCosmosStakingV1beta1MsgDelegate - | OsmoTest5TrxMsgCosmosStakingV1beta1MsgUndelegate - | OsmoTest5TrxMsgCosmosWasmV1MsgExecuteContract - | OsmoTest5TrxMsgCosmosWasmV1MsgInstantiateContract - | OsmoTest5TrxMsgCosmosWasmV1MsgMigrateContract - | OsmoTest5TrxMsgCosmWasmWasmV1MsgStoreCode - | OsmoTest5TrxMsgIbcApplicationsTransferV1MsgTransfer - | OsmoTest5TrxMsgIbcCoreChannelV1MsgAcknowledgement - | OsmoTest5TrxMsgIbcCoreChannelV1MsgChannelCloseConfirm - | OsmoTest5TrxMsgIbcCoreChannelV1MsgChannelOpenAck - | OsmoTest5TrxMsgIbcCoreChannelV1MsgChannelOpenConfirm - | OsmoTest5TrxMsgIbcCoreChannelV1MsgChannelOpenInit - | OsmoTest5TrxMsgIbcCoreChannelV1MsgChannelOpenTry - | OsmoTest5TrxMsgIbcCoreChannelV1MsgRecvPacket - | OsmoTest5TrxMsgIbcCoreChannelV1MsgTimeout - | OsmoTest5TrxMsgIbcCoreClientV1MsgCreateClient - | OsmoTest5TrxMsgIbcCoreClientV1MsgUpdateClient - | OsmoTest5TrxMsgIbcCoreConnectionV1MsgConnectionOpenAck - | OsmoTest5TrxMsgIbcCoreConnectionV1MsgConnectionOpenConfirm - | OsmoTest5TrxMsgIbcCoreConnectionV1MsgConnectionOpenInit - | OsmoTest5TrxMsgIbcCoreConnectionV1MsgConnectionOpenTry - | OsmoTest5TrxMsgOsmosisConcentratedLiquidityPoolModelConcentratedV1beta1MsgCreateConcentratedPool - | OsmoTest5TrxMsgOsmosisConcentratedLiquidityV1Beta1MsgCollectIncentives - | OsmoTest5TrxMsgOsmosisCosmwasmPoolV1Beta1MsgCreateCosmWasmPool - | OsmoTest5TrxMsgOsmosisGammV1Beta1MsgJoinPool - | OsmoTest5TrxMsgOsmosisGammV1beta1MsgSwapExactAmountIn - | OsmoTest5TrxMsgOsmosisPoolManagerV1beta1MsgSwapExactAmountIn - | OsmoTest5TrxMsgOsmosisTokenFactoryV1beta1MsgCreateDenom - | OsmoTest5TrxMsgOsmosisTokenFactoryV1beta1MsgMint - | OsmoTest5TrxMsgOsmosisValsetprefV1beta1MsgDelegateToValidatorSet - | OsmoTest5TrxMsgOsmosisValsetprefV1beta1MsgSetValidatorSetPreference; - -// types for mgs type:: /cosmos.bank.v1beta1.MsgSend -export interface OsmoTest5TrxMsgCosmosBankV1beta1MsgSend extends IRangeMessage { - type: OsmoTest5TrxMsgTypes.CosmosBankV1beta1MsgSend; - data: { - amount: { denom: string; amount: string }[]; - toAddress: string; - fromAddress: string; - }; -} - -// types for mgs type:: /cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward -export interface OsmoTest5TrxMsgCosmosDistributionV1beta1MsgWithdrawDelegatorReward - extends IRangeMessage { - type: OsmoTest5TrxMsgTypes.CosmosDistributionV1beta1MsgWithdrawDelegatorReward; - data: { - delegatorAddress: string; - validatorAddress: string; - }; -} - -// types for mgs type:: /cosmos.gov.v1beta1.MsgSubmitProposal -export interface OsmoTest5TrxMsgCosmosGovV1beta1MsgSubmitProposal - extends IRangeMessage { - type: OsmoTest5TrxMsgTypes.CosmosGovV1beta1MsgSubmitProposal; - data: { - '@type': string; - content: { - plan: { - info: string; - name: string; - time: string; - height: string; - upgraded_client_state?: unknown; - }; - '@type': string; - title: string; - description: string; - }; - proposer: string; - initial_deposit: { denom: string; amount: string }[]; - }; -} - -// types for mgs type:: /cosmos.gov.v1beta1.MsgVote -export interface OsmoTest5TrxMsgCosmosGovV1beta1MsgVote extends IRangeMessage { - type: OsmoTest5TrxMsgTypes.CosmosGovV1beta1MsgVote; - data: { - voter: string; - option: string; - proposalId: string; - }; -} - -// types for mgs type:: /cosmos.slashing.v1beta1.MsgUnjail -export interface OsmoTest5TrxMsgCosmosSlashingV1beta1MsgUnjail - extends IRangeMessage { - type: OsmoTest5TrxMsgTypes.CosmosSlashingV1beta1MsgUnjail; - data: { - validatorAddr: string; - }; -} - -// types for mgs type:: /cosmos.staking.v1beta1.MsgBeginRedelegate -export interface OsmoTest5TrxMsgCosmosStakingV1beta1MsgBeginRedelegate - extends IRangeMessage { - type: OsmoTest5TrxMsgTypes.CosmosStakingV1beta1MsgBeginRedelegate; - data: { - amount: { denom: string; amount: string }; - delegatorAddress: string; - validatorDstAddress: string; - validatorSrcAddress: string; - }; -} - -// types for mgs type:: /cosmos.staking.v1beta1.MsgCreateValidator -export interface OsmoTest5TrxMsgCosmosStakingV1beta1MsgCreateValidator - extends IRangeMessage { - type: OsmoTest5TrxMsgTypes.CosmosStakingV1beta1MsgCreateValidator; - data: { - '@type': string; - value: { denom: string; amount: string }; - pubkey: { key: string; '@type': string }; - commission: { rate: string; max_rate: string; max_change_rate: string }; - description: { - details: string; - moniker: string; - website: string; - identity: string; - security_contact: string; - }; - delegator_address: string; - validator_address: string; - min_self_delegation: string; - }; -} - -// types for mgs type:: /cosmos.staking.v1beta1.MsgDelegate -export interface OsmoTest5TrxMsgCosmosStakingV1beta1MsgDelegate - extends IRangeMessage { - type: OsmoTest5TrxMsgTypes.CosmosStakingV1beta1MsgDelegate; - data: { - amount: { denom: string; amount: string }; - delegatorAddress: string; - validatorAddress: string; - }; -} - -// types for mgs type:: /cosmos.staking.v1beta1.MsgUndelegate -export interface OsmoTest5TrxMsgCosmosStakingV1beta1MsgUndelegate - extends IRangeMessage { - type: OsmoTest5TrxMsgTypes.CosmosStakingV1beta1MsgUndelegate; - data: { - amount: { denom: string; amount: string }; - delegatorAddress: string; - validatorAddress: string; - }; -} - -// types for mgs type:: /cosmwasm.wasm.v1.MsgExecuteContract -export interface OsmoTest5TrxMsgCosmosWasmV1MsgExecuteContract - extends IRangeMessage { - type: OsmoTest5TrxMsgTypes.CosmosWasmV1MsgExecuteContract; - data: { - msg: string; - funds: { denom: string; amount: string }[]; - sender: string; - contract: string; - }; -} - -// types for mgs type:: /cosmwasm.wasm.v1.MsgInstantiateContract -export interface OsmoTest5TrxMsgCosmosWasmV1MsgInstantiateContract - extends IRangeMessage { - type: OsmoTest5TrxMsgTypes.CosmosWasmV1MsgInstantiateContract; - data: { - msg: string; - admin: string; - funds: { denom: string; amount: string }[]; - label: string; - codeId: string; - sender: string; - }; -} - -// types for mgs type:: /cosmwasm.wasm.v1.MsgMigrateContract -export interface OsmoTest5TrxMsgCosmosWasmV1MsgMigrateContract - extends IRangeMessage { - type: OsmoTest5TrxMsgTypes.CosmosWasmV1MsgMigrateContract; - data: { - msg: string; - codeId: string; - sender: string; - contract: string; - }; -} - -// types for mgs type:: /cosmwasm.wasm.v1.MsgStoreCode -export interface OsmoTest5TrxMsgCosmWasmWasmV1MsgStoreCode - extends IRangeMessage { - type: OsmoTest5TrxMsgTypes.CosmWasmWasmV1MsgStoreCode; - data: { - sender: string; - wasmByteCode: string; - }; -} - -// types for mgs type:: /ibc.applications.transfer.v1.MsgTransfer -export interface OsmoTest5TrxMsgIbcApplicationsTransferV1MsgTransfer - extends IRangeMessage { - type: OsmoTest5TrxMsgTypes.IbcApplicationsTransferV1MsgTransfer; - data: { - token: { - denom: string; - amount: string; - }; - sender: string; - receiver: string; - sourcePort: string; - sourceChannel: string; - timeoutTimestamp: string; - }; -} - -// types for mgs type:: /ibc.core.channel.v1.MsgAcknowledgement -export interface OsmoTest5TrxMsgIbcCoreChannelV1MsgAcknowledgement - extends IRangeMessage { - type: OsmoTest5TrxMsgTypes.IbcCoreChannelV1MsgAcknowledgement; - data: { - packet: { - data: string; - sequence: string; - sourcePort: string; - sourceChannel: string; - timeoutHeight: { revisionHeight: string; revisionNumber: string }; - destinationPort: string; - timeoutTimestamp: string; - destinationChannel: string; - }; - signer: string; - proofAcked: string; - proofHeight: { revisionHeight: string; revisionNumber: string }; - acknowledgement: string; - }; -} - -// types for mgs type:: /ibc.core.channel.v1.MsgChannelCloseConfirm -export interface OsmoTest5TrxMsgIbcCoreChannelV1MsgChannelCloseConfirm - extends IRangeMessage { - type: OsmoTest5TrxMsgTypes.IbcCoreChannelV1MsgChannelCloseConfirm; - data: { - portId: string; - signer: string; - channelId: string; - proofInit: string; - proofHeight: { revisionHeight: string; revisionNumber: string }; - }; -} - -// types for mgs type:: /ibc.core.channel.v1.MsgChannelOpenAck -export interface OsmoTest5TrxMsgIbcCoreChannelV1MsgChannelOpenAck - extends IRangeMessage { - type: OsmoTest5TrxMsgTypes.IbcCoreChannelV1MsgChannelOpenAck; - data: { - portId: string; - signer: string; - proofTry: string; - channelId: string; - proofHeight: { - revisionHeight: string; - revisionNumber: string; - }; - counterpartyVersion: string; - counterpartyChannelId: string; - }; -} - -// types for mgs type:: /ibc.core.channel.v1.MsgChannelOpenConfirm -export interface OsmoTest5TrxMsgIbcCoreChannelV1MsgChannelOpenConfirm - extends IRangeMessage { - type: OsmoTest5TrxMsgTypes.IbcCoreChannelV1MsgChannelOpenConfirm; - data: { - portId: string; - signer: string; - proofAck: string; - channelId: string; - proofHeight: { - revisionHeight: string; - revisionNumber: string; - }; - }; -} - -// types for mgs type:: /ibc.core.channel.v1.MsgChannelOpenInit -export interface OsmoTest5TrxMsgIbcCoreChannelV1MsgChannelOpenInit - extends IRangeMessage { - type: OsmoTest5TrxMsgTypes.IbcCoreChannelV1MsgChannelOpenInit; - data: { - portId: string; - signer: string; - channel: { - state: string; - version: string; - ordering: string; - counterparty: { - portId: string; - }; - connectionHops: string[]; - }; - }; -} - -// types for mgs type:: /ibc.core.channel.v1.MsgChannelOpenTry -export interface OsmoTest5TrxMsgIbcCoreChannelV1MsgChannelOpenTry - extends IRangeMessage { - type: OsmoTest5TrxMsgTypes.IbcCoreChannelV1MsgChannelOpenTry; - data: { - portId: string; - signer: string; - channel: { - state: string; - version: string; - ordering: string; - counterparty: { - portId: string; - channelId: string; - }; - connectionHops: string[]; - }; - proofInit: string; - proofHeight: { - revisionHeight: string; - revisionNumber: string; - }; - counterpartyVersion: string; - }; -} - -// types for msg type: /ibc.core.channel.v1.MsgRecvPacket -export interface OsmoTest5TrxMsgIbcCoreChannelV1MsgRecvPacket - extends IRangeMessage { - type: OsmoTest5TrxMsgTypes.IbcCoreChannelV1MsgRecvPacket; - data: { - packet: { - data: string; - sequence: string; - sourcePort: string; - sourceChannel: string; - timeoutHeight: Record; - destinationPort: string; - timeoutTimestamp: string; - destinationChannel: string; - }; - signer: string; - proofHeight: { revisionHeight: string; revisionNumber: string }; - proofCommitment: string; - }; -} - -// types for msg type: /ibc.core.channel.v1.MsgTimeout -export interface OsmoTest5TrxMsgIbcCoreChannelV1MsgTimeout - extends IRangeMessage { - type: OsmoTest5TrxMsgTypes.IbcCoreChannelV1MsgTimeout; - data: { - packet: { - data: string; - sequence: string; - sourcePort: string; - sourceChannel: string; - timeoutHeight: Record; - destinationPort: string; - timeoutTimestamp: string; - destinationChannel: string; - }; - signer: string; - proofHeight: { revisionHeight: string; revisionNumber: string }; - proofUnreceived: string; - nextSequenceRecv: string; - }; -} - -// types for msg type: /ibc.core.client.v1.MsgCreateClient -export interface OsmoTest5TrxMsgIbcCoreClientV1MsgCreateClient - extends IRangeMessage { - type: OsmoTest5TrxMsgTypes.IbcCoreClientV1MsgCreateClient; - data: { - '@type': string; - signer: string; - client_state: { - '@type': string; - chain_id: string; - proof_specs: { - leaf_spec: { - hash: string; - length: string; - prefix: string; - prehash_key: string; - prehash_value: string; - }; - max_depth: number; - min_depth: number; - inner_spec: { - hash: string; - child_size: number; - child_order: number[]; - empty_child?: unknown; - max_prefix_length: number; - min_prefix_length: number; - }; - prehash_key_before_comparison: boolean; - }[]; - trust_level: { numerator: string; denominator: string }; - upgrade_path: string[]; - frozen_height: { revisionHeight: string; revisionNumber: string }; - latest_height: { revisionHeight: string; revisionNumber: string }; - max_clock_drift: string; - trusting_period: string; - unbonding_period: string; - allow_update_after_expiry: boolean; - allow_update_after_misbehaviour: boolean; - }; - consensus_state: { - root: { hash: string }; - '@type': string; - timestamp: string; - next_validators_hash: string; - }; - }; -} - -// types for msg type:: /ibc.core.client.v1.MsgUpdateClient -export interface OsmoTest5TrxMsgIbcCoreClientV1MsgUpdateClient - extends IRangeMessage { - type: OsmoTest5TrxMsgTypes.IbcCoreClientV1MsgUpdateClient; - data: { - '@type': string; - signer: string; - client_id: string; - client_message: { - '@type': string; - signed_header: { - commit: { - round: number; - height: string; - block_id: { - hash: string; - part_set_header: { - hash: string; - total: number; - }; - }; - signatures: { - signature: string; - timestamp: string; - block_id_flag: string; - validator_address: string; - }[]; - }; - header: { - time: string; - height: string; - version: { - app: string; - block: string; - }; - app_hash: string; - chain_id: string; - data_hash: string; - evidence_hash: string; - last_block_id: { - hash: string; - part_set_header: { - hash: string; - total: number; - }; - }; - consensus_hash: string; - validators_hash: string; - last_commit_hash: string; - proposer_address: string; - last_results_hash: string; - next_validators_hash: string; - }; - }; - validator_set: { - proposer: { - address: string; - pub_key: { - ed25519: string; - }; - voting_power: string; - proposer_priority: string; - }; - validators: { - address: string; - pub_key: { - ed25519: string; - }; - voting_power: string; - proposer_priority: string; - }[]; - total_voting_power: string; - }; - trusted_height: { - revision_height: string; - revision_number: string; - }; - trusted_validators: { - proposer: { - address: string; - pub_key: { - ed25519: string; - }; - voting_power: string; - proposer_priority: string; - }; - validators: { - address: string; - pub_key: { - ed25519: string; - }; - voting_power: string; - proposer_priority: string; - }[]; - total_voting_power: string; - }; - }; - }; -} - -// types for msg type:: /ibc.core.connection.v1.MsgConnectionOpenAck -export interface OsmoTest5TrxMsgIbcCoreConnectionV1MsgConnectionOpenAck - extends IRangeMessage { - type: OsmoTest5TrxMsgTypes.IbcCoreConnectionV1MsgConnectionOpenAck; - data: { - '@type': string; - signer: string; - version: { - features: string[]; - identifier: string; - }; - proof_try: string; - client_state: { - '@type': string; - chain_id: string; - proof_specs: { - leaf_spec: { - hash: string; - length: string; - prefix: string; - prehash_key: string; - prehash_value: string; - }; - max_depth: number; - min_depth: number; - inner_spec: { - hash: string; - child_size: number; - child_order: number[]; - empty_child?: unknown; - max_prefix_length: number; - min_prefix_length: number; - }; - prehash_key_before_comparison: boolean; - }[]; - trust_level: { - numerator: string; - denominator: string; - }; - upgrade_path: string[]; - frozen_height: { - revision_height: string; - revision_number: string; - }; - latest_height: { - revision_height: string; - revision_number: string; - }; - max_clock_drift: string; - trusting_period: string; - unbonding_period: string; - allow_update_after_expiry: boolean; - allow_update_after_misbehaviour: boolean; - }; - proof_client: string; - proof_height: { - revision_height: string; - revision_number: string; - }; - connection_id: string; - proof_consensus: string; - consensus_height: { - revision_height: string; - revision_number: string; - }; - counterparty_connection_id: string; - host_consensus_state_proof?: unknown; - }; -} - -// types for msg type:: /ibc.core.connection.v1.MsgConnectionOpenConfirm -export interface OsmoTest5TrxMsgIbcCoreConnectionV1MsgConnectionOpenConfirm - extends IRangeMessage { - type: OsmoTest5TrxMsgTypes.IbcCoreConnectionV1MsgConnectionOpenConfirm; - data: { - signer: string; - proofAck: string; - proofHeight: { revisionHeight: string; revisionNumber: string }; - connectionId: string; - }; -} - -// types for msg type:: /ibc.core.connection.v1.MsgConnectionOpenInit -export interface OsmoTest5TrxMsgIbcCoreConnectionV1MsgConnectionOpenInit - extends IRangeMessage { - type: OsmoTest5TrxMsgTypes.IbcCoreConnectionV1MsgConnectionOpenInit; - data: { - signer: string; - version: { - features: string[]; - identifier: string; - }; - clientId: string; - counterparty: { - prefix: { - keyPrefix: string; - }; - clientId: string; - }; - }; -} - -// types for msg type:: /ibc.core.connection.v1.MsgConnectionOpenTry -export interface OsmoTest5TrxMsgIbcCoreConnectionV1MsgConnectionOpenTry - extends IRangeMessage { - type: OsmoTest5TrxMsgTypes.IbcCoreConnectionV1MsgConnectionOpenTry; - data: { - '@type': string; - signer: string; - client_id: string; - proof_init: string; - client_state: { - '@type': string; - chain_id: string; - proof_specs: { - leaf_spec: { - hash: string; - length: string; - prefix: string; - prehash_key: string; - prehash_value: string; - }; - max_depth: number; - min_depth: number; - inner_spec: { - hash: string; - child_size: number; - child_order: number[]; - max_prefix_length: number; - min_prefix_length: number; - }; - prehash_key_before_comparison: boolean; - }[]; - trust_level: { - numerator: string; - denominator: string; - }; - upgrade_path: string[]; - frozen_height: { - revision_height: string; - revision_number: string; - }; - latest_height: { - revision_height: string; - revision_number: string; - }; - max_clock_drift: string; - trusting_period: string; - unbonding_period: string; - allow_update_after_expiry: boolean; - allow_update_after_misbehaviour: boolean; - }; - counterparty: { - prefix: { - key_prefix: string; - }; - client_id: string; - connection_id: string; - }; - delay_period: string; - proof_client: string; - proof_height: { - revision_height: string; - revision_number: string; - }; - proof_consensus: string; - consensus_height: { - revision_height: string; - revision_number: string; - }; - counterparty_versions: { - features: string[]; - identifier: string; - }[]; - previous_connection_id: string; - }; -} - -// types for msg type:: /osmosis.concentratedliquidity.poolmodel.concentrated.v1beta1.MsgCreateConcentratedPool -export interface OsmoTest5TrxMsgOsmosisConcentratedLiquidityPoolModelConcentratedV1beta1MsgCreateConcentratedPool - extends IRangeMessage { - type: OsmoTest5TrxMsgTypes.OsmosisConcentratedLiquidityPoolModelConcentratedV1beta1MsgCreateConcentratedPool; - data: { - denom0: string; - denom1: string; - sender: string; - tickSpacing: string; - spreadFactor: string; - }; -} - -// types for mgs type:: /osmosis.concentratedliquidity.v1beta1.MsgCollectIncentives -export interface OsmoTest5TrxMsgOsmosisConcentratedLiquidityV1Beta1MsgCollectIncentives - extends IRangeMessage { - type: OsmoTest5TrxMsgTypes.OsmosisConcentratedLiquidityV1Beta1MsgCollectIncentives; - data: { - sender: string; - positionIds: string[]; - }; -} - -// types for mgs type:: /osmosis.cosmwasmpool.v1beta1.MsgCreateCosmWasmPool -export interface OsmoTest5TrxMsgOsmosisCosmwasmPoolV1Beta1MsgCreateCosmWasmPool - extends IRangeMessage { - type: OsmoTest5TrxMsgTypes.OsmosisCosmwasmPoolV1Beta1MsgCreateCosmWasmPool; - data: { - codeId: string; - sender: string; - instantiateMsg: string; - }; -} - -// types for mgs type:: /osmosis.gamm.v1beta1.MsgJoinPool -export interface OsmoTest5TrxMsgOsmosisGammV1Beta1MsgJoinPool - extends IRangeMessage { - type: OsmoTest5TrxMsgTypes.OsmosisGammV1Beta1MsgJoinPool; - data: { - poolId: string; - sender: string; - tokenInMaxs: { - denom: string; - amount: string; - }[]; - shareOutAmount: string; - }; -} - -// types for msg type:: /osmosis.gamm.v1beta1.MsgSwapExactAmountIn -export interface OsmoTest5TrxMsgOsmosisGammV1beta1MsgSwapExactAmountIn - extends IRangeMessage { - type: OsmoTest5TrxMsgTypes.OsmosisGammV1beta1MsgSwapExactAmountIn; - data: { - routes: Array<{ poolId: string; tokenOutDenom: string }>; - sender: string; - tokenIn: { denom: string; amount: string }; - tokenOutMinAmount: string; - }; -} - -// types for msg type:: /osmosis.poolmanager.v1beta1.MsgSwapExactAmountIn -export interface OsmoTest5TrxMsgOsmosisPoolManagerV1beta1MsgSwapExactAmountIn - extends IRangeMessage { - type: OsmoTest5TrxMsgTypes.OsmosisPoolManagerV1beta1MsgSwapExactAmountIn; - data: { - routes: Array<{ poolId: string; tokenOutDenom: string }>; - sender: string; - tokenIn: { denom: string; amount: string }; - tokenOutMinAmount: string; - }; -} - -// types for msg type:: /osmosis.tokenfactory.v1beta1.MsgCreateDenom -export interface OsmoTest5TrxMsgOsmosisTokenFactoryV1beta1MsgCreateDenom - extends IRangeMessage { - type: OsmoTest5TrxMsgTypes.OsmosisTokenFactoryV1beta1MsgCreateDenom; - data: { - sender: string; - subdenom: string; - }; -} - -// types for mgs type:: /osmosis.tokenfactory.v1beta1.MsgMint -export interface OsmoTest5TrxMsgOsmosisTokenFactoryV1beta1MsgMint - extends IRangeMessage { - type: OsmoTest5TrxMsgTypes.OsmosisTokenFactoryV1beta1MsgMint; - data: { - amount: { - denom: string; - amount: string; - }; - sender: string; - mintToAddress: string; - }; -} - -// types for mgs type:: /osmosis.valsetpref.v1beta1.MsgDelegateToValidatorSet -export interface OsmoTest5TrxMsgOsmosisValsetprefV1beta1MsgDelegateToValidatorSet - extends IRangeMessage { - type: OsmoTest5TrxMsgTypes.OsmosisValsetprefV1beta1MsgDelegateToValidatorSet; - data: { - coin: { - denom: string; - amount: string; - }; - delegator: string; - }; -} - -// types for mgs type:: /osmosis.valsetpref.v1beta1.MsgSetValidatorSetPreference -export interface OsmoTest5TrxMsgOsmosisValsetprefV1beta1MsgSetValidatorSetPreference - extends IRangeMessage { - type: OsmoTest5TrxMsgTypes.OsmosisValsetprefV1beta1MsgSetValidatorSetPreference; - data: { - delegator: string; - preferences: { - weight: string; - valOperAddress: string; - }[]; - }; -} diff --git a/src/types/chain/osmosis-1/IRangeBlockOsmosis1Trx.ts b/src/types/chain/osmosis-1/IRangeBlockOsmosis1Trx.ts deleted file mode 100644 index 3711d54b..00000000 --- a/src/types/chain/osmosis-1/IRangeBlockOsmosis1Trx.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { IRangeTransaction } from '../IRangeTransaction'; -import { Osmosis1TrxMsg } from './IRangeBlockOsmosis1TrxMsg'; - -export interface Osmosis1Trx extends IRangeTransaction { - messages: Osmosis1TrxMsg[]; -} diff --git a/src/types/chain/osmosis-1/IRangeBlockOsmosis1TrxMsg.ts b/src/types/chain/osmosis-1/IRangeBlockOsmosis1TrxMsg.ts deleted file mode 100644 index 7b8d3d79..00000000 --- a/src/types/chain/osmosis-1/IRangeBlockOsmosis1TrxMsg.ts +++ /dev/null @@ -1,1457 +0,0 @@ -import { IRangeMessage } from '../IRangeMessage'; - -export enum Osmosis1TrxMsgTypes { - CosmosAuthzV1beta1MsgExec = 'cosmos.authz.v1beta1.MsgExec', - CosmosAuthzV1beta1MsgGrant = 'cosmos.authz.v1beta1.MsgGrant', - CosmosAuthzV1beta1MsgRevoke = 'cosmos.authz.v1beta1.MsgRevoke', - CosmosBankV1beta1MsgSend = 'cosmos.bank.v1beta1.MsgSend', - CosmosDistributionV1beta1MsgSetWithdrawAddress = 'cosmos.distribution.v1beta1.MsgSetWithdrawAddress', - CosmosDistributionV1beta1MsgWithdrawDelegatorReward = 'cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward', - CosmosDistributionV1beta1MsgWithdrawValidatorCommission = 'cosmos.distribution.v1beta1.MsgWithdrawValidatorCommission', - CosmosGovV1beta1MsgDeposit = 'cosmos.gov.v1beta1.MsgDeposit', - CosmosGovV1beta1MsgSubmitProposal = 'cosmos.gov.v1beta1.MsgSubmitProposal', - CosmosGovV1beta1MsgVote = 'cosmos.gov.v1beta1.MsgVote', - CosmosSlashingV1beta1MsgUnjail = 'cosmos.slashing.v1beta1.MsgUnjail', - CosmosStakingV1beta1MsgBeginRedelegate = 'cosmos.staking.v1beta1.MsgBeginRedelegate', - CosmosStakingV1beta1MsgDelegate = 'cosmos.staking.v1beta1.MsgDelegate', - CosmosStakingV1beta1MsgEditValidator = 'cosmos.staking.v1beta1.MsgEditValidator', - CosmosStakingV1beta1MsgUndelegate = 'cosmos.staking.v1beta1.MsgUndelegate', - CosmosVestingV1beta1MsgCreateVestingAccount = 'cosmos.vesting.v1beta1.MsgCreateVestingAccount', - CosmwasmWasmV1MsgExecuteContract = 'cosmwasm.wasm.v1.MsgExecuteContract', - CosmwasmWasmV1MsgInstantiateContract = 'cosmwasm.wasm.v1.MsgInstantiateContract', - CosmwasmWasmV1MsgMigrateContract = 'cosmwasm.wasm.v1.MsgMigrateContract', - CosmwasmWasmV1MsgStoreCode = 'cosmwasm.wasm.v1.MsgStoreCode', - IbcApplicationsTransferV1MsgTransfer = 'ibc.applications.transfer.v1.MsgTransfer', - IbcCoreChannelV1MsgAcknowledgement = 'ibc.core.channel.v1.MsgAcknowledgement', - IbcCoreChannelV1MsgChannelCloseConfirm = 'ibc.core.channel.v1.MsgChannelCloseConfirm', - IbcCoreChannelV1MsgChannelOpenConfirm = 'ibc.core.channel.v1.MsgChannelOpenConfirm', - IbcCoreChannelV1MsgChannelOpenTry = 'ibc.core.channel.v1.MsgChannelOpenTry', - IbcCoreChannelV1MsgRecvPacket = 'ibc.core.channel.v1.MsgRecvPacket', - IbcCoreChannelV1MsgTimeout = 'ibc.core.channel.v1.MsgTimeout', - IbcCoreClientV1MsgCreateClient = 'ibc.core.client.v1.MsgCreateClient', - IbcCoreClientV1MsgUpdateClient = 'ibc.core.client.v1.MsgUpdateClient', - IbcCoreConnectionV1MsgConnectionOpenConfirm = 'ibc.core.connection.v1.MsgConnectionOpenConfirm', - OsmosisConcentratedLiquidityPoolModelConcentratedV1beta1MsgCreateConcentratedPool = 'osmosis.concentratedliquidity.poolmodel.concentrated.v1beta1.MsgCreateConcentratedPool', - OsmosisConcentratedLiquidityV1beta1MsgAddToPosition = 'osmosis.concentratedliquidity.v1beta1.MsgAddToPosition', - OsmosisConcentratedLiquidityV1beta1MsgCollectIncentives = 'osmosis.concentratedliquidity.v1beta1.MsgCollectIncentives', - OsmosisConcentratedLiquidityV1beta1MsgCollectSpreadRewards = 'osmosis.concentratedliquidity.v1beta1.MsgCollectSpreadRewards', - OsmosisConcentratedLiquidityV1beta1MsgCreatePosition = 'osmosis.concentratedliquidity.v1beta1.MsgCreatePosition', - OsmosisConcentratedLiquidityV1beta1MsgFungifyChargedPositions = 'osmosis.concentratedliquidity.v1beta1.MsgFungifyChargedPositions', - OsmosisConcentratedLiquidityV1beta1MsgWithdrawPosition = 'osmosis.concentratedliquidity.v1beta1.MsgWithdrawPosition', - OsmosisCosmwasmPoolV1beta1MsgCreateCosmWasmPool = 'osmosis.cosmwasmpool.v1beta1.MsgCreateCosmWasmPool', - OsmosisGammPoolmodelsBalancerV1beta1MsgCreateBalancerPool = 'osmosis.gamm.poolmodels.balancer.v1beta1.MsgCreateBalancerPool', - OsmosisGammPoolmodelsStableswapV1beta1MsgCreateStableswapPool = 'osmosis.gamm.poolmodels.stableswap.v1beta1.MsgCreateStableswapPool', - OsmosisGammPoolModelsStableSwapV1beta1MsgStableSwapAdjustScalingFactors = 'osmosis.gamm.poolmodels.stableswap.v1beta1.MsgStableSwapAdjustScalingFactors', - OsmosisGammV1beta1MsgExitPool = 'osmosis.gamm.v1beta1.MsgExitPool', - OsmosisGammV1beta1MsgJoinPool = 'osmosis.gamm.v1beta1.MsgJoinPool', - OsmosisGammV1beta1MsgJoinSwapExternAmountIn = 'osmosis.gamm.v1beta1.MsgJoinSwapExternAmountIn', - OsmosisGammV1beta1MsgSwapExactAmountIn = 'osmosis.gamm.v1beta1.MsgSwapExactAmountIn', - OsmosisGammV1beta1MsgSwapExactAmountOut = 'osmosis.gamm.v1beta1.MsgSwapExactAmountOut', - OsmosisIncentivesMsgAddToGauge = 'osmosis.incentives.MsgAddToGauge', - OsmosisIncentivesMsgCreateGauge = 'osmosis.incentives.MsgCreateGauge', - OsmosisLockupMsgBeginUnlocking = 'osmosis.lockup.MsgBeginUnlocking', - OsmosisLockupMsgLockTokens = 'osmosis.lockup.MsgLockTokens', - OsmosisPoolmanagerV1beta1MsgSwapExactAmountIn = 'osmosis.poolmanager.v1beta1.MsgSwapExactAmountIn', - OsmosisPoolmanagerV1beta1MsgSplitRouteSwapExactAmountIn = 'osmosis.poolmanager.v1beta1.MsgSplitRouteSwapExactAmountIn', - OsmosisPoolManagerV1beta1MsgSwapExactAmountOut = 'osmosis.poolmanager.v1beta1.MsgSwapExactAmountOut', - OsmosisSuperfluidMsgAddToConcentratedLiquiditySuperfluidPosition = 'osmosis.superfluid.MsgAddToConcentratedLiquiditySuperfluidPosition', - OsmosisSuperfluidMsgCreateFullRangePositionAndSuperfluidDelegate = 'osmosis.superfluid.MsgCreateFullRangePositionAndSuperfluidDelegate', - OsmosisSuperfluidMsgLockAndSuperfluidDelegate = 'osmosis.superfluid.MsgLockAndSuperfluidDelegate', - OsmosisSuperfluidMsgSuperfluidDelegate = 'osmosis.superfluid.MsgSuperfluidDelegate', - OsmosisSuperfluidMsgSuperfluidUnbondLock = 'osmosis.superfluid.MsgSuperfluidUnbondLock', - OsmosisSuperfluidMsgSuperfluidUndelegate = 'osmosis.superfluid.MsgSuperfluidUndelegate', - OsmosisSuperfluidMsgUnbondConvertAndStake = 'osmosis.superfluid.MsgUnbondConvertAndStake', - OsmosisSuperfluidMsgUnlockAndMigrateSharesToFullRangeConcentratedPosition = 'osmosis.superfluid.MsgUnlockAndMigrateSharesToFullRangeConcentratedPosition', - OsmosisTokenFactoryV1beta1MsgCreateDenom = 'osmosis.tokenfactory.v1beta1.MsgCreateDenom', - OsmosisTokenfactoryV1beta1MsgMint = 'osmosis.tokenfactory.v1beta1.MsgMint', - OsmosisValsetprefV1beta1MsgWithdrawDelegationRewards = 'osmosis.valsetpref.v1beta1.MsgWithdrawDelegationRewards', - CosmosStakingV1beta1MsgCreateValidator = 'cosmos.staking.v1beta1.MsgCreateValidator', - CosmosDistributionV1beta1MsgFundCommunityPool = 'cosmos.distribution.v1beta1.MsgFundCommunityPool', - IbcCoreChannelV1MsgChannelCloseInit = 'ibc.core.channel.v1.MsgChannelCloseInit', - CosmwasmWasmV1MsgUpdateAdmin = 'cosmwasm.wasm.v1.MsgUpdateAdmin', - CosmosAuthV1beta1MsgUpdateParams = 'cosmos.auth.v1beta1.MsgUpdateParams', - CosmosCrisisV1beta1MsgUpdateParams = 'cosmos.crisis.v1beta1.MsgUpdateParams', - CosmosDistributionV1beta1MsgCommunityPoolSpend = 'cosmos.distribution.v1beta1.MsgCommunityPoolSpend', - CosmosEvidenceV1beta1MsgSubmitEvidence = 'cosmos.evidence.v1beta1.MsgSubmitEvidence', - CosmosSlashingV1beta1MsgUpdateParams = 'cosmos.slashing.v1beta1.MsgUpdateParams', - CosmosStakingV1beta1MsgUpdateParams = 'cosmos.staking.v1beta1.MsgUpdateParams', - CosmosUpgradeV1beta1MsgCancelUpgrade = 'cosmos.upgrade.v1beta1.MsgCancelUpgrade', - CosmosUpgradeV1beta1MsgSoftwareUpgrade = 'cosmos.upgrade.v1beta1.MsgSoftwareUpgrade', - CosmwasmWasmV1MsgClearAdmin = 'cosmwasm.wasm.v1.MsgClearAdmin', - CosmosBankV1beta1MsgUpdateParams = 'cosmos.bank.v1beta1.MsgUpdateParams', - OsmosisTokenFactoryV1betaBurn = 'osmosis.tokenfactory.v1beta1.MsgBurn', - OsmosisTokenfactoryV1beta1MsgChangeAdmin = 'osmosis.tokenfactory.v1beta1.MsgChangeAdmin', - OsmosisTokenfactoryV1beta1MsgSetDenomMetadata = 'osmosis.tokenfactory.v1beta1.MsgSetDenomMetadata', -} - -export type Osmosis1TrxMsg = - | Osmosis1TrxMsgCosmosAuthzV1beta1MsgExec - | Osmosis1TrxMsgCosmosAuthzV1beta1MsgGrant - | Osmosis1TrxMsgCosmosAuthzV1beta1MsgRevoke - | Osmosis1TrxMsgCosmosBankV1beta1MsgSend - | Osmosis1TrxMsgCosmosDistributionV1beta1MsgSetWithdrawAddress - | Osmosis1TrxMsgCosmosDistributionV1beta1MsgWithdrawDelegatorReward - | Osmosis1TrxMsgCosmosDistributionV1beta1MsgWithdrawValidatorCommission - | Osmosis1TrxMsgCosmosGovV1beta1MsgDeposit - | Osmosis1TrxMsgCosmosGovV1beta1MsgSubmitProposal - | Osmosis1TrxMsgCosmosGovV1beta1MsgVote - | Osmosis1TrxMsgCosmosSlashingV1beta1MsgUnjail - | Osmosis1TrxMsgCosmosStakingV1beta1MsgBeginRedelegate - | Osmosis1TrxMsgCosmosStakingV1beta1MsgDelegate - | Osmosis1TrxMsgCosmosStakingV1beta1MsgEditValidator - | Osmosis1TrxMsgCosmosStakingV1beta1MsgUndelegate - | Osmosis1TrxMsgCosmosVestingV1beta1MsgCreateVestingAccount - | Osmosis1TrxMsgCosmwasmWasmV1MsgExecuteContract - | Osmosis1TrxMsgCosmwasmWasmV1MsgInstantiateContract - | Osmosis1TrxMsgCosmwasmWasmV1MsgMigrateContract - | Osmosis1TrxMsgCosmwasmWasmV1MsgStoreCode - | Osmosis1TrxMsgIbcApplicationsTransferV1MsgTransfer - | Osmosis1TrxMsgIbcCoreChannelV1MsgAcknowledgement - | Osmosis1TrxMsgIbcCoreChannelV1MsgChannelCloseConfirm - | Osmosis1TrxMsgIbcCoreChannelV1MsgChannelOpenConfirm - | Osmosis1TrxMsgIbcCoreChannelV1MsgChannelOpenTry - | Osmosis1TrxMsgIbcCoreChannelV1MsgRecvPacket - | Osmosis1TrxMsgIbcCoreChannelV1MsgTimeout - | Osmosis1TrxMsgIbcCoreClientV1MsgCreateClient - | Osmosis1TrxMsgIbcCoreClientV1MsgUpdateClient - | Osmosis1TrxMsgIbcCoreConnectionV1MsgConnectionOpenConfirm - | Osmosis1TrxMsgOsmosisConcentratedliquidityPoolModelConcentratedV1beta1MsgCreateConcentratedPool - | Osmosis1TrxMsgOsmosisConcentratedliquidityV1beta1MsgAddToPosition - | Osmosis1TrxMsgOsmosisConcentratedliquidityV1beta1MsgCollectIncentives - | Osmosis1TrxMsgOsmosisConcentratedliquidityV1beta1MsgCollectSpreadRewards - | Osmosis1TrxMsgOsmosisConcentratedliquidityV1beta1MsgCreatePosition - | Osmosis1TrxMsgOsmosisConcentratedliquidityV1beta1MsgFungifyChargedPositions - | Osmosis1TrxMsgOsmosisConcentratedliquidityV1beta1MsgWithdrawPosition - | Osmosis1TrxMsgOsmosisCosmwasmPoolV1beta1MsgCreateCosmWasmPool - | Osmosis1TrxMsgOsmosisGammPoolmodelsBalancerV1beta1MsgCreateBalancerPool - | Osmosis1TrxMsgOsmosisGammPoolmodelsStableswapV1beta1MsgCreateStableswapPool - | Osmosis1TrxMsgOsmosisGammPoolModelsStableSwapV1beta1MsgStableSwapAdjustScalingFactors - | Osmosis1TrxMsgOsmosisGammV1beta1MsgExitPool - | Osmosis1TrxMsgOsmosisGammV1beta1MsgJoinPool - | Osmosis1TrxMsgOsmosisGammV1beta1MsgJoinSwapExternAmountIn - | Osmosis1TrxMsgOsmosisGammV1beta1MsgSwapExactAmountIn - | Osmosis1TrxMsgOsmosisGammV1beta1MsgSwapExactAmountOut - | Osmosis1TrxMsgOsmosisIncentivesMsgAddToGauge - | Osmosis1TrxMsgOsmosisIncentivesMsgCreateGauge - | Osmosis1TrxMsgOsmosisLockupMsgBeginUnlocking - | Osmosis1TrxMsgOsmosisLockupMsgLockTokens - | Osmosis1TrxMsgOsmosisPoolmanagerV1beta1MsgSwapExactAmountIn - | Osmosis1TrxMsgOsmosisPoolmanagerV1beta1MsgSplitRouteSwapExactAmountIn - | Osmosis1TrxMsgOsmosisPoolManagerV1beta1MsgSwapExactAmountOut - | Osmosis1TrxMsgOsmosisSuperfluidMsgAddToConcentratedLiquiditySuperfluidPosition - | Osmosis1TrxMsgOsmosisSuperfluidMsgCreateFullRangePositionAndSuperfluidDelegate - | Osmosis1TrxMsgOsmosisSuperfluidMsgLockAndSuperfluidDelegate - | Osmosis1TrxMsgOsmosisSuperfluidMsgSuperfluidDelegate - | Osmosis1TrxMsgOsmosisSuperfluidMsgSuperfluidUnbondLock - | Osmosis1TrxMsgOsmosisSuperfluidMsgSuperfluidUndelegate - | Osmosis1TrxMsgOsmosisSuperfluidMsgUnbondConvertAndStake - | Osmosis1TrxMsgOsmosisSuperfluidMsgUnlockAndMigrateSharesToFullRangeConcentratedPosition - | Osmosis1TrxMsgOsmosisTokenFactoryV1beta1MsgCreateDenom - | Osmosis1TrxMsgOsmosisTokenfactoryV1beta1MsgMint - | Osmosis1TrxMsgOsmosisValsetprefV1beta1MsgWithdrawDelegationRewards - | Osmosis1TrxMsgCosmosStakingV1beta1MsgCreateValidator - | Osmosis1TrxMsgCosmosDistributionV1beta1MsgFundCommunityPool - | Osmosis1TrxMsgIbcCoreChannelV1MsgChannelCloseInit - | Osmosis1TrxMsgCosmwasmWasmV1MsgUpdateAdmin - | Osmosis1TrxMsgCosmosAuthV1beta1MsgUpdateParams - | Osmosis1TrxMsgCosmosCrisisV1beta1MsgUpdateParams - | Osmosis1TrxMsgCosmosDistributionV1beta1MsgCommunityPoolSpend - | Osmosis1TrxMsgCosmosEvidenceV1beta1MsgSubmitEvidence - | Osmosis1TrxMsgCosmosSlashingV1beta1MsgUpdateParams - | Osmosis1TrxMsgCosmosStakingV1beta1MsgUpdateParams - | Osmosis1TrxMsgCosmosUpgradeV1beta1MsgCancelUpgrade - | Osmosis1TrxMsgCosmosUpgradeV1beta1MsgSoftwareUpgrade - | Osmosis1TrxMsgCosmwasmWasmV1MsgClearAdmin - | Osmosis1TrxMsgCosmosBankV1beta1MsgUpdateParams - | Osmosis1TrxMsgOsmosisTokenFactoryV1betaBurn - | Osmosis1TrxMsgOsmosisTokenfactoryV1beta1MsgChangeAdmin - | Osmosis1TrxMsgOsmosisTokenfactoryV1beta1MsgSetDenomMetadata; - -// types for mgs type:: /cosmos.authz.v1beta1.MsgExec -export interface Osmosis1TrxMsgCosmosAuthzV1beta1MsgExec extends IRangeMessage { - type: Osmosis1TrxMsgTypes.CosmosAuthzV1beta1MsgExec; - data: { - grantee: string; - msgs: unknown[]; - }; -} - -// types for mgs type:: /cosmos.authz.v1beta1.MsgGrant -export interface Osmosis1TrxMsgCosmosAuthzV1beta1MsgGrant - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.CosmosAuthzV1beta1MsgGrant; - data: { - granter: string; - grantee: string; - grant: - | Osmosis1TrxMsgCosmosAuthzV1beta1MsgGrantDataGrantGenericAuthorization - | Osmosis1TrxMsgCosmosAuthzV1beta1MsgGrantDataGrantSendAuthorization - | Osmosis1TrxMsgCosmosAuthzV1beta1MsgGrantDataGrantStakeAuthorization; - }; -} - -interface Osmosis1TrxMsgCosmosAuthzV1beta1MsgGrantDataGrantGenericAuthorization { - authorization: { - '@type': '/cosmos.authz.v1beta1.GenericAuthorization'; - msg: string; - }; - expiration: string; -} - -interface Osmosis1TrxMsgCosmosAuthzV1beta1MsgGrantDataGrantSendAuthorization { - authorization: { - '@type': '/cosmos.bank.v1beta1.SendAuthorization'; - spendLimit: { - denom: string; - amount: string; - }[]; - expiration: string; - }; -} - -interface Osmosis1TrxMsgCosmosAuthzV1beta1MsgGrantDataGrantStakeAuthorization { - authorization: { - '@type': '/cosmos.staking.v1beta1.StakeAuthorization'; - allowList: { - address: string[]; - }; - authorizationType: string; - maxTokens?: { - denom: string; - amount: string; - }; - }; - expiration?: string; -} - -// types for mgs type:: /cosmos.authz.v1beta1.MsgRevoke -export interface Osmosis1TrxMsgCosmosAuthzV1beta1MsgRevoke - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.CosmosAuthzV1beta1MsgRevoke; - data: { - grantee: string; - granter: string; - msgTypeUrl: string; - }; -} - -// types for mgs type:: /cosmos.bank.v1beta1.MsgSend -export interface Osmosis1TrxMsgCosmosBankV1beta1MsgSend extends IRangeMessage { - type: Osmosis1TrxMsgTypes.CosmosBankV1beta1MsgSend; - data: { - amount: { - denom: string; - amount: string; - }[]; - toAddress: string; - fromAddress: string; - }; -} - -// types for mgs type:: /cosmos.distribution.v1beta1.MsgSetWithdrawAddress -export interface Osmosis1TrxMsgCosmosDistributionV1beta1MsgSetWithdrawAddress - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.CosmosDistributionV1beta1MsgSetWithdrawAddress; - data: { - withdrawAddress: string; - delegatorAddress: string; - }; -} - -// types for mgs type:: /cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward -export interface Osmosis1TrxMsgCosmosDistributionV1beta1MsgWithdrawDelegatorReward - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.CosmosDistributionV1beta1MsgWithdrawDelegatorReward; - data: { - delegatorAddress: string; - validatorAddress: string; - }; -} - -// types for mgs type:: /cosmos.distribution.v1beta1.MsgWithdrawValidatorCommission -export interface Osmosis1TrxMsgCosmosDistributionV1beta1MsgWithdrawValidatorCommission - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.CosmosDistributionV1beta1MsgWithdrawValidatorCommission; - data: { - validatorAddress: string; - }; -} - -// types for mgs type:: /cosmos.gov.v1beta1.MsgDeposit -export interface Osmosis1TrxMsgCosmosGovV1beta1MsgDeposit - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.CosmosGovV1beta1MsgDeposit; - data: { - amount: { - denom: string; - amount: string; - }[]; - depositor: string; - proposalId: string; - }; -} - -// types for mgs type:: /cosmos.gov.v1beta1.MsgSubmitProposal -export interface Osmosis1TrxMsgCosmosGovV1beta1MsgSubmitProposal - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.CosmosGovV1beta1MsgSubmitProposal; - data: { - content: Osmosis1TrxMsgCosmosGovV1beta1MsgSubmitProposalDataContentTypeClientUpdateProposal; - initialDeposit: { - denom: string; - amount: string; - }[]; - proposer: string; - }; -} - -interface Osmosis1TrxMsgCosmosGovV1beta1MsgSubmitProposalDataContentTypeClientUpdateProposal { - '@type': '/ibc.core.client.v1.ClientUpdateProposal'; - title: string; - description: string; - subjectClientId: string; - substituteClientId: string; -} - -// types for mgs type:: /cosmos.gov.v1beta1.MsgVote -export interface Osmosis1TrxMsgCosmosGovV1beta1MsgVote extends IRangeMessage { - type: Osmosis1TrxMsgTypes.CosmosGovV1beta1MsgVote; - data: { - voter: string; - option: string; - proposalId?: string; - }; -} - -// types for mgs type:: /cosmos.slashing.v1beta1.MsgUnjail -export interface Osmosis1TrxMsgCosmosSlashingV1beta1MsgUnjail - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.CosmosSlashingV1beta1MsgUnjail; - data: { - validatorAddr: string; - }; -} - -// types for mgs type:: /cosmos.staking.v1beta1.MsgBeginRedelegate -export interface Osmosis1TrxMsgCosmosStakingV1beta1MsgBeginRedelegate - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.CosmosStakingV1beta1MsgBeginRedelegate; - data: { - amount: { - denom: string; - amount: string; - }; - delegatorAddress: string; - validatorDstAddress: string; - validatorSrcAddress: string; - }; -} - -// types for mgs type:: /cosmos.staking.v1beta1.MsgDelegate -export interface Osmosis1TrxMsgCosmosStakingV1beta1MsgDelegate - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.CosmosStakingV1beta1MsgDelegate; - data: { - amount: { - denom: string; - amount: string; - }; - delegatorAddress: string; - validatorAddress: string; - }; -} - -// types for mgs type:: /cosmos.staking.v1beta1.MsgEditValidator -export interface Osmosis1TrxMsgCosmosStakingV1beta1MsgEditValidator - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.CosmosStakingV1beta1MsgEditValidator; - data: { - description: { - moniker?: string; - identity?: string; - website?: string; - securityContact?: string; - details?: string; - }; - validatorAddress: string; - commissionRate?: string; - }; -} - -// types for mgs type:: /cosmos.staking.v1beta1.MsgUndelegate -export interface Osmosis1TrxMsgCosmosStakingV1beta1MsgUndelegate - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.CosmosStakingV1beta1MsgUndelegate; - data: { - amount: { - denom: string; - amount: string; - }; - delegatorAddress: string; - validatorAddress: string; - }; -} - -// types for mgs type:: /cosmos.vesting.v1beta1.MsgCreateVestingAccount -export interface Osmosis1TrxMsgCosmosVestingV1beta1MsgCreateVestingAccount - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.CosmosVestingV1beta1MsgCreateVestingAccount; - data: { - amount: { - denom: string; - amount: string; - }[]; - delayed: boolean; - endTime: string; - toAddress: string; - fromAddress: string; - }; -} - -// types for mgs type:: /cosmwasm.wasm.v1.MsgExecuteContract -export interface Osmosis1TrxMsgCosmwasmWasmV1MsgExecuteContract - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.CosmwasmWasmV1MsgExecuteContract; - data: { - sender: string; - contract: string; - msg: unknown; - funds?: { - denom: string; - amount: string; - }[]; - }; -} - -// types for mgs type:: /cosmwasm.wasm.v1.MsgInstantiateContract -export interface Osmosis1TrxMsgCosmwasmWasmV1MsgInstantiateContract - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.CosmwasmWasmV1MsgInstantiateContract; - data: { - admin?: string; - sender: string; - codeId: string; - label: string; - msg: Record; - }; -} - -// types for mgs type:: /cosmwasm.wasm.v1.MsgMigrateContract -export interface Osmosis1TrxMsgCosmwasmWasmV1MsgMigrateContract - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.CosmwasmWasmV1MsgMigrateContract; - data: { - msg: string; - codeId: string; - sender: string; - contract: string; - }; -} - -// types for mgs type:: /cosmwasm.wasm.v1.MsgStoreCode -export interface Osmosis1TrxMsgCosmwasmWasmV1MsgStoreCode - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.CosmwasmWasmV1MsgStoreCode; - data: { - sender: string; - wasmByteCode: string; - instantiatePermission?: { - permission: string; - addresses: string[]; - }; - }; -} - -// types for mgs type:: /ibc.applications.transfer.v1.MsgTransfer -export interface Osmosis1TrxMsgIbcApplicationsTransferV1MsgTransfer - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.IbcApplicationsTransferV1MsgTransfer; - data: { - sourcePort: string; - sourceChannel: string; - token: { - denom: string; - amount: string; - }; - sender: string; - receiver: string; - timeoutHeight?: { - revisionNumber?: string; - revisionHeight?: string; - }; - timeoutTimestamp?: string; - memo?: string; - }; -} - -// types for mgs type:: /ibc.core.channel.v1.MsgAcknowledgement -export interface Osmosis1TrxMsgIbcCoreChannelV1MsgAcknowledgement - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.IbcCoreChannelV1MsgAcknowledgement; - data: { - packet: { - sequence: string; - sourcePort: string; - sourceChannel: string; - destinationPort: string; - destinationChannel: string; - data: string; - timeoutHeight?: { - revisionNumber?: string; - revisionHeight?: string; - }; - timeoutTimestamp?: string; - }; - acknowledgement?: string; - proofAcked: string; - proofHeight?: { - revisionNumber?: string; - revisionHeight?: string; - }; - signer?: string; - }; -} - -// types for mgs type:: /ibc.core.channel.v1.MsgChannelCloseConfirm -export interface Osmosis1TrxMsgIbcCoreChannelV1MsgChannelCloseConfirm - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.IbcCoreChannelV1MsgChannelCloseConfirm; - data: { - portId: string; - channelId: string; - proofInit: string; - proofHeight: { - revisionHeight: string; - revisionNumber?: string; - }; - signer: string; - }; -} - -// types for mgs type:: /ibc.core.channel.v1.MsgChannelOpenConfirm -export interface Osmosis1TrxMsgIbcCoreChannelV1MsgChannelOpenConfirm - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.IbcCoreChannelV1MsgChannelOpenConfirm; - data: { - portId: string; - channelId: string; - proofAck: string; - proofHeight: { - revisionHeight: string; - revisionNumber?: string; - }; - signer: string; - }; -} - -// types for mgs type:: /ibc.core.channel.v1.MsgChannelOpenTry -export interface Osmosis1TrxMsgIbcCoreChannelV1MsgChannelOpenTry - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.IbcCoreChannelV1MsgChannelOpenTry; - data: { - portId: string; - channel: { - state: string; - ordering: string; - counterparty: { - portId: string; - channelId: string; - }; - connectionHops: string[]; - version: string; - }; - counterpartyVersion: string; - proofInit: string; - proofHeight: { - revisionHeight: string; - revisionNumber?: string; - }; - signer: string; - }; -} - -// types for mgs type:: /ibc.core.channel.v1.MsgRecvPacket -export interface Osmosis1TrxMsgIbcCoreChannelV1MsgRecvPacket - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.IbcCoreChannelV1MsgRecvPacket; - data: { - packet: { - sequence: string; - sourcePort: string; - sourceChannel: string; - destinationPort: string; - destinationChannel: string; - data: string; - timeoutTimestamp?: string; - timeoutHeight?: { - revisionNumber?: string; - revisionHeight?: string; - }; - }; - proofCommitment: string; - proofHeight: { - revisionNumber?: string; - revisionHeight: string; - }; - signer: string; - }; -} - -// types for mgs type:: /ibc.core.channel.v1.MsgTimeout -export interface Osmosis1TrxMsgIbcCoreChannelV1MsgTimeout - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.IbcCoreChannelV1MsgTimeout; - data: { - packet: { - sequence: string; - sourcePort: string; - sourceChannel: string; - destinationPort: string; - destinationChannel: string; - data: string; - timeoutHeight?: { - revisionNumber?: string; - revisionHeight?: string; - }; - timeoutTimestamp?: string; - }; - proofUnreceived: string; - proofHeight?: { - revisionNumber?: string; - revisionHeight?: string; - }; - nextSequenceRecv: string; - signer: string; - }; -} - -// types for mgs type:: /ibc.core.client.v1.MsgCreateClient -export interface Osmosis1TrxMsgIbcCoreClientV1MsgCreateClient - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.IbcCoreClientV1MsgCreateClient; - data: { - clientState: { - '@type': string; - chainId: string; - trustLevel: { - numerator: string; - denominator: string; - }; - trustingPeriod: string; - unbondingPeriod: string; - maxClockDrift: string; - frozenHeight: { - revisionNumber?: string; - revisionHeight?: string; - }; - latestHeight: { - revisionNumber?: string; - revisionHeight: string; - }; - proofSpecs: { - leafSpec: { - hash: string; - prehashValue: string; - length: string; - prefix: string; - }; - innerSpec: { - childOrder: number[]; - childSize: number; - minPrefixLength: number; - maxPrefixLength: number; - hash: string; - }; - }[]; - upgradePath: string[]; - allowUpdateAfterExpiry: boolean; - allowUpdateAfterMisbehaviour: boolean; - }; - consensusState: { - '@type': string; - timestamp: string; - root: { - hash: string; - }; - nextValidatorsHash: string; - }; - signer: string; - }; -} - -// types for mgs type:: /ibc.core.client.v1.MsgUpdateClient -export interface Osmosis1TrxMsgIbcCoreClientV1MsgUpdateClient - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.IbcCoreClientV1MsgUpdateClient; - data: { - clientId: string; - clientMessage: unknown; - signer: string; - }; -} - -// types for mgs type:: /ibc.core.connection.v1.MsgConnectionOpenConfirm -export interface Osmosis1TrxMsgIbcCoreConnectionV1MsgConnectionOpenConfirm - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.IbcCoreConnectionV1MsgConnectionOpenConfirm; - data: { - connectionId: string; - proofAck: string; - proofHeight: { - revisionNumber?: string; - revisionHeight: string; - }; - signer: string; - }; -} - -// types for mgs type:: /osmosis.concentratedliquidity.poolmodel.concentrated.v1beta1.MsgCreateConcentratedPool -export interface Osmosis1TrxMsgOsmosisConcentratedliquidityPoolModelConcentratedV1beta1MsgCreateConcentratedPool - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.OsmosisConcentratedLiquidityPoolModelConcentratedV1beta1MsgCreateConcentratedPool; - data: { - denom0: string; - denom1: string; - sender: string; - tickSpacing: string; - spreadFactor: string; - }; -} - -// types for mgs type:: /osmosis.concentratedliquidity.v1beta1.MsgAddToPosition -export interface Osmosis1TrxMsgOsmosisConcentratedliquidityV1beta1MsgAddToPosition - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.OsmosisConcentratedLiquidityV1beta1MsgAddToPosition; - data: { - sender: string; - amount0: string; - amount1: string; - positionId: string; - tokenMinAmount0: string; - tokenMinAmount1: string; - }; -} - -// types for mgs type:: /osmosis.concentratedliquidity.v1beta1.MsgCollectIncentives -export interface Osmosis1TrxMsgOsmosisConcentratedliquidityV1beta1MsgCollectIncentives - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.OsmosisConcentratedLiquidityV1beta1MsgCollectIncentives; - data: { - sender: string; - positionIds: string[]; - }; -} - -// types for mgs type:: /osmosis.concentratedliquidity.v1beta1.MsgCollectSpreadRewards -export interface Osmosis1TrxMsgOsmosisConcentratedliquidityV1beta1MsgCollectSpreadRewards - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.OsmosisConcentratedLiquidityV1beta1MsgCollectSpreadRewards; - data: { - sender: string; - positionIds: string[]; - }; -} - -// types for mgs type:: /osmosis.concentratedliquidity.v1beta1.MsgCreatePosition -export interface Osmosis1TrxMsgOsmosisConcentratedliquidityV1beta1MsgCreatePosition - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.OsmosisConcentratedLiquidityV1beta1MsgCreatePosition; - data: { - poolId: string; - sender: string; - lowerTick?: string; - upperTick?: string; - tokensProvided: { - denom: string; - amount: string; - }[]; - tokenMinAmount0: string; - tokenMinAmount1: string; - }; -} - -// types for mgs type:: /osmosis.concentratedliquidity.v1beta1.MsgFungifyChargedPositions -export interface Osmosis1TrxMsgOsmosisConcentratedliquidityV1beta1MsgFungifyChargedPositions - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.OsmosisConcentratedLiquidityV1beta1MsgFungifyChargedPositions; - data: { - sender: string; - positionIds: string[]; - }; - status: string; - block_number: string; - addresses: any[]; - contract_addresses?: any; -} - -// types for mgs type:: /osmosis.concentratedliquidity.v1beta1.MsgWithdrawPosition -export interface Osmosis1TrxMsgOsmosisConcentratedliquidityV1beta1MsgWithdrawPosition - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.OsmosisConcentratedLiquidityV1beta1MsgWithdrawPosition; - data: { - sender: string; - positionId: string; - liquidityAmount: string; - }; -} - -// types for mgs type:: /osmosis.cosmwasmpool.v1beta1.MsgCreateCosmWasmPool -export interface Osmosis1TrxMsgOsmosisCosmwasmPoolV1beta1MsgCreateCosmWasmPool - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.OsmosisCosmwasmPoolV1beta1MsgCreateCosmWasmPool; - data: { - codeId: string; - sender: string; - instantiateMsg: string; - }; -} - -// types for mgs type:: /osmosis.gamm.poolmodels.balancer.v1beta1.MsgCreateBalancerPool -export interface Osmosis1TrxMsgOsmosisGammPoolmodelsBalancerV1beta1MsgCreateBalancerPool - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.OsmosisGammPoolmodelsBalancerV1beta1MsgCreateBalancerPool; - data: { - sender: string; - poolParams: { - swapFee: string; - exitFee: string; - }; - poolAssets: { - token: { - denom: string; - amount: string; - }; - weight: string; - }[]; - futurePoolGovernor?: string; - }; -} - -// types for mgs type:: /osmosis.gamm.poolmodels.stableswap.v1beta1.MsgCreateStableswapPool -export interface Osmosis1TrxMsgOsmosisGammPoolmodelsStableswapV1beta1MsgCreateStableswapPool - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.OsmosisGammPoolmodelsStableswapV1beta1MsgCreateStableswapPool; - data: { - sender: string; - poolParams: { - exitFee: string; - swapFee: string; - }; - scalingFactors: string[]; - futurePoolGovernor: string; - scalingFactorController?: string; - initialPoolLiquidity: { - denom: string; - amount: string; - }[]; - }; -} - -// types for mgs type:: /osmosis.gamm.poolmodels.stableswap.v1beta1.MsgStableSwapAdjustScalingFactors -export interface Osmosis1TrxMsgOsmosisGammPoolModelsStableSwapV1beta1MsgStableSwapAdjustScalingFactors - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.OsmosisGammPoolModelsStableSwapV1beta1MsgStableSwapAdjustScalingFactors; - data: { - poolId: string; - sender: string; - scalingFactors: string[]; - }; -} - -// types for mgs type:: /osmosis.gamm.v1beta1.MsgExitPool -export interface Osmosis1TrxMsgOsmosisGammV1beta1MsgExitPool - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.OsmosisGammV1beta1MsgExitPool; - data: { - sender: string; - poolId: string; - tokenOutMins?: { - denom: string; - amount: string; - }[]; - shareInAmount: string; - }; -} - -// types for mgs type:: /osmosis.gamm.v1beta1.MsgJoinPool -export interface Osmosis1TrxMsgOsmosisGammV1beta1MsgJoinPool - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.OsmosisGammV1beta1MsgJoinPool; - data: { - poolId?: string; - sender: string; - shareOutAmount: string; - tokenInMaxs?: { - denom: string; - amount: string; - }[]; - }; -} - -// types for mgs type:: /osmosis.gamm.v1beta1.MsgJoinSwapExternAmountIn -export interface Osmosis1TrxMsgOsmosisGammV1beta1MsgJoinSwapExternAmountIn - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.OsmosisGammV1beta1MsgJoinSwapExternAmountIn; - data: { - poolId: string; - sender: string; - tokenIn: { - denom: string; - amount: string; - }; - shareOutMinAmount: string; - }; -} - -// types for mgs type:: /osmosis.gamm.v1beta1.MsgSwapExactAmountIn -export interface Osmosis1TrxMsgOsmosisGammV1beta1MsgSwapExactAmountIn - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.OsmosisGammV1beta1MsgSwapExactAmountIn; - data: { - sender: string; - routes: { - tokenOutDenom: string; - poolId?: string; - }[]; - tokenIn: { - denom: string; - amount: string; - }; - tokenOutMinAmount: string; - }; -} - -// types for mgs type:: /osmosis.gamm.v1beta1.MsgSwapExactAmountOut -export interface Osmosis1TrxMsgOsmosisGammV1beta1MsgSwapExactAmountOut - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.OsmosisGammV1beta1MsgSwapExactAmountOut; - data: { - routes: { - poolId: string; - tokenInDenom: string; - }[]; - sender: string; - tokenOut: { - denom: string; - amount: string; - }; - tokenInMaxAmount: string; - }; -} - -// types for mgs type:: /osmosis.incentives.MsgAddToGauge -export interface Osmosis1TrxMsgOsmosisIncentivesMsgAddToGauge - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.OsmosisIncentivesMsgAddToGauge; - data: { - owner: string; - gaugeId: string; - rewards: { - denom: string; - amount: string; - }[]; - }; -} - -// types for mgs type:: /osmosis.incentives.MsgCreateGauge -export interface Osmosis1TrxMsgOsmosisIncentivesMsgCreateGauge - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.OsmosisIncentivesMsgCreateGauge; - data: { - owner: string; - distributeTo: { - lockQueryType: string; - denom?: string; - duration: string; - timestamp: string; - }; - coins: { - denom: string; - amount: string; - }[]; - startTime: string; - numEpochsPaidOver: string; - poolId: string; - }; -} - -// types for mgs type:: /osmosis.lockup.MsgBeginUnlocking -export interface Osmosis1TrxMsgOsmosisLockupMsgBeginUnlocking - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.OsmosisLockupMsgBeginUnlocking; - data: { - owner: string; - ID: string; - coins?: { - denom: string; - amount: string; - }[]; - }; -} - -// types for mgs type:: /osmosis.lockup.MsgLockTokens -export interface Osmosis1TrxMsgOsmosisLockupMsgLockTokens - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.OsmosisLockupMsgLockTokens; - data: { - coins: { - denom: string; - amount: string; - }[]; - owner: string; - duration: string; - }; -} - -// types for mgs type:: /osmosis.poolmanager.v1beta1.MsgSplitRouteSwapExactAmountIn -export interface Osmosis1TrxMsgOsmosisPoolmanagerV1beta1MsgSplitRouteSwapExactAmountIn - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.OsmosisPoolmanagerV1beta1MsgSplitRouteSwapExactAmountIn; - data: { - routes: { - pools: { - poolId: string; - tokenOutDenom: string; - }[]; - tokenInAmount?: string; - }[]; - sender: string; - tokenInDenom: string; - tokenOutMinAmount: string; - }; -} - -// types for mgs type:: /osmosis.poolmanager.v1beta1.MsgSwapExactAmountIn -export interface Osmosis1TrxMsgOsmosisPoolmanagerV1beta1MsgSwapExactAmountIn - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.OsmosisPoolmanagerV1beta1MsgSwapExactAmountIn; - data: { - sender: string; - routes: { - tokenOutDenom: string; - poolId?: string; - }[]; - tokenIn: { - denom: string; - amount: string; - }; - tokenOutMinAmount: string; - }; -} - -// types for mgs type:: /osmosis.poolmanager.v1beta1.MsgSwapExactAmountOut -export interface Osmosis1TrxMsgOsmosisPoolManagerV1beta1MsgSwapExactAmountOut - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.OsmosisPoolManagerV1beta1MsgSwapExactAmountOut; - data: { - routes: { - poolId: string; - tokenInDenom: string; - }[]; - sender: string; - tokenOut: { - denom: string; - amount: string; - }; - tokenInMaxAmount: string; - }; -} - -// types for mgs type:: /osmosis.superfluid.MsgAddToConcentratedLiquiditySuperfluidPosition -export interface Osmosis1TrxMsgOsmosisSuperfluidMsgAddToConcentratedLiquiditySuperfluidPosition - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.OsmosisSuperfluidMsgAddToConcentratedLiquiditySuperfluidPosition; - data: { - sender: string; - positionId: string; - tokenDesired0: { - denom: string; - amount: string; - }; - tokenDesired1: { - denom: string; - amount: string; - }; - }; -} - -// types for mgs type:: /osmosis.superfluid.MsgCreateFullRangePositionAndSuperfluidDelegate -export interface Osmosis1TrxMsgOsmosisSuperfluidMsgCreateFullRangePositionAndSuperfluidDelegate - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.OsmosisSuperfluidMsgCreateFullRangePositionAndSuperfluidDelegate; - data: { - coins: { - denom: string; - amount: string; - }[]; - poolId: string; - sender: string; - valAddr: string; - }; -} - -// types for mgs type:: /osmosis.superfluid.MsgLockAndSuperfluidDelegate -export interface Osmosis1TrxMsgOsmosisSuperfluidMsgLockAndSuperfluidDelegate - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.OsmosisSuperfluidMsgLockAndSuperfluidDelegate; - data: { - coins: { - denom: string; - amount: string; - }[]; - sender: string; - valAddr: string; - }; -} - -// types for mgs type:: /osmosis.superfluid.MsgSuperfluidDelegate -export interface Osmosis1TrxMsgOsmosisSuperfluidMsgSuperfluidDelegate - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.OsmosisSuperfluidMsgSuperfluidDelegate; - data: { - lockId: string; - sender: string; - valAddr: string; - }; -} - -// types for mgs type:: /osmosis.superfluid.MsgSuperfluidUnbondLock -export interface Osmosis1TrxMsgOsmosisSuperfluidMsgSuperfluidUnbondLock - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.OsmosisSuperfluidMsgSuperfluidUnbondLock; - data: { - lockId: string; - sender: string; - }; -} - -// types for mgs type:: /osmosis.superfluid.MsgSuperfluidUndelegate -export interface Osmosis1TrxMsgOsmosisSuperfluidMsgSuperfluidUndelegate - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.OsmosisSuperfluidMsgSuperfluidUndelegate; - data: { - lockId: string; - sender: string; - }; -} - -// types for mgs type:: /osmosis.superfluid.MsgUnbondConvertAndStake -export interface Osmosis1TrxMsgOsmosisSuperfluidMsgUnbondConvertAndStake - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.OsmosisSuperfluidMsgUnbondConvertAndStake; - data: { - lockId: string; - sender: string; - valAddr: string; - minAmtToStake: string; - sharesToConvert: { - denom: string; - amount: string; - }; - }; -} - -// types for mgs type:: /osmosis.superfluid.MsgUnlockAndMigrateSharesToFullRangeConcentratedPosition -export interface Osmosis1TrxMsgOsmosisSuperfluidMsgUnlockAndMigrateSharesToFullRangeConcentratedPosition - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.OsmosisSuperfluidMsgUnlockAndMigrateSharesToFullRangeConcentratedPosition; - data: { - lockId: string; - sender: string; - tokenOutMins: { - denom: string; - amount: string; - }[]; - sharesToMigrate: { - denom: string; - amount: string; - }; - }; -} - -// types for mgs type:: /osmosis.tokenfactory.v1beta1.MsgCreateDenom -export interface Osmosis1TrxMsgOsmosisTokenFactoryV1beta1MsgCreateDenom - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.OsmosisTokenFactoryV1beta1MsgCreateDenom; - data: { - sender: string; - subdenom: string; - }; -} - -// types for mgs type:: /osmosis.tokenfactory.v1beta1.MsgMint -export interface Osmosis1TrxMsgOsmosisTokenfactoryV1beta1MsgMint - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.OsmosisTokenfactoryV1beta1MsgMint; - data: { - sender: string; - amount: { - denom: string; - amount: string; - }; - mintToAddress?: string; - }; -} - -// types for mgs type:: /osmosis.valsetpref.v1beta1.MsgWithdrawDelegationRewards -export interface Osmosis1TrxMsgOsmosisValsetprefV1beta1MsgWithdrawDelegationRewards - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.OsmosisValsetprefV1beta1MsgWithdrawDelegationRewards; - data: { - delegator: string; - }; -} - -// types for mgs type:: /cosmos.staking.v1beta1.MsgCreateValidator -export interface Osmosis1TrxMsgCosmosStakingV1beta1MsgCreateValidator - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.CosmosStakingV1beta1MsgCreateValidator; - data: { - description: { - moniker?: string; - identity?: string; - website?: string; - details?: string; - securityContact?: string; - }; - commission: { - rate: string; - maxRate: string; - maxChangeRate: string; - }; - minSelfDelegation: string; - delegatorAddress: string; - validatorAddress: string; - pubkey: { - '@type': string; - key: string; - }; - value: { - denom: string; - amount: string; - }; - }; -} - -// types for mgs type:: /cosmos.distribution.v1beta1.MsgFundCommunityPool -export interface Osmosis1TrxMsgCosmosDistributionV1beta1MsgFundCommunityPool - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.CosmosDistributionV1beta1MsgFundCommunityPool; - data: { - amount: { - denom: string; - amount: string; - }[]; - depositor: string; - }; -} - -// types for msg type:: /ibc.core.channel.v1.MsgChannelCloseInit -export interface Osmosis1TrxMsgIbcCoreChannelV1MsgChannelCloseInit - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.IbcCoreChannelV1MsgChannelCloseInit; - data: { - port_id: string; - channel_id: string; - signer: string; - }; -} - -// types for msg type:: /cosmwasm.wasm.v1.MsgUpdateAdmin -export interface Osmosis1TrxMsgCosmwasmWasmV1MsgUpdateAdmin - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.CosmwasmWasmV1MsgUpdateAdmin; - data: { - sender: string; - newAdmin: string; - contract: string; - }; -} - -// types for msg type:: /cosmos.auth.v1beta1.MsgUpdateParams -export interface Osmosis1TrxMsgCosmosAuthV1beta1MsgUpdateParams - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.CosmosAuthV1beta1MsgUpdateParams; - data: { - authority: string; - params: { - max_memo_characters: string; - tx_sig_limit: string; - tx_size_cost_per_byte: string; - sig_verify_cost_ed25519: string; - sig_verify_cost_secp256k1: string; - }; - }; -} - -// types for msg type:: /cosmos.crisis.v1beta1.MsgUpdateParams -export interface Osmosis1TrxMsgCosmosCrisisV1beta1MsgUpdateParams - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.CosmosCrisisV1beta1MsgUpdateParams; - data: { - authority: string; - constant_fee: { - denom: string; - amount: string; - }; - }; -} - -// types for msg type:: /cosmos.distribution.v1beta1.MsgCommunityPoolSpend -export interface Osmosis1TrxMsgCosmosDistributionV1beta1MsgCommunityPoolSpend - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.CosmosDistributionV1beta1MsgCommunityPoolSpend; - data: { - authority: string; - recipient: string; - amount: { - denom: string; - amount: string; - }; - }; -} - -// types for msg type:: /cosmos.evidence.v1beta1.MsgSubmitEvidence -export interface Osmosis1TrxMsgCosmosEvidenceV1beta1MsgSubmitEvidence - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.CosmosEvidenceV1beta1MsgSubmitEvidence; - data: { - submitter: string; - evidence: { - type_url: string; - value: string; - }; - }; -} - -// types for msg type:: /cosmos.slashing.v1beta1.MsgUpdateParams -export interface Osmosis1TrxMsgCosmosSlashingV1beta1MsgUpdateParams - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.CosmosSlashingV1beta1MsgUpdateParams; - data: { - authority: string; - params: { - signed_blocks_window: string; - min_signed_per_window: string; - downtime_jail_duration: string; - slash_fraction_double_sign: string; - slash_fraction_downtime: string; - }; - }; -} - -// types for msg type:: /cosmos.staking.v1beta1.MsgUpdateParams -export interface Osmosis1TrxMsgCosmosStakingV1beta1MsgUpdateParams - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.CosmosStakingV1beta1MsgUpdateParams; - data: { - authority: string; - params: { - unbonding_time: string; - max_validators: string; - max_entries: string; - historical_entries: string; - bond_denom: string; - min_commission_rate: string; - }; - }; -} - -// types for msg type:: /cosmos.upgrade.v1beta1.MsgCancelUpgrade -export interface Osmosis1TrxMsgCosmosUpgradeV1beta1MsgCancelUpgrade - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.CosmosUpgradeV1beta1MsgCancelUpgrade; - data: { - authority: string; - }; -} - -// types for msg type:: /cosmos.upgrade.v1beta1.MsgSoftwareUpgrade -export interface Osmosis1TrxMsgCosmosUpgradeV1beta1MsgSoftwareUpgrade - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.CosmosUpgradeV1beta1MsgSoftwareUpgrade; - data: { - authority: string; - plan: { - name: string; - time: string; - height: string; - info: string; - upgraded_client_state: { - type_url: string; - value: string; - }; - }; - }; -} - -// types for msg type:: /cosmwasm.wasm.v1.MsgClearAdmin -export interface Osmosis1TrxMsgCosmwasmWasmV1MsgClearAdmin - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.CosmwasmWasmV1MsgClearAdmin; - data: { - sender: string; - contract: string; - }; -} - -// types for msg type:: /cosmos.bank.v1beta1.MsgUpdateParams -export interface Osmosis1TrxMsgCosmosBankV1beta1MsgUpdateParams - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.CosmosBankV1beta1MsgUpdateParams; - data: { - authority: string; - params: { - send_enabled: { - denom: string; - enabled: string; - }[]; - default_send_enabled: boolean; - }; - }; -} - -// types for msg type:: /osmosis.tokenfactory.v1beta1.MsgBurn -export interface Osmosis1TrxMsgOsmosisTokenFactoryV1betaBurn - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.OsmosisTokenFactoryV1betaBurn; - data: { - sender: string; - amount: { - denom: string; - amount: string; - }; - burnFromAddress: string; - }; -} - -// types for msg type:: /osmosis.tokenfactory.v1beta1.MsgChangeAdmin -export interface Osmosis1TrxMsgOsmosisTokenfactoryV1beta1MsgChangeAdmin - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.OsmosisTokenfactoryV1beta1MsgChangeAdmin; - data: { - sender: string; - denom: string; - newAdmin: string; - }; -} - -// types for msg type:: /osmosis.tokenfactory.v1beta1.MsgChangeAdmin -export interface Osmosis1TrxMsgOsmosisTokenfactoryV1beta1MsgSetDenomMetadata - extends IRangeMessage { - type: Osmosis1TrxMsgTypes.OsmosisTokenfactoryV1beta1MsgSetDenomMetadata; - data: { - sender: string; - metadata: { - description: string; - denomUnits: { - denom: string; - aliases: string[]; - }[]; - base: string; - display: string; - name: string; - symbol: string; - }; - }; -} diff --git a/src/types/chain/solana/IRangeBlockSolanaTrx.ts b/src/types/chain/solana/IRangeBlockSolanaTrx.ts deleted file mode 100644 index d20044d0..00000000 --- a/src/types/chain/solana/IRangeBlockSolanaTrx.ts +++ /dev/null @@ -1,125 +0,0 @@ -export interface SolanaTrxMeta { - err?: { - InstructionError: ( - | { - Custom: number; - } - | number - | string - )[][]; - } | null; - fee: number; - status: { - Ok?: null; - Err?: { - InstructionError: ( - | { - Custom: number; - } - | number - | string - )[][]; - }; - }; - rewards?: unknown | null; - returnData?: { - data: string[]; - programId: string; - }; - logMessages: string[]; - preBalances: number[]; - postBalances: number[]; - preTokenBalances: { - mint: string; - owner: string; - programId: string; - accountIndex: number; - uiTokenAmount: { - amount: string; - decimals: number; - uiAmount?: number; - uiAmountString: string; - }; - }[]; - innerInstructions: { - index: number; - instructions: - | { - parsed: { - info: { - amount: string; - source: string; - authority?: string; - destination?: string; - owner?: string; - delegate?: string; - }; - type: string; - }; - program: string; - programId: string; - stackHeight: number; - } - | { - data: string; - accounts: string[]; - programId: string; - stackHeight: number; - }[]; - }[]; - postTokenBalances: { - mint: string; - owner: string; - programId: string; - accountIndex: number; - uiTokenAmount: { - amount: string; - decimals: number; - uiAmount?: any; - uiAmountString: string; - }; - }[]; - computeUnitsConsumed: number; -} - -export interface SolanaTrxTrx { - message: { - accountKeys: { - pubkey: string; - signer: boolean; - source: string; - writable: boolean; - }[]; - instructions: ( - | { - programId: string; - } - | { - programId: string; - accounts: string[]; - data: string; - } - | { - programId: string; - stackHeight: any; - parsed: - | { - info: { - source: string; - lamports: number; - destination: string; - }; - type: string; - } - | string; - program: string; - } - )[]; - }; - signatures: string[]; -} - -export interface SolanaTrx { - meta: SolanaTrxMeta; - transaction: SolanaTrxTrx; -} diff --git a/src/types/chain/stride-1/IRangeBlockStride1Trx.ts b/src/types/chain/stride-1/IRangeBlockStride1Trx.ts deleted file mode 100644 index ce43bdba..00000000 --- a/src/types/chain/stride-1/IRangeBlockStride1Trx.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { IRangeTransaction } from '../IRangeTransaction'; -import { Stride1TrxMsg } from './IRangeBlockStride1TrxMsg'; - -export interface Stride1Trx extends IRangeTransaction { - messages: Stride1TrxMsg[]; -} diff --git a/src/types/chain/stride-1/IRangeBlockStride1TrxMsg.ts b/src/types/chain/stride-1/IRangeBlockStride1TrxMsg.ts deleted file mode 100644 index a3632fd8..00000000 --- a/src/types/chain/stride-1/IRangeBlockStride1TrxMsg.ts +++ /dev/null @@ -1,584 +0,0 @@ -import { IRangeMessage } from '../IRangeMessage'; - -enum Stride1TrxMsgTypes { - CosmosBankV1beta1MsgMultiSend = 'cosmos.bank.v1beta1.MsgMultiSend', - CosmosBankV1Beta1MsgSend = 'cosmos.bank.v1beta1.MsgSend', - CosmosDistributionV1Beta1MsgSetWithdrawAddress = 'cosmos.distribution.v1beta1.MsgSetWithdrawAddress', - CosmosDistributionV1Beta1MsgWithdrawDelegatorReward = 'cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward', - CosmosDistributionV1Beta1MsgWithdrawValidatorCommission = 'cosmos.distribution.v1beta1.MsgWithdrawValidatorCommission', - CosmosFeegrantV1beta1MsgGrantAllowance = 'cosmos.feegrant.v1beta1.MsgGrantAllowance', - CosmosGovV1beta1MsgSubmitProposal = 'cosmos.gov.v1beta1.MsgSubmitProposal', - CosmosGovV1Beta1MsgVote = 'cosmos.gov.v1beta1.MsgVote', - CosmosGovV1MsgVote = 'cosmos.gov.v1.MsgVote', - CosmosGovV1MsgVoteWeighted = 'cosmos.gov.v1.MsgVoteWeighted', - CosmosStakingV1Beta1MsgBeginRedelegate = 'cosmos.staking.v1beta1.MsgBeginRedelegate', - CosmosStakingV1Beta1MsgCancelUnbondingDelegation = 'cosmos.staking.v1beta1.MsgCancelUnbondingDelegation', - CosmosStakingV1Beta1MsgDelegate = 'cosmos.staking.v1beta1.MsgDelegate', - CosmosStakingV1Beta1MsgUndelegate = 'cosmos.staking.v1beta1.MsgUndelegate', - IbcApplicationsTransferV1MsgTransfer = 'ibc.applications.transfer.v1.MsgTransfer', - IbcCoreChannelV1MsgAcknowledgement = 'ibc.core.channel.v1.MsgAcknowledgement', - IbcCoreChannelV1MsgChannelOpenAck = 'ibc.core.channel.v1.MsgChannelOpenAck', - IbcCoreChannelV1MsgRecvPacket = 'ibc.core.channel.v1.MsgRecvPacket', - IbcCoreChannelV1MsgTimeout = 'ibc.core.channel.v1.MsgTimeout', - StrideClaimMsgClaimFreeAmount = 'stride.claim.MsgClaimFreeAmount', - StrideStakeibcMsgAddValidators = 'stride.stakeibc.MsgAddValidators', - StrideInterchainqueryV1MsgSubmitQueryResponse = 'stride.interchainquery.v1.MsgSubmitQueryResponse', - StrideStakeIBCMsgChangeValidatorWeight = 'stride.stakeibc.MsgChangeValidatorWeight', - StrideStakeibcMsgClaimUndelegatedTokens = 'stride.stakeibc.MsgClaimUndelegatedTokens', - StrideStakeIBCMsgLiquidStake = 'stride.stakeibc.MsgLiquidStake', - StrideStakeIBCMsgRedeemStake = 'stride.stakeibc.MsgRedeemStake', - StrideStakeIBCMsgRestoreInterchainAccount = 'stride.stakeibc.MsgRestoreInterchainAccount', - StrideStakeIBCMsgUpdateValidatorSharesExchRate = 'stride.stakeibc.MsgUpdateValidatorSharesExchRate', - IbcCoreClientV1MsgUpdateClient = 'ibc.core.client.v1.MsgUpdateClient', -} - -export type Stride1TrxMsg = - | Stride1TrxMsgCosmosBankV1beta1MsgMultiSend - | Stride1TrxMsgCosmosBankV1Beta1MsgSend - | Stride1TrxMsgCosmosDistributionV1Beta1MsgSetWithdrawAddress - | Stride1TrxMsgCosmosDistributionV1Beta1MsgWithdrawDelegatorReward - | Stride1TrxMsgCosmosDistributionV1Beta1MsgWithdrawValidatorCommission - | Stride1TrxMsgCosmosFeegrantV1beta1MsgGrantAllowance - | Stride1TrxMsgCosmosGovV1beta1MsgSubmitProposal - | Stride1TrxMsgCosmosGovV1Beta1MsgVote - | Stride1TrxMsgCosmosGovV1MsgVote - | Stride1TrxMsgCosmosGovV1MsgVoteWeighted - | Stride1TrxMsgCosmosStakingV1Beta1MsgBeginRedelegate - | Stride1TrxMsgCosmosStakingV1Beta1MsgCancelUnbondingDelegation - | Stride1TrxMsgCosmosStakingV1Beta1MsgDelegate - | Stride1TrxMsgCosmosStakingV1Beta1MsgUndelegate - | Stride1TrxMsgIbcApplicationsTransferV1MsgTransfer - | Stride1TrxMsgIbcCoreChannelV1MsgAcknowledgement - | Stride1TrxMsgIbcCoreChannelV1MsgChannelOpenAck - | Stride1TrxMsgIbcCoreChannelV1MsgRecvPacket - | Stride1TrxMsgIbcCoreChannelV1MsgTimeout - | Stride1TrxMsgStrideClaimMsgClaimFreeAmount - | Stride1TrxMsgStrideInterchainqueryV1MsgSubmitQueryResponse - | Stride1TrxMsgStrideStakeIBCMsgAddValidators - | Stride1TrxMsgStrideStakeIBCMsgChangeValidatorWeight - | Stride1TrxMsgStrideStakeIBCMsgClaimUndelegatedTokens - | Stride1TrxMsgStrideStakeIBCMsgLiquidStake - | Stride1TrxMsgStrideStakeIBCMsgRedeemStake - | Stride1TrxMsgStrideStakeIBCMsgRestoreInterchainAccount - | Stride1TrxMsgStrideStakeIBCMsgUpdateValidatorSharesExchRate - | Stride1TrxMsgIbcCoreClientV1MsgUpdateClient; - -// types for mgs type:: /cosmos.bank.v1beta1.MsgMultiSend -export interface Stride1TrxMsgCosmosBankV1beta1MsgMultiSend - extends IRangeMessage { - type: Stride1TrxMsgTypes.CosmosBankV1beta1MsgMultiSend; - data: { - inputs: { - coins: { denom: string; amount: string }[]; - address: string; - }[]; - outputs: { - coins: { denom: string; amount: string }[]; - address: string; - }[]; - }; -} - -// types for mgs type:: /cosmos.bank.v1beta1.MsgSend -export interface Stride1TrxMsgCosmosBankV1Beta1MsgSend extends IRangeMessage { - type: Stride1TrxMsgTypes.CosmosBankV1Beta1MsgSend; - data: { - amount: { denom: string; amount: string }[]; - toAddress: string; - fromAddress: string; - }; -} - -// types for mgs type:: /cosmos.distribution.v1beta1.MsgSetWithdrawAddress -export interface Stride1TrxMsgCosmosDistributionV1Beta1MsgSetWithdrawAddress - extends IRangeMessage { - type: Stride1TrxMsgTypes.CosmosDistributionV1Beta1MsgSetWithdrawAddress; - data: { - withdrawAddress: string; - delegatorAddress: string; - }; -} - -// types for mgs type:: /cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward -export interface Stride1TrxMsgCosmosDistributionV1Beta1MsgWithdrawDelegatorReward - extends IRangeMessage { - type: Stride1TrxMsgTypes.CosmosDistributionV1Beta1MsgWithdrawDelegatorReward; - data: { - delegatorAddress: string; - validatorAddress: string; - }; -} - -// types for mgs type:: /cosmos.distribution.v1beta1.MsgWithdrawValidatorCommission -export interface Stride1TrxMsgCosmosDistributionV1Beta1MsgWithdrawValidatorCommission - extends IRangeMessage { - type: Stride1TrxMsgTypes.CosmosDistributionV1Beta1MsgWithdrawValidatorCommission; - data: { - validatorAddress: string; - }; -} - -// types for mgs type:: /cosmos.feegrant.v1beta1.MsgGrantAllowance -export interface Stride1TrxMsgCosmosFeegrantV1beta1MsgGrantAllowance - extends IRangeMessage { - type: Stride1TrxMsgTypes.CosmosFeegrantV1beta1MsgGrantAllowance; - data: { - granter: string; - grantee: string; - allowance: { - '@type': string; - spendLimit: { - denom: string; - amount: string; - }[]; - expiration: string; - }; - }; -} - -// types for mgs type:: /cosmos.gov.v1beta1.MsgSubmitProposal -export interface Stride1TrxMsgCosmosGovV1beta1MsgSubmitProposal - extends IRangeMessage { - type: Stride1TrxMsgTypes.CosmosGovV1beta1MsgSubmitProposal; - data: { - content: { - '@type': string; - title: string; - description: string; - plan?: { - name: string; - time: string; - height: string; - }; - }; - initialDeposit: { - denom: string; - amount: string; - }[]; - proposer: string; - }; -} - -// types for mgs type:: /cosmos.gov.v1beta1.MsgVote -export interface Stride1TrxMsgCosmosGovV1Beta1MsgVote extends IRangeMessage { - type: Stride1TrxMsgTypes.CosmosGovV1Beta1MsgVote; - data: { - voter: string; - option: string; - proposalId: string; - }; -} - -// types for mgs type:: /cosmos.gov.v1.MsgVote -export interface Stride1TrxMsgCosmosGovV1MsgVote extends IRangeMessage { - type: Stride1TrxMsgTypes.CosmosGovV1MsgVote; - data: { - voter: string; - option: string; - proposalId: string; - }; -} - -// types for mgs type:: /cosmos.gov.v1.MsgVoteWeighted -export interface Stride1TrxMsgCosmosGovV1MsgVoteWeighted extends IRangeMessage { - type: Stride1TrxMsgTypes.CosmosGovV1MsgVoteWeighted; - data: { - voter: string; - options: { - option: string; - weight: string; - }[]; - proposalId: string; - }; -} - -// types for mgs type:: /cosmos.staking.v1beta1.MsgBeginRedelegate -export interface Stride1TrxMsgCosmosStakingV1Beta1MsgBeginRedelegate - extends IRangeMessage { - type: Stride1TrxMsgTypes.CosmosStakingV1Beta1MsgBeginRedelegate; - data: { - amount: { - denom: string; - amount: string; - }; - delegatorAddress: string; - validatorDstAddress: string; - validatorSrcAddress: string; - }; -} - -// types for mgs type:: /cosmos.staking.v1beta1.MsgCancelUnbondingDelegation -export interface Stride1TrxMsgCosmosStakingV1Beta1MsgCancelUnbondingDelegation - extends IRangeMessage { - type: Stride1TrxMsgTypes.CosmosStakingV1Beta1MsgCancelUnbondingDelegation; - data: { - amount: { - denom: string; - amount: string; - }; - creationHeight: string; - delegatorAddress: string; - validatorAddress: string; - }; -} - -// types for mgs type:: /cosmos.staking.v1beta1.MsgDelegate -export interface Stride1TrxMsgCosmosStakingV1Beta1MsgDelegate - extends IRangeMessage { - type: Stride1TrxMsgTypes.CosmosStakingV1Beta1MsgDelegate; - data: { - amount: { - denom: string; - amount: string; - }; - delegatorAddress: string; - validatorAddress: string; - }; -} - -// types for mgs type:: /cosmos.staking.v1beta1.MsgUndelegate -export interface Stride1TrxMsgCosmosStakingV1Beta1MsgUndelegate - extends IRangeMessage { - type: Stride1TrxMsgTypes.CosmosStakingV1Beta1MsgUndelegate; - data: { - amount: { - denom: string; - amount: string; - }; - delegatorAddress: string; - validatorAddress: string; - }; -} - -// types for mgs type:: /ibc.applications.transfer.v1.MsgTransfer -export interface Stride1TrxMsgIbcApplicationsTransferV1MsgTransfer - extends IRangeMessage { - type: Stride1TrxMsgTypes.IbcApplicationsTransferV1MsgTransfer; - data: { - sourcePort: string; - sourceChannel: string; - token: { - denom: string; - amount: string; - }; - sender: string; - receiver: string; - timeoutHeight?: { - revisionNumber?: string; - revisionHeight?: string; - }; - timeoutTimestamp?: string; - memo?: string; - }; -} - -// types for mgs type:: /ibc.core.channel.v1.MsgAcknowledgement -export interface Stride1TrxMsgIbcCoreChannelV1MsgAcknowledgement - extends IRangeMessage { - type: Stride1TrxMsgTypes.IbcCoreChannelV1MsgAcknowledgement; - data: { - packet: { - sequence: string; - sourcePort: string; - sourceChannel: string; - destinationPort: string; - destinationChannel: string; - data: string; - timeoutHeight?: { - revisionHeight?: string; - revisionNumber?: string; - }; - timeoutTimestamp?: string; - }; - acknowledgement: string; - proofAcked: string; - proofHeight: { - revisionHeight: string; - revisionNumber?: string; - }; - signer: string; - }; -} - -// types for mgs type:: /ibc.core.channel.v1.MsgChannelOpenAck -export interface Stride1TrxMsgIbcCoreChannelV1MsgChannelOpenAck - extends IRangeMessage { - type: Stride1TrxMsgTypes.IbcCoreChannelV1MsgChannelOpenAck; - data: { - portId: string; - channelId: string; - counterpartyChannelId: string; - counterpartyVersion: string; - proofTry: string; - proofHeight: { - revisionNumber: string; - revisionHeight: string; - }; - signer: string; - }; -} - -// types for mgs type:: /ibc.core.channel.v1.MsgRecvPacket -export interface Stride1TrxMsgIbcCoreChannelV1MsgRecvPacket - extends IRangeMessage { - type: Stride1TrxMsgTypes.IbcCoreChannelV1MsgRecvPacket; - data: { - packet: { - sequence: string; - sourcePort: string; - sourceChannel: string; - destinationPort: string; - destinationChannel: string; - data: string; - timeoutHeight?: { - revisionHeight?: string; - revisionNumber?: string; - }; - timeoutTimestamp?: string; - }; - proofCommitment: string; - proofHeight: { - revisionHeight: string; - revisionNumber?: string; - }; - signer: string; - }; -} - -// types for mgs type:: /ibc.core.channel.v1.MsgTimeout -export interface Stride1TrxMsgIbcCoreChannelV1MsgTimeout extends IRangeMessage { - type: Stride1TrxMsgTypes.IbcCoreChannelV1MsgTimeout; - data: { - packet: { - sequence: string; - sourcePort: string; - sourceChannel: string; - destinationPort: string; - destinationChannel: string; - data: string; - timeoutHeight?: { - revisionNumber?: string; - revisionHeight?: string; - }; - timeoutTimestamp?: string; - }; - proofUnreceived: string; - proofHeight: { - revisionNumber: string; - revisionHeight: string; - }; - nextSequenceRecv: string; - signer: string; - }; -} - -// types for mgs type:: /stride.claim.MsgClaimFreeAmount -export interface Stride1TrxMsgStrideClaimMsgClaimFreeAmount - extends IRangeMessage { - type: Stride1TrxMsgTypes.StrideClaimMsgClaimFreeAmount; - data: { - user: string; - }; -} - -// types for mgs type:: /stride.interchainquery.v1.MsgSubmitQueryResponse -export interface Stride1TrxMsgStrideInterchainqueryV1MsgSubmitQueryResponse - extends IRangeMessage { - type: Stride1TrxMsgTypes.StrideInterchainqueryV1MsgSubmitQueryResponse; - data: { - chainId: string; - queryId: string; - proofOps: { - ops: { - type: string; - key: string; - data: string; - }[]; - }; - height: string; - fromAddress: string; - result?: string; - }; -} - -// types for mgs type:: /stride.stakeibc.MsgAddValidators -export interface Stride1TrxMsgStrideStakeIBCMsgAddValidators - extends IRangeMessage { - type: Stride1TrxMsgTypes.StrideStakeibcMsgAddValidators; - data: { - creator: string; - hostZone: string; - validators: { - name: string; - address: string; - delegationAmt: string; - weight?: string; - }[]; - }; -} - -// types for mgs type:: /stride.stakeibc.MsgChangeValidatorWeight -export interface Stride1TrxMsgStrideStakeIBCMsgChangeValidatorWeight - extends IRangeMessage { - type: Stride1TrxMsgTypes.StrideStakeIBCMsgChangeValidatorWeight; - data: { - creator: string; - valAddr: string; - hostZone: string; - }; -} - -// types for mgs type:: /stride.stakeibc.MsgClaimUndelegatedTokens -export interface Stride1TrxMsgStrideStakeIBCMsgClaimUndelegatedTokens - extends IRangeMessage { - type: Stride1TrxMsgTypes.StrideStakeibcMsgClaimUndelegatedTokens; - data: { - epoch: string; - creator: string; - hostZoneId: string; - sender?: string; - }; -} - -// types for mgs type:: /stride.stakeibc.MsgLiquidStake -export interface Stride1TrxMsgStrideStakeIBCMsgLiquidStake - extends IRangeMessage { - type: Stride1TrxMsgTypes.StrideStakeIBCMsgLiquidStake; - data: { - amount: string; - creator: string; - hostDenom: string; - }; -} - -// types for mgs type:: /stride.stakeibc.MsgRedeemStake -export interface Stride1TrxMsgStrideStakeIBCMsgRedeemStake - extends IRangeMessage { - type: Stride1TrxMsgTypes.StrideStakeIBCMsgRedeemStake; - data: { - amount: string; - creator: string; - hostZone: string; - receiver: string; - }; -} - -// types for mgs type:: /stride.stakeibc.MsgRestoreInterchainAccount -export interface Stride1TrxMsgStrideStakeIBCMsgRestoreInterchainAccount - extends IRangeMessage { - type: Stride1TrxMsgTypes.StrideStakeIBCMsgRestoreInterchainAccount; - data: { - chainId: string; - creator: string; - }; -} - -// types for mgs type:: /stride.stakeibc.MsgUpdateValidatorSharesExchRate -export interface Stride1TrxMsgStrideStakeIBCMsgUpdateValidatorSharesExchRate - extends IRangeMessage { - type: Stride1TrxMsgTypes.StrideStakeIBCMsgUpdateValidatorSharesExchRate; - data: { - chainId: string; - creator: string; - valoper: string; - }; -} - -// types for mgs type:: /ibc.core.client.v1.MsgUpdateClient -export interface Stride1TrxMsgIbcCoreClientV1MsgUpdateClient - extends IRangeMessage { - type: Stride1TrxMsgTypes.IbcCoreClientV1MsgUpdateClient; - data: { - clientId: string; - clientMessage: { - '@type': string; - signedHeader: { - header: { - version: { - block: string; - app?: string; - }; - chainId: string; - height: string; - time: string; - lastBlockId: { - hash: string; - partSetHeader: { - total: number; - hash: string; - }; - }; - lastCommitHash: string; - dataHash: string; - validatorsHash: string; - nextValidatorsHash: string; - consensusHash: string; - appHash: string; - lastResultsHash: string; - evidenceHash: string; - proposerAddress: string; - }; - commit: { - height: string; - round?: number; - blockId: { - hash: string; - partSetHeader: { - total: number; - hash: string; - }; - }; - signatures: { - blockIdFlag: string; - timestamp?: string; - validatorAddress?: string; - signature?: string; - }[]; - }; - }; - validatorSet: { - validators: { - address: string; - pubKey: { - ed25519: string; - }; - votingPower: string; - proposerPriority?: string; - }[]; - proposer: { - address: string; - pubKey: { - ed25519: string; - }; - votingPower: string; - proposerPriority?: string; - }; - totalVotingPower?: string; - }; - trustedHeight: { - revisionNumber?: string; - revisionHeight: string; - }; - trustedValidators: { - validators: { - address: string; - pubKey: { - ed25519: string; - }; - votingPower: string; - proposerPriority?: string; - }[]; - proposer: { - address: string; - pubKey: { - ed25519: string; - }; - votingPower: string; - proposerPriority?: string; - }; - totalVotingPower?: string; - }; - }; - signer: string; - }; -} diff --git a/src/utils/basic.ts b/src/utils/basic.ts new file mode 100644 index 00000000..83326f83 --- /dev/null +++ b/src/utils/basic.ts @@ -0,0 +1,171 @@ +export const RANGE_URL = 'https://app.range.org'; + +export function capitalizeFirstLetter(str: string) { + return str.charAt(0).toUpperCase() + str.slice(1); +} + +export function camelCaseToTitleCase(str: string): string { + return str + .replace(/([A-Z])/g, ' $1') + .replace(/^./, (str) => str.toUpperCase()) + .trim(); +} + +export function safeJsonParse(str: string) { + try { + return JSON.parse(str); + } catch (error) { + return null; + } +} + +import { INetwork } from '../types/INetwork'; + +export function deepClone(obj: T): T { + return JSON.parse(JSON.stringify(obj)); +} + +export const sleep = (ms: number) => + new Promise((resolve) => setTimeout(resolve, ms)); + +export function filterCommonAddresses( + msgAddresses: string[], + addresses: string[] +) { + msgAddresses = [...new Set(msgAddresses)]; + addresses = [...new Set(addresses)]; + + const addressSet = new Set(addresses); // Convert the second array to a Set for efficient lookup + return msgAddresses.filter((a) => addressSet.has(a)); +} + +export function formatAddresses(addresses: string[]) { + if (!addresses?.length) return ''; + + if (addresses.length <= 3) { + return addresses.join(', '); + } + + return ( + addresses.slice(0, 3).join(', ') + ` and ${addresses.length - 3} others` + ); +} + +export function findValuesFromAttributes(attributes: any, keys: any) { + if (!attributes) return null; + + const results: any = {}; + + for (const attr of attributes) { + if (keys.includes(attr.key)) { + results[attr.key] = attr.value; + } + } + + return results; +} + +export function getObjectFromAttributes(attributes: any) { + if (!attributes) return null; + + const results: any = {}; + + for (const attr of attributes) { + results[attr.key] = attr.value; + } + + return results; +} + +export function getSenderFromMessage(msg: any) { + for (const ev of msg.events) { + const sender = ev.attributes.find((a: any) => a.key === 'sender')?.value; + if (sender) return sender; + } + return null; +} + +export function splitAmountDenom(str: string): { + amount: number; + denom: string; +} { + const match = str.match(/^(\d+)(.+)$/); + + if (!match) { + throw new Error(`String format is incorrect: ${str}`); + } + + const [, amount, denom] = match; + + return { amount: Number(amount), denom }; +} + +export function getWasmPatterns(events: any) { + const res: { contract: any; sender: any; method: any }[] = []; + let sender; + let wasmEvent: any = {}; + + for (const ev of events) { + if (ev.type === 'message') { + const obj = getObjectFromAttributes(ev.attributes); + if (obj.sender) { + sender = obj.sender; + } + } + if (ev.type === 'wasm') { + const obj = getObjectFromAttributes(ev.attributes); + wasmEvent.contract = obj._contract_address; + wasmEvent.method = obj.method || obj.action || 'unknown'; + res.push({ ...wasmEvent, sender }); + wasmEvent = {}; + } + } + + return res; +} + +export function getRunnerNetwork(runnerNetwork: string): INetwork { + const match = runnerNetwork.match(/-runner-(.+)/); + if (!match) return runnerNetwork as INetwork; + return match[1].split('.')[0] as INetwork; +} + +export const isTestEnv = + process.env.NODE_ENV === 'test' || process.env.NODE_ENV === 'local'; + +export function arraySum(arr: any) { + return arr.reduce((a: any, b: any) => a + b, 0); +} + +export function safeJsonStringify(obj: any) { + try { + return JSON.stringify(obj, (_, value) => { + if (typeof value === 'bigint') { + return value.toString(); + } + return value; + }); + } catch (e) { + return null; + } +} + +export function removeBigintFromObject(obj: any): any { + if (obj === null || typeof obj !== 'object') { + return obj; + } + + if (Array.isArray(obj)) { + return obj.map((item) => removeBigintFromObject(item)); + } + + const newObj = { ...obj }; + for (const key in newObj) { + if (typeof newObj[key] === 'bigint') { + newObj[key] = newObj[key].toString(); + } else if (typeof newObj[key] === 'object') { + newObj[key] = removeBigintFromObject(newObj[key]); + } + } + return newObj; +} diff --git a/src/utils/dayjs.ts b/src/utils/dayjs.ts new file mode 100644 index 00000000..1cabf47a --- /dev/null +++ b/src/utils/dayjs.ts @@ -0,0 +1,26 @@ +import dayjs from 'dayjs'; +import advancedFormat from 'dayjs/plugin/advancedFormat'; +import customParseFormat from 'dayjs/plugin/customParseFormat'; +import duration from 'dayjs/plugin/duration'; +import isoWeek from 'dayjs/plugin/isoWeek'; +import isSameOrAfter from 'dayjs/plugin/isSameOrAfter'; +import isSameOrBefore from 'dayjs/plugin/isSameOrBefore'; +import relativeTime from 'dayjs/plugin/relativeTime'; +import timezone from 'dayjs/plugin/timezone'; +import utc from 'dayjs/plugin/utc'; + +dayjs.extend(customParseFormat); +dayjs.extend(advancedFormat); +dayjs.extend(isSameOrAfter); +dayjs.extend(isSameOrBefore); +dayjs.extend(utc); +dayjs.extend(timezone); +dayjs.extend(relativeTime); +dayjs.extend(isoWeek); +dayjs.extend(duration); + +function minuteHumanize(min: number) { + return dayjs.duration(min, 'minutes').humanize(); +} + +export { dayjs, minuteHumanize }; diff --git a/src/utils/doc-helper.ts b/src/utils/doc-helper.ts new file mode 100644 index 00000000..0d1df6b0 --- /dev/null +++ b/src/utils/doc-helper.ts @@ -0,0 +1,217 @@ +import { INetwork } from '../types/INetwork'; + +export const TICKER_PARAM = { + label: 'Ticker', + description: + 'Choose the interval at which the rule will execute. For example, selecting 1 hour means the rule will run every hour.', + field: 'ticker', + fieldType: 'TimeDuration', +} as const; + +export const MIN_PERC_CHANGE = { + label: 'Minimum Percentage Change', + description: + 'Set the minimum percentage change required to trigger an alert.', + field: 'minPercChange', + fieldType: 'Number', +} as const; + +export const ASSET_SYMBOL_PARAM = { + label: 'Asset Symbol', + description: 'Enter the symbol of the asset you wish to track.', + field: 'assetSymbol', + fieldType: 'AssetSymbol', +} as const; + +export const MIN_USD_PARAM = { + label: 'Minimum USD', + description: 'Specify the minimum USD amount needed to trigger an alert.', + field: 'minUsd', + fieldType: 'Number', +} as const; + +export const NOTIFY_INTERVAL_PARAM = { + label: 'Notify Interval', + description: + 'The interval in minutes to notify the user. The default is every 6 hours.', + field: 'notifyInterval', + fieldType: 'TimeDuration', + optional: true, +} as const; + +export const MESSAGE_TYPE_SUBSTRING_PARAM = { + label: 'Message Type (Full or Partial)', + description: + 'Input a full or partial message type for matching, such as cosmos, gamm, or cosmos.gov.v1.MsgVote.', + field: 'messageType', + fieldType: 'Text', + optional: true, +} as const; + +export const SENDER_PARAM = { + label: 'Sender', + description: 'Monitor one or more sender addresses.', + field: 'sender', + fieldType: 'AddressesContractsList', + optional: true, +} as const; + +export const RECEIVER_PARAM = { + label: 'Receiver', + description: 'Monitor one or more receiver addresses.', + field: 'receiver', + fieldType: 'AddressesContractsList', + optional: true, +} as const; + +export const NUMERIC_CHANGE_PARAM = { + label: 'Numeric Change Threshold', + description: + 'The threshold for the absolute liquidity change in USD for which the rule will trigger', + field: 'numericChange', + fieldType: 'Number', + optional: true, +} as const; + +export const PERC_CHANGE_PARAM = { + label: 'Percentage Change Threshold', + description: + 'The threshold for the percentage liquidity change in USD for which the rule will trigger', + field: 'percChange', + fieldType: 'Number', + optional: true, +} as const; + +export const NOTIFY_DIRECTION_PARAM = { + label: 'Notify Direction', + description: + 'By default we will notify when the delta is positive or negative.', + field: 'notifyDirection' as const, + fieldType: 'CustomDropdownSingle' as const, + options: [ + { + label: 'Positive', + value: 'positive', + }, + { + label: 'Negative', + value: 'negative', + }, + ], + optional: true, +}; + +export const CW_NETWORKS: INetwork[] = [ + 'osmosis-1', + 'cosmoshub-4', + 'dydx-mainnet-1', + 'dymension_1100-1', + 'neutron-1', + 'noble-1', +]; + +export const COSMOS_NETWORKS: INetwork[] = [ + 'osmosis-1', + 'cosmoshub-4', + 'dydx-mainnet-1', + 'dymension_1100-1', + 'neutron-1', + 'noble-1', +]; + +export const CCV_NETWORKS: INetwork[] = ['cosmoshub-4']; + +export const DISTRIBUTION_NETWORKS: INetwork[] = COSMOS_NETWORKS; +export const EVIDENCE_NETWORKS: INetwork[] = COSMOS_NETWORKS; + +export const COSMOS_GOV_NETWORKS: INetwork[] = [ + 'osmosis-1', + 'celestia', + 'cosmoshub-4', + 'dydx-mainnet-1', + 'dymension_1100-1', + 'noble-1', + 'stride-1', + 'pio-mainnet-1', + 'agoric-3', +]; + +export const TOKENFACTORY_NETWORKS: INetwork[] = [ + 'osmosis-1', + 'neutron-1', + 'stride-1', + 'noble-1', + 'dydx-mainnet-1', + 'celestia', + 'cosmoshub-4', + 'dymension_1100-1', + 'pio-mainnet-1', +]; + +export const INCENTIVES_NETWORKS: INetwork[] = TOKENFACTORY_NETWORKS; + +export const ES_AGGREGATION_NETWORKS: INetwork[] = ['osmosis-1']; + +export const WORKSPACES = { + dev: ['dev', 'cm2u6lm140012p401w7buwwi0', 'range-validators'], + mars: ['cm239nf300035pd010qsifdyu'], + neutron: ['neutron-dao-monitoring'], + osmosis: ['osmosis'], + dymension: ['dymension'], + agoric: ['agoric'], + dydx: ['dydx-v4-perpetuals'], + provenance: ['provenance-pio'], + noble: ['noble'], + squads: [ + 'cm2j9b5q1001apc01jrfm7udj', + 'cm3cn4c3n004nqk013h2trq5w', + 'cm915kcmo000lqs01ze0dzes3', + 'cm970slsz0008nm01ddgiaxag', + 'cm970t4qh0002lp013k36bzfm', + 'cmbz00tlh003kqo018tni85i1', + ], + hydro: ['cm41amc7c000smo01dnhxtayx'], + agent_x: ['cm84kd6pp000hqp01f06m4p7p'], +}; + +export const DYMENSION: INetwork[] = [`dymension_1100-1`]; +export const AGORIC: INetwork[] = [`agoric-3`]; +export const PROVENANCE: INetwork[] = [`pio-mainnet-1`]; +export const NOBLE: INetwork[] = [`noble-1`]; +export const DYDX: INetwork[] = [`dydx-mainnet-1`]; +export const COSMOSHUB: INetwork[] = [`cosmoshub-4`]; + +export const SOLANA_SIGNER_PARAM = { + label: 'Signer', + description: + 'Monitor one or more signers of the transaction. By default, all signers will be included.', + field: 'signer', + fieldType: 'AddressesContractsList', + optional: true, +} as const; + +export const SOLANA_PROGRAM_ID_PARAM = { + label: 'Program ID', + description: + 'Specify the program ID to monitor. Providing a specific program ID helps reduce unnecessary notifications. By default, all program IDs are monitored.', + field: 'programId', + fieldType: 'ContractList', + optional: true, +} as const; + +export const SOLANA_PROGRAM_ID_PARAM_REQUIRED = { + label: 'Program ID', + description: + 'Specify the program ID to monitor. Providing a specific program ID helps avoid excessive notifications.', + field: 'programId', + fieldType: 'ContractList', +} as const; + +export const SOLANA_INVOLVED_ACCOUNT_PARAM = { + label: 'Involved Account', + description: + 'Enter the account address you want to monitor. Leave this field empty to monitor all accounts.', + field: 'involvedAccount', + fieldType: 'AddressesContractsList', + optional: true, +} as const; diff --git a/src/utils/explorer-api.ts b/src/utils/explorer-api.ts new file mode 100644 index 00000000..fe3256ec --- /dev/null +++ b/src/utils/explorer-api.ts @@ -0,0 +1,173 @@ +import { axios } from '../services/axios'; +import { dayjs } from './dayjs'; + +export const EXPLORER_API = 'https://explorer.range.org'; + +export async function fetchCrossChainTransactions( + bridge: string, + min_usd: string +) { + if (!min_usd) min_usd = '0'; + if (!bridge) bridge = ''; + + const url = `${EXPLORER_API}/api/payments?direction=first&limit=100&bridge=${bridge}&anchorTxn=&status=&min_usd=${min_usd}`; + + const res = await axios.get(url); + + return res.data.resources; +} + +interface ICctpTransfer { + id: string; + burn_hash: string | null; + mint_hash: string | null; + transfer_hash: string; + from: string; + destination: string; + from_network: string; + destination_network: string; + amount: string; + denom: string; + status: string; + from_timestamp: string; + destination_timestamp: string; + from_block: string; + destination_block: string | null; + nonce: string; +} + +export async function fetchCctpLatestTimestamps() { + const res = await axios.get( + `${EXPLORER_API}/usdc/api/usdc-helpers/latest-transfer-timestamp` + ); + + return res.data; +} + +export function cleanOldNotifiedLogs( + notified: Record, + timestamp: string +) { + return Object.fromEntries( + Object.entries(notified) + .map((e) => { + const [, from_timestamp] = e; + const diffInHours = dayjs(timestamp).diff( + dayjs(from_timestamp as string), + 'hours' + ); + if (diffInHours < 6) { + return e; + } + return null; + }) + .filter(Boolean) as any + ); +} + +interface ITransfer { + sender_symbol: string; + status: string; + receiver_address: string; + sender_address: string; + time: string; + bridge_info: any; + id: string; + sender_network: string; + receiver_network: string; + sender_amount: number; + sender_tx_hash: string; +} + +export async function fetchCctpPendingTransfers({ + any_network, + begin_time, +}: { + any_network: string; + begin_time: string; +}): Promise { + const res = await axios.get( + `${EXPLORER_API}/usdc/api/usdc-helpers/pending-transfers?any_network=${any_network}&begin_time=${begin_time}` + ); + return res.data.resources; +} + +export interface IRateLimit { + asset_name: string; + name: string; + inflow: string; + outflow: string; + netflow: string; + percentage_filled: string; + base_denom_exponent: string; + price: string; +} + +export async function getRateLimits(network: string): Promise { + const res = await axios.get( + `${EXPLORER_API}/api/rate-limits?network=${network}` + ); + return res.data.resources; +} + +interface IIbcTransfer { + id: string; + amount: string; + denom: string; + sender: string; + receiver: string; + source_chain_id: string; + source_channel_id: string; + destination_chain_id: string; + destination_channel_id: string; + source_block_height: string; + source_block_time: string; + source_tx_hash: string; + asset_symbol: string; + ibc_status: string; + usd: number; + destination_ibccallbackerror_context?: string; +} + +export async function getPendingTransfers({ + sourceNetworks, + destinationNetworks, + min_usd, +}: { + sourceNetworks?: string; + destinationNetworks?: string; + min_usd?: string; +}): Promise { + const limit = 100; + const direction = 'first'; + const status = 'PENDING'; + const max_usd = ''; + + sourceNetworks = sourceNetworks || ''; + destinationNetworks = destinationNetworks || ''; + min_usd = min_usd || ''; + + const res = await axios.get( + `${EXPLORER_API}/ibc/api/transfers?txHash=&anchorTxn=&sourceNetworks=${sourceNetworks}&destinationNetworks=${destinationNetworks}&limit=${limit}&direction=${direction}&status=${status}&min_usd=${min_usd}&max_usd=${max_usd}` + ); + return res.data.resources; +} + +export async function getErrorTransfers({ + sourceNetworks, + destinationNetworks, + min_usd, +}: { + sourceNetworks?: string; + destinationNetworks?: string; + min_usd?: string; +}): Promise { + const limit = 100; + const direction = 'first'; + const status = 'ERROR_ON_DESTINATION'; + const max_usd = ''; + const res = await axios.get( + `${EXPLORER_API}/ibc/api/transfers?txHash=&anchorTxn=&sourceNetworks=${sourceNetworks}&destinationNetworks=${destinationNetworks}&limit=${limit}&direction=${direction}&status=${status}&min_usd=${min_usd}&max_usd=${max_usd}` + ); + return res.data.resources; +} diff --git a/src/utils/fill-findings.ts b/src/utils/fill-findings.ts new file mode 100644 index 00000000..556b7868 --- /dev/null +++ b/src/utils/fill-findings.ts @@ -0,0 +1,9 @@ +export function fillFindings( + template: string, + variables: { [key: string]: string } +): string { + return template.replace( + /\{\{(\w+)\}\}/g, + (_, key) => variables[key] || 'unknown' + ); +} diff --git a/src/utils/logger.ts b/src/utils/logger.ts new file mode 100644 index 00000000..80e293ff --- /dev/null +++ b/src/utils/logger.ts @@ -0,0 +1,39 @@ +import * as winston from 'winston'; +import { env } from '../env'; + +// Create custom logger that wraps the winston logger +export const winstonLogger = winston.createLogger({ + level: env.LOG_LEVEL, + format: winston.format.combine( + winston.format.timestamp(), + winston.format.json() + ), + transports: [ + new winston.transports.Console({ + format: winston.format.combine( + winston.format.colorize(), + winston.format.printf( + ({ timestamp, level, message }) => + `${timestamp} | ${level} | ${message}` + ) + ), + }), + ], +}); + +// Export wrapped logger with helper - forwards meta to winston +export const logger = { + ...winstonLogger, + debug: (message: string, meta?: object) => { + winstonLogger.debug(message, meta); + }, + info: (message: string, meta?: object) => { + winstonLogger.info(message, meta); + }, + warn: (message: string, meta?: object) => { + winstonLogger.warn(message, meta); + }, + error: (message: string, meta?: object) => { + winstonLogger.error(message, meta); + }, +}; diff --git a/src/utils/number-fmt.ts b/src/utils/number-fmt.ts new file mode 100644 index 00000000..4abe9e72 --- /dev/null +++ b/src/utils/number-fmt.ts @@ -0,0 +1,141 @@ +import { dayjs } from './dayjs'; +import type { DurationUnitType } from 'dayjs/plugin/duration'; +import { findAssetInfo, formatAmountToUsd } from '../services/AssetManager'; + +const formatNumber = (raw_num: number) => { + if (raw_num === 0) { + return '0'; + } + + const isNegetive = raw_num < 0; + + const num = Math.abs(raw_num); + + let res: string; + + if (num < 10 ** -6) { + res = '~0'; + } else if (Math.abs(num) < 1_000) { + res = new Intl.NumberFormat('en-US', { + maximumFractionDigits: num >= 1 ? 2 : 6, + }).format(num); + } else if (Math.abs(num) < 1_000_000) { + res = parseFloat((num / 1000).toFixed(1)) + 'K'; // convert to K for number from > 1000 < 1 million + } else if (Math.abs(num) < 1_000_000_000) { + res = parseFloat((num / 1_000_000).toFixed(1)) + 'M'; // convert to M for number from > 1 million + } else if (Math.abs(num) < 1_000_000_000_000) { + res = parseFloat((num / 1_000_000_000).toFixed(1)) + 'B'; // convert to M for number from > 1 billion + } else if (Math.abs(num) < 1_000_000_000_000_000) { + res = parseFloat((num / 1_000_000_000_000).toFixed(1)) + 'T'; // convert to M for number from > 1 trillion + } else { + res = Number(num).toExponential(1); + } + + if (isNegetive) { + res = '-' + res; + } + + return res; +}; + +export const secToHumanReadable = (sec: number, t: DurationUnitType) => { + const timeUnit = t; + const d = dayjs.duration(sec, timeUnit); + + const years = d.years(); + const months = d.months(); + const days = d.days(); + const hours = d.hours(); + const minutes = d.minutes(); + const seconds = d.seconds(); + + let result = ''; + + if (years) result += `${years} year${years > 1 ? 's' : ''} `; + if (months) result += `${months} month${months > 1 ? 's' : ''} `; + if (days) result += `${days} day${days > 1 ? 's' : ''} `; + if (hours) result += `${hours} hour${hours > 1 ? 's' : ''} `; + if (minutes) result += `${minutes} minute${minutes > 1 ? 's' : ''} `; + if (seconds) result += `${seconds} second${seconds > 1 ? 's' : ''}`; + + return result.trim(); +}; + +export function fmtMsgType(msgType: string) { + const splitRes = msgType.split('.'); + return `${splitRes[splitRes.length - 1]}(${splitRes[0]})`; +} + +function fmtObjectAmount(obj: any) { + if ( + typeof obj === 'object' && + obj && + 'amount' in obj && + 'denom' in obj && + Object.keys(obj).length === 2 + ) { + return formatAmountToUsd(obj).tokenUsdString; + } + + return null; +} + +export function fmtObject(obj: any, size = 100) { + let str = ''; + + const amtFmt = fmtObjectAmount(obj); + if (amtFmt) return amtFmt; + + for (const [key, value] of Object.entries(obj)) { + let value_f = value; + + if (value && typeof value === 'object') { + const amtFmt_1 = fmtObjectAmount(value); + value_f = amtFmt_1 || '(' + fmtObject(value, size) + ')'; + } + + if (value && Array.isArray(value)) { + value_f = '[' + value.map((v) => fmtObject(v, size)).join(', ') + ']'; + } + + if (typeof value === 'string') { + const info = findAssetInfo(value); + if (info) { + value_f = value_f + '(' + info.symbol + ')'; + } + } + + str += `${key}: ${value_f}, `; + } + + str = str.slice(0, -2); + + if (str.length > size) { + str = str.slice(0, size) + '...'; + } + + return str; +} + +export function fmtSec(sec: number) { + return secToHumanReadable(sec, 'second'); +} + +export function fmtMin(sec: number) { + return secToHumanReadable(sec, 'minute'); +} + +/** + * A universal formatter for numbers and objects + */ +export function format(input: any, size?: number): string { + if (typeof input === 'number') { + return formatNumber(input); + } + + if (typeof input === 'object' && input !== null) { + return fmtObject(input, size); + } + + return String(input); +} diff --git a/src/utils/pipeline-setup.ts b/src/utils/pipeline-setup.ts new file mode 100644 index 00000000..a72d30ee --- /dev/null +++ b/src/utils/pipeline-setup.ts @@ -0,0 +1,43 @@ +import 'reflect-metadata'; +import { join } from 'path'; +import { GenericContainer, StartedTestContainer } from 'testcontainers'; +import { initPool, closePool } from '../threadpool/pool'; + +export interface PipelineContext { + container: StartedTestContainer; + redisUrl: string; +} + +export interface PipelineOptions { + maxThreads?: number; + processorsFile: string; +} + +export async function setupPipeline( + opts: PipelineOptions +): Promise { + const container = await new GenericContainer('redis:7-alpine') + .withExposedPorts(6379) + .start(); + + const redisUrl = `${container.getHost()}:${container.getMappedPort(6379)}`; + process.env.BLOCK_REDIS_URL = redisUrl; + process.env.TICK_REDIS_URL = redisUrl; + process.env.RUNNER_CACHE_REDIS_URL = redisUrl; + process.env.NOTIFICATIONS_REDIS_URL = redisUrl; + + await import(opts.processorsFile); + + await initPool({ + filename: join(__dirname, '..', 'threadpool', 'worker.js'), + maxThreads: opts.maxThreads ?? 2, + }); + + return { container, redisUrl }; +} + +export async function destroyPipeline(ctx: PipelineContext): Promise { + await closePool(); + await ctx.container.stop(); + process.exit(0); +} diff --git a/src/utils/processor.ts b/src/utils/processor.ts new file mode 100644 index 00000000..29183714 --- /dev/null +++ b/src/utils/processor.ts @@ -0,0 +1,118 @@ +import 'reflect-metadata'; +import { ISubEvent } from '../types/IEvent'; +import { IRule } from '../types/IRule'; +import { IAlertRule } from '../types/IAlertRule'; +import { initAssetService } from '../services/AssetManager'; + +export abstract class BlockProcessor { + readonly taskType = 'BLOCK' as const; + abstract callback(processorParams: IBlockProcessor): Promise; +} + +export abstract class TickProcessor { + readonly taskType = 'TICK' as const; + abstract callback(processorParams: ITickProcessor): Promise; +} + +export function Processor(rule: IRule) { + return function (processorClass: new () => BlockProcessor | TickProcessor) { + ProcessorRegistry.register(rule, processorClass); + }; +} + +export interface IBlockProcessor { + block: B; + rule: IAlertRule; +} +export interface ITickProcessor { + timestamp: string; + rule: IAlertRule; +} + +export const Rule = (rule: IRule) => { + return function (processorClass: new () => BlockProcessor | TickProcessor) { + Reflect.defineMetadata('rule', rule, processorClass); + + const original = processorClass.prototype.callback; + processorClass.prototype.callback = async function (...args: any[]) { + await initAssetService(); + return original.apply(this, args); + }; + + ProcessorRegistry.register(rule, processorClass); + }; +}; + +export interface ProcessorInfo { + rule: IRule; + instance: BlockProcessor | TickProcessor; +} + +export class ProcessorRegistry { + private static processorMap = new Map(); + + static register( + rule: IRule, + processorClass: new () => BlockProcessor | TickProcessor + ) { + if (!rule.type?.trim()) { + throw new Error( + 'ProcessorRegistry: rule.type must be a non-empty string.' + ); + } + + if (!rule.networks?.length) { + throw new Error( + `ProcessorRegistry: rule "${rule.type}" must specify at least one network.` + ); + } + + if (this.processorMap.has(rule.type)) { + throw new Error( + `ProcessorRegistry: duplicate rule type "${rule.type}". Each rule type must be unique.` + ); + } + + const instance = new processorClass(); + + if ( + typeof (instance as any).callback !== 'function' || + !('taskType' in instance) + ) { + throw new Error( + `ProcessorRegistry: ${processorClass.name} must extend BlockProcessor or TickProcessor.` + ); + } + + if (rule.parameters?.length) { + const fields = rule.parameters.map((p) => p.field); + const duplicateFields = fields.filter((f, i) => fields.indexOf(f) !== i); + if (duplicateFields.length > 0) { + console.warn( + `ProcessorRegistry: rule "${rule.type}" has duplicate parameter fields: ${[...new Set(duplicateFields)].join(', ')}` + ); + } + } + + this.processorMap.set(rule.type, { rule, instance }); + } + + static get(ruleType: string): ProcessorInfo | undefined { + return this.processorMap.get(ruleType); + } + + static getAlertTemplates(network?: string): Map { + const templates = new Map(); + this.processorMap.forEach((info, ruleType) => { + if (network && !info.rule.networks.includes(network)) return; + const rule = { + ...info.rule, + severity: info.rule.severity || 'info', + trigger: info.instance.taskType, + }; + if (network) rule.networks = [network]; + templates.set(ruleType, rule); + }); + return templates; + } +} diff --git a/src/utils/redis-keys.ts b/src/utils/redis-keys.ts new file mode 100644 index 00000000..1b0b3aaf --- /dev/null +++ b/src/utils/redis-keys.ts @@ -0,0 +1,20 @@ +export const RedisKeys = { + getParamsForRuleByRuleGroupIdAndRuleId: (input: { + ruleGroupId: string; + ruleId: string; + }) => { + return `{${input.ruleGroupId}}:rule:${input.ruleId}:parameters`; + }, + + getCachedFunctionKey(funName: string) { + return `cached:function:{${funName}}`; + }, + + getBgAggregationKey(aggName: string) { + return `bg:aggregation:${aggName}`; + }, + + getProgramIdlKey(programId: string) { + return `solanafm:idl:${programId}`; + }, +}; diff --git a/src/utils/redis.ts b/src/utils/redis.ts new file mode 100644 index 00000000..ce5d52ab --- /dev/null +++ b/src/utils/redis.ts @@ -0,0 +1,190 @@ +import * as r from 'redis'; +import { commandOptions } from 'redis'; +import { z } from 'zod'; +import { safeJsonParse } from './basic'; +import { logger } from './logger'; + +const PayloadValidator = z.object({ + id: z.string().min(1), + message: z.object({ + message: z.string(), + }), +}); + +let lastLoggedTime: Date | null = null; +const LOG_THROTTLE_MINUTES = 10; + +export async function consumeRedisStream({ + client, + streamName, + consumerGroup, + consumerName, + callback, +}: { + client: ReturnType; + streamName: string; + consumerGroup: string; + consumerName: string; + callback: (payload: any, messageId: string) => Promise; +}) { + if (!streamName || !consumerGroup || !consumerName) { + console.error( + `Invalid stream name, consumer group, or consumer name: ${streamName}, ${consumerGroup}, ${consumerName}` + ); + throw new Error( + `Invalid stream name, consumer group, or consumer name: ${streamName}, ${consumerGroup}, ${consumerName}` + ); + } + + // Check if consumer group exists + const groups = await client.xInfoGroups(streamName); + const groupExists = groups.some((g) => g.name === consumerGroup); + if (!groupExists) { + // Create consumer group starting from latest message + await client.xGroupCreate(streamName, consumerGroup, '$'); + logger.info( + `Created consumer group ${consumerGroup} for stream ${streamName}` + ); + } + + // Check if consumer exists in group + const consumers = await client.xInfoConsumers(streamName, consumerGroup); + const consumerExists = consumers.some((c) => c.name === consumerName); + if (!consumerExists) { + // Create consumer in group + await client.xGroupCreateConsumer(streamName, consumerGroup, consumerName); + logger.info(`Created consumer ${consumerName} in group ${consumerGroup}`); + } + + while (true) { + const response = await client.xReadGroup( + commandOptions({ + isolated: true, + }), + consumerGroup, + consumerName, + [ + { + key: streamName, + id: '>', // Using '>' to read new messages that haven't been delivered to any consumer yet + }, + ], + { + COUNT: 10, + BLOCK: 5000, + } + ); + + if (response !== null) { + for (const row of response[0].messages) { + const msg = PayloadValidator.safeParse(row); + if (msg.success) { + const payload = safeJsonParse(msg.data.message.message); + if (payload) { + await callback(payload, msg.data.id); + // console.log('Callback executed successfully'); + } + } + + await client.xAck(streamName, consumerGroup, row.id); + // console.log('Acknowledging message:', row.id); + } + } else { + logIfThresholdExceeded( + `No new messages in stream ${streamName} for consumer ${consumerName}` + ); + } + } +} + +function logIfThresholdExceeded(message: string) { + const now = new Date(); + + if ( + !lastLoggedTime || + now.getTime() - lastLoggedTime.getTime() > LOG_THROTTLE_MINUTES * 60 * 1000 + ) { + logger.info(message); + lastLoggedTime = now; + } +} + +export async function createRedisClient(url: string) { + const client = r.createClient({ + url: `redis://${url}`, + }); + await client.connect(); + return client; +} + +export async function consumeById({ + client, + streamName, + messageId, + callback, +}: { + client: ReturnType; + streamName: string; + messageId: string; + callback?: (payload: any, messageId: string) => Promise; +}) { + if (!streamName) { + throw new Error(`Invalid stream name: ${streamName}`); + } + + // Read message by ID using xRange to get a single message + const response = await client.xRange(streamName, messageId, messageId); + + if (response && response.length > 0) { + const message = response[0]; + + if (callback) { + const msg = PayloadValidator.safeParse(message); + if (msg.success) { + const payload = safeJsonParse(msg.data.message.message); + if (payload) { + await callback(payload, msg.data.id); + } + } + } + + return message; + } + + logger.info('Message not found'); + return null; +} + +export async function publishToStream({ + client, + streamName, + payload, +}: { + client: ReturnType; + streamName: string; + payload: any; +}) { + if (!streamName) { + throw new Error(`Invalid stream name: ${streamName}`); + } + + // Create stream if it doesn't exist + try { + await client.xGroupCreate(streamName, streamName, '$', { MKSTREAM: true }); + logger.info(`Created stream ${streamName}`); + } catch (err: any) { + // Ignore if group already exists + if (!err.message.includes('BUSYGROUP')) { + throw err; + } + } + + await client.xAdd( + streamName, + '*', // Let Redis generate the message ID + { + message: JSON.stringify(payload), + } + ); + logger.debug(`Published payload to stream ${streamName}`); +} diff --git a/src/utils/risk-score.ts b/src/utils/risk-score.ts new file mode 100644 index 00000000..55e9b635 --- /dev/null +++ b/src/utils/risk-score.ts @@ -0,0 +1,26 @@ +import { env } from '../env'; +import { axios } from '../services/axios'; + +export async function fetchRangeRiskScore({ + address, + network, +}: { + address: string; + network: string; +}) { + try { + const res = await axios.get( + `${env.RANGE_API_HOST}/v1/risk/address?address=${address}&network=${network}`, + { + headers: { + 'X-API-KEY': env.RANGE_API_KEY, + }, + } + ); + + return res.data.riskScore; + } catch (error) { + console.log(error); + return 0; + } +} diff --git a/src/utils/safe-fetch.ts b/src/utils/safe-fetch.ts new file mode 100644 index 00000000..99bba526 --- /dev/null +++ b/src/utils/safe-fetch.ts @@ -0,0 +1,56 @@ +import { dayjs } from './dayjs'; + +/** + * Helper function to safely fetch data with caching and rate limiting. + * Implements caching to avoid repeated API calls and handles rate limiting by enforcing a 1 hour cooldown between fetches. + * If data exists in cache, returns it directly. Otherwise attempts to fetch new data if cooldown period has elapsed. + * Handles errors gracefully by caching failed attempts to prevent retry spam. + * + * @param rule - The rule object containing parameters for the fetch + * @param cache - Cache object to store fetched data + * @param fetchFun - Async function that performs the actual data fetch + * @param saveCache - Function to save updated cache data + * @param fieldKey - Key in cache object where fetched data should be stored + * @returns Promise - Returns true if data is available (either freshly fetched or from cache), false otherwise + */ +export async function safeFetch({ + rule, + cache, + fetchFun, + saveCache, + fieldKey, +}: { + rule: any; + cache: any; + fetchFun: () => Promise; + saveCache: (rule: any, cache: any) => Promise; + fieldKey: string; +}) { + if (!cache[fieldKey]) { + if ( + !cache.lastFetched || + dayjs().diff(dayjs(cache.lastFetched), 'hour') >= 1 + ) { + try { + const fieldValue = await fetchFun(); + cache[fieldKey] = fieldValue; + cache.lastFetched = dayjs().toISOString(); + await saveCache(rule, cache); + return true; + } catch (error) { + console.warn( + `WARNING: safeFetch() encountered an error. Please reach out to the development team for assistance: ${error}` + ); + + cache[fieldKey] = null; + cache.lastFetched = dayjs().toISOString(); + await saveCache(rule, cache); + return false; + } + } else { + return false; + } + } else { + return true; + } +} diff --git a/src/utils/skip-tick.ts b/src/utils/skip-tick.ts new file mode 100644 index 00000000..9f7f6f2d --- /dev/null +++ b/src/utils/skip-tick.ts @@ -0,0 +1,50 @@ +import * as crypto from 'crypto'; +import { dayjs } from './dayjs'; +import { isTestEnv } from './basic'; + +export function skipTick({ + timestamp, + ticker = 30, + threshold = 60, + salt, +}: { + ticker: number; + timestamp: string; + threshold?: number; + salt: string; +}) { + if (isTestEnv) return false; + + const timestampAge = dayjs().diff(dayjs(timestamp), 'minute'); + + if (timestampAge >= threshold) { + return true; + } + + let offset = 0; + + if (salt) { + // a constant offset for each alert rule based on hash of created_at + offset = sha256HashToSmallNumber(sha256(salt)) % ticker; + } + + const unixMinute = Math.floor(dayjs(timestamp).unix() / 60); + const remainder = (unixMinute + offset) % ticker; + return remainder !== 0; +} + +function sha256(input: string): string { + const hash = crypto.createHash('sha256'); + hash.update(input); + return hash.digest('hex'); +} + +// Function to convert SHA-256 hash to a number smaller than 10^9 +function sha256HashToSmallNumber(hash: string): number { + // Take the first 16 characters of the hash and parse it as a hexadecimal number + const hex = hash.slice(0, 16); + // Convert hexadecimal to decimal and take modulo 10^9 + const number = BigInt('0x' + hex) % BigInt(10 ** 9); + // Convert BigInt to regular number + return Number(number); +} diff --git a/src/utils/slack.ts b/src/utils/slack.ts new file mode 100644 index 00000000..c49b1843 --- /dev/null +++ b/src/utils/slack.ts @@ -0,0 +1,58 @@ +import axios from 'axios'; + +const SLACK_WEBHOOK_URL = process.env.SLACK_WEBHOOK_URL || ''; + +interface SlackDevContext { + ruleId?: string; + ruleType?: string; + network?: string; + triggerMode?: 'BLOCK' | 'TICK'; + blockHeight?: string | number; + blockTime?: string; + tickTime?: string; +} + +/** + * Send a dev alert to Slack with context about the current block/tick and rule. + * + * Usage from a BlockProcessor: + * slackSendDev({ ruleId: rule.id, ruleType: rule.ruleType, network: rule.network, triggerMode: 'BLOCK', blockHeight: block.height }, payload) + * + * Or simply: + * slackSendDev({}, 'something weird happened') + * slackSendDev({}, { count: 42, txHash: '...' }) + */ +export function slackSendDev(context: SlackDevContext, payload: unknown): void { + const ts = new Date().toISOString(); + + const ctxParts: string[] = []; + if (context.ruleId) ctxParts.push(`Rule: \`${context.ruleId}\``); + if (context.ruleType) ctxParts.push(`Type: \`${context.ruleType}\``); + if (context.network) ctxParts.push(`Network: \`${context.network}\``); + if (context.triggerMode === 'BLOCK') { + ctxParts.push(`Block: \`${context.blockHeight ?? '?'}\``); + if (context.blockTime) ctxParts.push(`Block Time: ${context.blockTime}`); + } else if (context.triggerMode === 'TICK') { + if (context.tickTime) ctxParts.push(`Tick: ${context.tickTime}`); + } + + let payloadStr: string; + if (typeof payload === 'string') { + payloadStr = payload; + } else { + try { + payloadStr = '```' + JSON.stringify(payload, null, 2) + '```'; + } catch { + payloadStr = String(payload); + } + } + + const text = + `:eyes: *Dev Alert* — ${ts}\n` + + (ctxParts.length > 0 ? ctxParts.join(' | ') + '\n' : '') + + payloadStr; + + // Fire-and-forget — don't block the processor + if (!SLACK_WEBHOOK_URL) return; + axios.post(SLACK_WEBHOOK_URL, { text }, { timeout: 5_000 }).catch(() => {}); +} diff --git a/src/utils/solana/balance-change.ts b/src/utils/solana/balance-change.ts new file mode 100644 index 00000000..83dabb75 --- /dev/null +++ b/src/utils/solana/balance-change.ts @@ -0,0 +1,115 @@ +import { SOL_MINT } from './programs'; + +export interface ISolanaBalanceChange { + amount: number; + mint: string; + sign: '' | '-'; +} + +export function getBalanceChangeMap(tx: any) { + const { preBalances, postBalances, preTokenBalances, postTokenBalances } = + tx.meta; + const keys = tx.transaction.message.accountKeys.map((e: any) => e.pubkey); + + const solBalanceChange: Record = {}; + + for (let i = 0; i < preBalances.length; i++) { + const preBalance = preBalances[i]; + const postBalance = postBalances[i]; + const account = keys[i]; + const diff = Math.abs(postBalance - preBalance); + + if (diff > 0) { + solBalanceChange[account] = { + amount: diff, + mint: SOL_MINT, + sign: postBalance > preBalance ? '' : '-', + }; + } + } + + // Map to track token owners + const ownerByTokenAccount: Record = {}; + + // Track balance changes by authority (owner) instead of token account + const tokenBalanceChange: Record< + string, + Record + > = {}; + + // First, build a map of token accounts to their owners + preTokenBalances.forEach((pre: any) => { + const account = keys[pre.accountIndex]; + const owner = pre.owner; + ownerByTokenAccount[account] = owner; + }); + + postTokenBalances.forEach((post: any) => { + const account = keys[post.accountIndex]; + const owner = post.owner; + ownerByTokenAccount[account] = owner; + }); + + const preTokenBalancesMap = Object.fromEntries( + preTokenBalances.map((e: any) => { + return [e.accountIndex, e]; + }) + ); + + // Process all post token balances + postTokenBalances.forEach((post: any) => { + const pre = preTokenBalancesMap[post.accountIndex]; + const owner = post.owner; + const mint = post.mint; + + // If the account doesn't exist in preTokenBalances, consider it as zero + const preRawAmount = pre ? Number(pre.uiTokenAmount.amount) : 0; + const postRawAmount = Number(post.uiTokenAmount.amount); + const diff = pre ? postRawAmount - preRawAmount : postRawAmount; + + if (diff !== 0) { + if (!tokenBalanceChange[owner]) tokenBalanceChange[owner] = {}; + + // For newly created accounts in a receive operation, the sign should be positive + const sign = pre + ? post.uiTokenAmount.uiAmount > preRawAmount + ? '' + : '-' + : ''; + + tokenBalanceChange[owner][mint] = { + amount: diff, + mint, + sign, + }; + } + }); + + // Process pre token balances that don't appear in post (fully spent/closed accounts) + preTokenBalances.forEach((pre: any) => { + const post = postTokenBalances.find( + (p: any) => p.accountIndex === pre.accountIndex + ); + + // Skip if we already processed this account + if (post) return; + + const owner = pre.owner; + const mint = pre.mint; + const preRawAmount = 0; + const postRawAmount = Number(pre.uiTokenAmount.amount); + const rawDiff = postRawAmount - preRawAmount; + const diff = Math.abs(rawDiff); + + if (diff !== 0) { + if (!tokenBalanceChange[owner]) tokenBalanceChange[owner] = {}; + tokenBalanceChange[owner][mint] = { + amount: diff, + mint, + sign: '-', // Always negative since the account was closed/emptied + }; + } + }); + + return { solBalanceChange, tokenBalanceChange }; +} diff --git a/src/utils/solana/programs.ts b/src/utils/solana/programs.ts new file mode 100644 index 00000000..cc2bc6a7 --- /dev/null +++ b/src/utils/solana/programs.ts @@ -0,0 +1,49 @@ +export const SOL_MINT = `So11111111111111111111111111111111111111112`; + +// SPL Token Program IDs +export const SPL_TOKEN_PROGRAM_ID = + 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'; +export const SPL_TOKEN_2022_PROGRAM_ID = + 'TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb'; +export const SPL_TOKEN_PROGRAMS = [ + SPL_TOKEN_PROGRAM_ID, + SPL_TOKEN_2022_PROGRAM_ID, +]; + +export const BPF_LOADER_PROGRAM_ID = + 'BPFLoaderUpgradeab1e11111111111111111111111'; + +export const JITO_TIP_ACCOUNTS = [ + '96gYZGLnJYVFmbjzopPSU6QiEV5fGqZNyN9nmNhvrZU5', + 'HFqU5x63VTqvQss8hp11i4wVV8bD44PvwucfZ2bU7gRe', + 'Cw8CFyM9FkoMi7K7Crf6HNQqf4uEMzpKw6QNghXLvLkY', + 'ADaUMid9yfUytqMBgopwjb2DTLSokTSzL1zt6iGPaS49', + 'DfXygSm4jCyNCybVYYK6DwvWqjKee8pbDmJGcLWNDXjh', + 'ADuUkR4vqLUMWXxW9gh6D6L8pMSawimctcNZ5pGwDcEt', + 'DttWaMuVvTiduZRnguLF7jNxTgiMBZ1hyAumKUiL2KRL', + '3AVi9Tg9Uo68tJfuvoKvqKNWKkC5wPdSSdeBnizKZ6jT', +]; + +export const SQUADS_V3_META = 'SMPL5bz5ERMdweouWrXtk3jmb6FnjZkWf7pHDsE6Zwz'; +export const SQUADS_V3 = 'SMPLecH534NA9acpos4G6x7uf3LWbCAwZQE9e8ZekMu'; + +export const SQUADS_V4 = 'SQDS4ep65T869zMMBKyuUq6aD6EgTu8psMjkvj52pCf'; + +// Helper to check if a string is potentially a Solana address (base58, 32-44 chars) +function isSolanaAddress(str: any): boolean { + const base58Regex = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/; + return typeof str === 'string' && base58Regex.test(str); +} + +export function getAddresses(info: any): string[] { + if (typeof info === 'string') { + return isSolanaAddress(info) ? [info] : []; + } + if (Array.isArray(info)) { + return info.flatMap(getAddresses); + } + if (info !== null && typeof info === 'object') { + return Object.values(info).flatMap(getAddresses); + } + return []; +} diff --git a/src/utils/solana/spl-actions.ts b/src/utils/solana/spl-actions.ts new file mode 100644 index 00000000..a17cf4d0 --- /dev/null +++ b/src/utils/solana/spl-actions.ts @@ -0,0 +1,7 @@ +import { SPL_TOKEN_PROGRAMS } from './programs'; + +export function extractSplActions(ixList: any[], ixType: string) { + return ixList + .filter((ix) => SPL_TOKEN_PROGRAMS.includes(ix.programId)) + .filter((e) => e.parsed?.info.type === ixType); +} diff --git a/src/utils/solana/tx-actions.ts b/src/utils/solana/tx-actions.ts new file mode 100644 index 00000000..ee6e5e90 --- /dev/null +++ b/src/utils/solana/tx-actions.ts @@ -0,0 +1,255 @@ +import { ISolanaTransaction } from '../../types/ISolanaBlock'; +import { JITO_TIP_ACCOUNTS, SOL_MINT, SQUADS_V3, SQUADS_V4 } from './programs'; +import { formatAmountToUsd } from '../../services/AssetManager'; + +export const isSquads = (p: string) => [SQUADS_V3, SQUADS_V4].includes(p); + +// Determine if log contains deployment and return program address +export function filterLogs(logs: any, prefix: string): string[] { + const programDeploymentLogs = logs.filter((l: string) => + l.startsWith(prefix) + ); + const newProgramIdList = programDeploymentLogs.map((l: string) => { + return l.split(' ').pop(); + }); + return newProgramIdList; +} + +// Determine if log contains set authority and return program address +export function extractSetAuthorityFromLog(logs: any): string | null { + const setAuthorityLog = logs.find((log: string) => + log.includes('New authority') + ); + + if (!setAuthorityLog) { + return null; + } + + // Extract the new authority from the log message + const parts = setAuthorityLog.split(' '); + return parts[parts.length - 1]; +} + +// Determine if log contains deployment and return program address +export function extractProgramUpgradedFromLog(logs: any): string | null { + const upgradeLog = logs.find((log: string) => + log.includes('Upgraded program') + ); + + if (!upgradeLog) { + return null; + } + + // Extract the program address from the log message + const parts = upgradeLog.split(' '); + return parts[parts.length - 1]; +} + +export function getErrorFromLog(logs: string[]) { + const errorList: any = logs + .map((l) => { + if (l.includes('Program') && l.includes('failed:')) { + const parts = l.split(/Program | failed:/); + const errorId = String( + parseInt(parts[2].split(' custom program error: ')[1]) + ); + return { + programId: parts[1], + errorId, + }; + } + }) + .filter(Boolean); + + return errorList; +} + +export function parseTxData(tx: ISolanaTransaction) { + const outer = tx.transaction.message.instructions || []; + const inner = tx.meta.innerInstructions || []; + const accounts = tx.transaction.message.accountKeys.map((e) => e.pubkey); + const signers = tx.transaction.message.accountKeys + .filter((e) => e.signer) + .map((e) => e.pubkey); + const txHash = tx.transaction.signatures[0]; + + return { inner, outer, accounts, txHash, signers }; +} + +// Raw transfer data — amounts are unscaled (lamports for SOL, raw token amounts for SPL) +export interface IRawTransfer { + from: string; + to: string; + amount: number; + mint: string; + id: string; +} + +// Enriched transfer with USD conversion and symbol +export interface ITransfer extends IRawTransfer { + symbol: string; + usd: number; + tokenUsdString: string; +} + +export function getTokenOwners(tx: any) { + const accountKeys: Record = Object.fromEntries( + tx.transaction.message.accountKeys.map((e: any, i: any) => { + return [i, e.pubkey]; + }) + ); + + const ownerMap: Record = {}; + + for (const tokenBalance of tx.meta.preTokenBalances) { + const tokenAccount = accountKeys[tokenBalance.accountIndex]; + ownerMap[tokenAccount] = tokenBalance.owner; + } + + for (const tokenBalance of tx.meta.postTokenBalances) { + const tokenAccount = accountKeys[tokenBalance.accountIndex]; + ownerMap[tokenAccount] = tokenBalance.owner; + } + + return ownerMap; +} + +export function getTransfers(tx: any): IRawTransfer[] { + const transfers: IRawTransfer[] = []; + + // Process outer instructions + const ownerMap = getTokenOwners(tx); + + for (let i = 0; i < tx.transaction.message.instructions.length; i++) { + const ix = tx.transaction.message.instructions[i]; + const obs = processTransferInstruction(ix, ownerMap); + transfers.push( + ...obs.map((e) => { + return { ...e, id: String(i + 1) }; + }) + ); + } + + // Process inner instructions + for (let j = 0; j < tx.meta.innerInstructions.length; j++) { + const ixObj = tx.meta.innerInstructions[j]; + for (let k = 0; k < ixObj.instructions.length; k++) { + const ix = ixObj.instructions[k]; + const obs = processTransferInstruction(ix, ownerMap); + transfers.push( + ...obs.map((e) => { + return { ...e, id: `${j + 1}.${k + 1}` }; + }) + ); + + if ( + ix.program === 'bpf-upgradeable-loader' && + ix.parsed.type === 'upgrade' + ) { + const { bufferAccount, spillAccount } = ix.parsed.info; + + const spillAccIndex = tx.transaction.message.accountKeys.findIndex( + (e: any) => e.pubkey === spillAccount + ); + + const spillAmount = + tx.meta.postBalances[spillAccIndex] - + tx.meta.preBalances[spillAccIndex]; + + transfers.push({ + from: bufferAccount, + to: spillAccount, + amount: spillAmount, + id: `${j + 1}.${k + 1}`, + mint: SOL_MINT, + }); + } + } + } + + return transfers; +} + +// Helper function to process a single instruction and extract raw transfer data +function processTransferInstruction( + ix: any, + ownerMap: Record +): Omit[] { + const observations: Omit[] = []; + + // Handle regular transfers + if (ix.parsed?.type === 'transfer') { + const parsed = ix.parsed?.info; + + if (parsed.tokenAmount) { + const sender = parsed.authority || parsed.owner || parsed.source; + const receiverTokenAccount = parsed.destination; + const receiverOwner = ownerMap[receiverTokenAccount]; + + // SPL token transfer + observations.push({ + from: sender, + to: receiverOwner || receiverTokenAccount, + amount: parsed.tokenAmount.amount, + mint: parsed.tokenAmount.mint, + }); + } else if (parsed.lamports) { + // SOL transfer + observations.push({ + from: parsed.source, + to: parsed.destination, + amount: parsed.lamports, + mint: SOL_MINT, + }); + } + } + + // Handle transferChecked + else if (ix.parsed?.type === 'transferChecked') { + const parsed = ix.parsed.info; + + if (parsed.tokenAmount) { + const sender = parsed.authority || parsed.source; + const receiverTokenAccount = parsed.destination; + const receiverOwner = ownerMap[receiverTokenAccount]; + // SPL token transfer (transferChecked) + observations.push({ + from: sender, + to: receiverOwner || receiverTokenAccount, + amount: parsed.tokenAmount.amount, + mint: parsed.mint, + }); + } + } + + return observations; +} + +// Enrich raw transfers with USD values and symbol via the AssetManager cache +export function enrichTransfers(transfers: IRawTransfer[]): ITransfer[] { + return transfers.map((t) => { + const { symbol, usd, tokenUsdString } = formatAmountToUsd({ + amount: t.amount, + mint: t.mint, + }); + return { ...t, symbol, usd, tokenUsdString }; + }); +} + +export function separateDust(transfers: ITransfer[]) { + const dust: ITransfer[] = []; + const nonDust: ITransfer[] = []; + const jitoTip: ITransfer[] = []; + + for (const transfer of transfers) { + if (JITO_TIP_ACCOUNTS.includes(transfer.to)) { + jitoTip.push(transfer); + } else if (transfer.usd < 1) { + dust.push(transfer); + } else { + nonDust.push(transfer); + } + } + + return { dust, nonDust, jitoTip }; +} diff --git a/src/utils/summary-helpers.ts b/src/utils/summary-helpers.ts new file mode 100644 index 00000000..6d3323a6 --- /dev/null +++ b/src/utils/summary-helpers.ts @@ -0,0 +1,192 @@ +/** + * Shared helpers for formatting summary custom attributes and grouped titles. + * Used by both V3 and V4 Squads trackers and the proposal service. + */ + +const DUST_PATTERN = /^\d+ lamports\(\$~0\)/; + +function isComputeBudget(summary: string): boolean { + return summary === 'Set Compute Budget'; +} + +function isDust(summary: string): boolean { + return DUST_PATTERN.test(summary); +} + +function isNoisySummary(summary: string): boolean { + return isComputeBudget(summary) || isDust(summary); +} + +/** + * Extract an action-type label from a summary string. + */ +function getActionType(summary: string): string { + if (/^Transfer /i.test(summary) || / sent /i.test(summary)) { + return 'Transfer'; + } + if ( + /^Update reserve config/i.test(summary) || + /^Reserve config update/i.test(summary) || + /^Tighten /i.test(summary) || + /^Raise /i.test(summary) || + /^Update (price feed|scope chain|TWAP|token name|max liquidation|liquidation (fee|threshold)|protocol (take rate|liquidation))/i.test( + summary + ) || + /^Update protocol /i.test(summary) || + /^Update custody config/i.test(summary) + ) { + return 'Config Update'; + } + if (/^Created a new reserve/i.test(summary)) return 'Init Reserve'; + if (/^Close token account/i.test(summary)) return 'Close Account'; + if (/^Program .+ upgraded/i.test(summary)) return 'Upgrade'; + if (/^Create new token account/i.test(summary)) return 'Token Account'; + if (/^(Remove|Add) member/i.test(summary) || /^(Remove|Add) /i.test(summary)) + return 'Member Change'; + if (/^Change threshold/i.test(summary)) return 'Threshold'; + if (/^Allocate /i.test(summary)) return 'Allocate'; + return 'Action'; +} + +interface SummaryEntry { + summary: string; + [key: string]: any; +} + +export interface CustomAttribute { + label: string; + value: string; + url?: string; + isHash?: boolean; +} + +/** + * Build custom attributes from a summary list. + * Filters noise (ComputeBudget, dust), collapses identical summaries, + * and uses action-type labels instead of "Ix N". + */ +export function buildSummaryCustomAttributes( + summaryList: SummaryEntry[], + inspectorUrl?: string, + isBatch = false +): CustomAttribute[] { + // Filter out noise + const filtered = summaryList.filter((e) => !isNoisySummary(e.summary)); + + if (filtered.length === 0 && inspectorUrl) { + return [{ label: 'Inspector', value: 'URL', url: inspectorUrl }]; + } + + // Group consecutive identical summaries + const groups: { summary: string; count: number; actionType: string }[] = []; + for (const entry of filtered) { + const last = groups[groups.length - 1]; + if (last && last.summary === entry.summary) { + last.count++; + } else { + groups.push({ + summary: entry.summary, + count: 1, + actionType: getActionType(entry.summary), + }); + } + } + + const attrList: CustomAttribute[] = []; + + if (isBatch) { + // For batch transactions, use "Tx N" labels on the filtered list + let txIndex = 1; + for (const entry of filtered) { + attrList.push({ + label: `Tx ${txIndex}`, + value: entry.summary, + }); + txIndex++; + } + } else { + // Use action-type labels with collapse + const typeCounters: Record = {}; + // Count how many groups per action type to decide if we need numbering + const typeTotals: Record = {}; + for (const g of groups) { + typeTotals[g.actionType] = (typeTotals[g.actionType] || 0) + 1; + } + + for (const group of groups) { + typeCounters[group.actionType] = + (typeCounters[group.actionType] || 0) + 1; + const needsNumber = typeTotals[group.actionType] > 1; + const label = needsNumber + ? `${group.actionType} ${typeCounters[group.actionType]}` + : group.actionType; + + if (group.count > 1) { + attrList.push({ + label, + value: `${group.count} ${group.actionType.toLowerCase()}s`, + }); + } else { + attrList.push({ + label, + value: group.summary, + }); + } + } + } + + if (inspectorUrl) { + attrList.push({ + label: 'Inspector', + value: 'URL', + url: inspectorUrl, + }); + } + + return attrList; +} + +/** + * Build a grouped title string from a summary list. + * Filters noise, groups by action type, and produces a concise title. + */ +export function buildGroupedTitle(summaryList: SummaryEntry[]): string { + const filtered = summaryList.filter((e) => !isNoisySummary(e.summary)); + + if (filtered.length === 0) { + // Fall back to original join if filtering removed everything + return summaryList.map((e) => e.summary).join(', '); + } + + // Group by action type + const typeGroups: Record = {}; + const typeOrder: string[] = []; + for (const entry of filtered) { + const type = getActionType(entry.summary); + if (!typeGroups[type]) { + typeGroups[type] = { summaries: [], type }; + typeOrder.push(type); + } + typeGroups[type].summaries.push(entry.summary); + } + + // If single group with single entry, use summary directly + if (typeOrder.length === 1) { + const group = typeGroups[typeOrder[0]]; + if (group.summaries.length === 1) { + return group.summaries[0]; + } + return `${group.summaries.length} ${group.type.toLowerCase()}s`; + } + + // Multiple groups: join with counts + return typeOrder + .map((type) => { + const group = typeGroups[type]; + if (group.summaries.length === 1) { + return `1 ${type.toLowerCase()}`; + } + return `${group.summaries.length} ${type.toLowerCase()}s`; + }) + .join(', '); +} diff --git a/src/utils/testing-helpers.ts b/src/utils/testing-helpers.ts new file mode 100644 index 00000000..8f9262bf --- /dev/null +++ b/src/utils/testing-helpers.ts @@ -0,0 +1,247 @@ +import { IAlertRule } from '../types/IAlertRule'; +import { ISubEvent } from '../types/IEvent'; +import { BlockProcessor, TickProcessor } from './processor'; +import { randomUUID } from 'crypto'; +import { dayjs } from './dayjs'; +import { mkdirSync, readFileSync, writeFileSync } from 'fs'; +import * as path from 'path'; +import { axios } from '../services/axios'; +import { INetwork } from '../types/INetwork'; +import { config } from 'dotenv'; +config({ + quiet: true, +}); + +/** Piscina worker config that loads src/worker.ts directly via ts-node (no dist build needed) */ +export const testWorkerFilename = path.join( + __dirname, + '..', + 'threadpool', + 'worker.ts' +); +export const testWorkerExecArgv = ['--require', 'ts-node/register']; + +export const createNewAlertRule = (rule: { + ruleType: string; + id?: string; + ruleGroupId?: string; + workspaceId?: string; + createdAt?: Date; + parameters?: any; + network?: INetwork; + severity?: string; + triggerMode?: string; +}): IAlertRule & { cache?: any } => { + if (!rule.ruleType) { + throw new Error( + 'You forget to set ruleType, this will result in unexpected behavior and the rule will be considered as successTransaction!' + ); + } + rule.id = rule.id || getNewId(); + rule.ruleGroupId = rule.ruleGroupId || getNewId(); + rule.workspaceId = rule.workspaceId || getNewId(); + rule.createdAt = rule.createdAt || new Date(); + rule.parameters = rule.parameters || {}; + rule.network = rule.network || 'osmosis-1'; + rule.severity = rule.severity || 'debug'; + rule.triggerMode = rule.triggerMode || 'BLOCK'; + + return rule as any; +}; + +export const getNewId = (): string => { + return `test-alert-rule-id-` + randomUUID(); +}; + +export const getTestTimestamp = ( + hours?: number | null, + minutes?: number | null, + seconds?: number | null +) => { + let t = dayjs(); + + if (hours) { + t = t.add(hours, 'hours'); + } + if (minutes) { + t = t.add(minutes, 'minutes'); + } + if (seconds) { + t = t.add(seconds, 'seconds'); + } + return t.toISOString(); +}; + +export async function runTickIterations( + mockRule: any, + testRangeSDK: any, + ITERATION_COUNT = 1 +) { + for (let i = 1; i <= ITERATION_COUNT; i++) { + const iteration = await testRangeSDK.assertRuleWithTick( + new Date().toISOString(), + mockRule + ); + console.log(`ITERATION ${i}`, iteration.length); + for (const e of iteration) { + console.dir(e, { depth: null }); + } + } +} + +const decoderHostMap: Record< + string, + { + host?: string; + token?: string; + urlFn: (host: string, height: string) => string; + } +> = { + solana: { + host: process.env.SOL_DECODER_HOST, + token: process.env.SOL_DECODER_TOKEN, + urlFn: (host, height) => `${host}/api/block/solana/slot/${height}`, + }, + eth: { + host: process.env.ETH_BLOCK_API_HOST, + token: process.env.EVM_BLOCK_API_TOKEN, + urlFn: (host, height) => `${host}/api/blocks/${height}`, + }, + arb1: { + host: process.env.ARB1_BLOCK_API_HOST, + token: process.env.EVM_BLOCK_API_TOKEN, + urlFn: (host, height) => `${host}/api/blocks/${height}`, + }, + bsc: { + host: process.env.BSC_BLOCK_API_HOST, + token: process.env.EVM_BLOCK_API_TOKEN, + urlFn: (host, height) => `${host}/api/blocks/${height}`, + }, + base: { + host: process.env.BASE_BLOCK_API_HOST, + token: process.env.EVM_BLOCK_API_TOKEN, + urlFn: (host, height) => `${host}/api/blocks/${height}`, + }, +}; + +async function downloadBlockFromDecoder(network: string, height: string) { + const decoder = decoderHostMap[network]; + + let url: string; + let token: string | undefined; + + if (decoder?.host) { + url = decoder.urlFn(decoder.host, height); + token = decoder.token ?? process.env.BLOCK_API_TOKEN; + } else { + url = `${process.env.BLOCK_API}/block?network=${network}&height=${height}`; + token = process.env.BLOCK_API_TOKEN; + } + + const response = await axios.get(url, { + headers: { + Authorization: `Bearer ${token}`, + }, + timeout: 30_000, + }); + + // Solana decoder wraps as { slot, block } — store only the block + const block = response.data?.block ?? response.data; + + const filePath = `src/test_data/${network}/${height}.json`; + writeFileSync(filePath, JSON.stringify(block)); + + return block; +} + +/** + * YAML-style logger for test output. Recursively prints objects with indentation. + * Uses process.stdout.write to bypass Jest's console interceptor. + */ +export function logYaml(obj: unknown, indent = 0, pick?: string[]): void { + const pad = ' '.repeat(indent); + if (Array.isArray(obj)) { + for (const item of obj) { + if (typeof item === 'object' && item !== null) { + const keys = Object.keys(item); + const filteredKeys = pick ? keys.filter((k) => pick.includes(k)) : keys; + if (filteredKeys.length > 0) { + process.stdout.write( + `${pad}- ${filteredKeys[0]}: ${formatValue(item[filteredKeys[0]])}\n` + ); + for (const key of filteredKeys.slice(1)) { + process.stdout.write(`${pad} ${key}: ${formatValue(item[key])}\n`); + if (typeof item[key] === 'object' && item[key] !== null) { + logYaml(item[key], indent + 4, pick); + } + } + } + } else { + process.stdout.write(`${pad}- ${item}\n`); + } + } + } else if (typeof obj === 'object' && obj !== null) { + const entries = Object.entries(obj); + for (const [key, value] of entries) { + if (pick && !pick.includes(key)) continue; + if (typeof value === 'object' && value !== null) { + process.stdout.write(`${pad}${key}:\n`); + logYaml(value, indent + 2, pick); + } else { + process.stdout.write(`${pad}${key}: ${value}\n`); + } + } + } else { + process.stdout.write(`${pad}${obj}\n`); + } +} + +function formatValue(v: unknown): string { + if (typeof v === 'object' && v !== null) return ''; + return String(v); +} + +export async function getCachedBlock(network: string, height: string) { + try { + const filePath = path.join('src/test_data', network, `${height}.json`); + return JSON.parse(readFileSync(filePath, 'utf8')); + } catch { + console.log(`${network} ${height} downloading...`); + const dir = path.join('src/test_data', network); + mkdirSync(dir, { recursive: true }); + const block = await downloadBlockFromDecoder(network, height); + console.log(`${network} ${height} downloaded`); + return block; + } +} + +/** + * Lightweight processor test harness. Runs a processor's callback + * directly without Redis, thread pool, or block stream. + */ +export async function testProcessor(opts: { + processorClass: new () => BlockProcessor | TickProcessor; + rule: Partial> & { ruleType: string }; + block?: any; + timestamp?: string; +}): Promise { + const instance = new opts.processorClass(); + const alertRule = createNewAlertRule(opts.rule as any); + + if (instance.taskType === 'BLOCK') { + return (instance as BlockProcessor).callback({ + block: opts.block, + rule: alertRule, + }); + } + + if (instance.taskType === 'TICK') { + const ts = opts.timestamp || new Date().toISOString(); + return (instance as TickProcessor).callback({ + timestamp: ts, + rule: alertRule, + }); + } + + throw new Error(`Unknown taskType: ${(instance as any).taskType}`); +} diff --git a/src/utils/toBuffer.ts b/src/utils/toBuffer.ts deleted file mode 100644 index 1d36eb02..00000000 --- a/src/utils/toBuffer.ts +++ /dev/null @@ -1,3 +0,0 @@ -export function toBuffer(obj: any) { - return Buffer.from(JSON.stringify(obj)); -} diff --git a/src/utils/updateRuleParamsInterface.ts b/src/utils/updateRuleParamsInterface.ts new file mode 100644 index 00000000..dbf0289b --- /dev/null +++ b/src/utils/updateRuleParamsInterface.ts @@ -0,0 +1,25 @@ +import { FieldTypeToTSType, IRule } from '../types/IRule'; +import * as fs from 'fs'; + +export function updateRuleParamsInterface(rule: IRule) { + const name = getInterfaceName(rule.type); + const fields = rule.parameters.map(getTypeDefinition); + const content = `export interface ${name} {\n${fields.map((f) => ` ${f}\n`).join('')}}\n`; + const path = `${__dirname}/../../src/types/rules/${name}.ts`; + try { + const old = fs.readFileSync(path, 'utf8'); + if (old !== content) { + throw new Error('Different content'); + } + } catch (_e) { + fs.writeFileSync(path, content); + } +} + +function getInterfaceName(ruleType: string) { + return `I${ruleType.charAt(0).toUpperCase()}${ruleType.slice(1).replace(/[^A-Za-z0-9]/g, '')}Params`; +} + +function getTypeDefinition(param: IRule['parameters'][0]): string { + return `${param.field}${param.optional ? '?' : ''}: ${FieldTypeToTSType[param.fieldType]};`; +} diff --git a/src/utils/validParam.ts b/src/utils/validParam.ts new file mode 100644 index 00000000..c8752d1c --- /dev/null +++ b/src/utils/validParam.ts @@ -0,0 +1,56 @@ +export type StringParam = string | string[] | undefined; + +export function validParam(input: any, ruleParam: StringParam): boolean { + if (!ruleParam) return true; + + if (Array.isArray(ruleParam) && !Array.isArray(input)) { + if (ruleParam.length === 0) return true; + return ruleParam.includes(input); + } + + if (Array.isArray(ruleParam) && Array.isArray(input)) { + if (ruleParam.length === 0) return true; + return ruleParam.some((param) => input.includes(param)); + } + + if (!Array.isArray(ruleParam) && Array.isArray(input)) { + return input.includes(ruleParam); + } + + return input === ruleParam; +} + +export function invalidParam(a: any, b: any) { + return !validParam(a, b); +} + +export type NumberParam = number | undefined; + +export function validGreaterThan(input: any, threshold: any) { + if (!threshold) return true; + + return Number(input) > Number(threshold); +} + +export function invalidGreaterThan(input: any, threshold: any) { + return !validGreaterThan(input, threshold); +} + +export function validSubString(input: any, param: any) { + if (!param) return true; + + return input.includes(param); +} + +export function isSmallerThan(input: any, threshold: any) { + if (!threshold) return true; + + return Number(input) < Number(threshold); +} + +export function isNotSmallerThan(input: any, threshold: any) { + return !isSmallerThan(input, threshold); +} + +export const isGreaterThan = validGreaterThan; +export const isNotGreaterThan = invalidGreaterThan; diff --git a/src/utils/validateParameters.ts b/src/utils/validateParameters.ts new file mode 100644 index 00000000..31f9fe03 --- /dev/null +++ b/src/utils/validateParameters.ts @@ -0,0 +1,85 @@ +import { FieldTypeToTSType, IRule } from '../types/IRule'; + +function getType(value: any) { + if (typeof value === 'number') { + return 'number'; + } else if ( + Array.isArray(value) && + value.every((item) => typeof item === 'number') + ) { + return 'number[]'; + } else if (typeof value === 'string') { + return 'string'; + } else if ( + Array.isArray(value) && + value.every((item) => typeof item === 'string') + ) { + return 'string[]'; + } else if (typeof value === 'boolean') { + return 'boolean'; + } else { + return 'unknown'; // for cases that don't match + } +} + +/** + * Validates and ensures rule parameters match their defined types from Alert Template documentation + * @recommended "Strongly recommended for new rules" + */ +function ensureRuleParams(params: any, cb: any): T { + const result = {} as any; + const rule = (cb as any).__rule as IRule; + + if (!rule) { + throw new Error(`No rule annotation found for ${cb.constructor.name}`); + } + + for (const definition of rule.parameters) { + const value = params[definition.field]; + + if (definition.optional && value === undefined) { + continue; + } + if (value === undefined) { + throw new Error(`Missing required field ${definition.field}`); + } + if (getType(value) !== FieldTypeToTSType[definition.fieldType]) { + console.error( + `invalid param field data for ${typeof value} ${value} for ${definition.field}!` + ); + continue; + } + + result[definition.field] = value; + } + return result; +} + +import 'reflect-metadata'; + +export function ValidateParameters() { + return function ( + target: any, + propertyKey: string, + descriptor: PropertyDescriptor + ) { + const originalMethod = descriptor.value; + + descriptor.value = function (...args: any[]) { + const rule = args[0]?.rule; + if (!rule) { + throw new Error('Rule is required'); + } + + // Assuming the first argument is the context object containing rule + const params = ensureRuleParams(rule.parameters, this); + + // Add params to the context or modify args as needed + args[0].params = params; + + return originalMethod.apply(this, args); + }; + + return descriptor; + }; +} diff --git a/src/wrappers/solana-block-wrapper.ts b/src/wrappers/solana-block-wrapper.ts new file mode 100644 index 00000000..aab0701f --- /dev/null +++ b/src/wrappers/solana-block-wrapper.ts @@ -0,0 +1,531 @@ +import * as flatbuffers from 'flatbuffers'; +import { SolanaBlock } from '../flatbuffers/solana/block/solana-block'; +import { SolanaBlockT } from '../flatbuffers/solana/block/solana-block'; +import { Message } from '../flatbuffers/solana/block/message'; +import { SolanaTransactionT } from '../flatbuffers/solana/block/solana-transaction'; +import { + TransactionT, + Transaction, +} from '../flatbuffers/solana/block/transaction'; +import { + TransactionMetaT, + TransactionMeta, +} from '../flatbuffers/solana/block/transaction-meta'; +import { MessageT } from '../flatbuffers/solana/block/message'; +import { + InstructionT, + Instruction, +} from '../flatbuffers/solana/block/instruction'; +import { InnerInstructionT } from '../flatbuffers/solana/block/inner-instruction'; +import { TokenBalanceT } from '../flatbuffers/solana/block/token-balance'; +import { UiTokenAmountT } from '../flatbuffers/solana/block/ui-token-amount'; +import { AccountKeyT } from '../flatbuffers/solana/block/account-key'; +import { BlockDataT } from '../flatbuffers/solana/block/block-data'; + +export class SolanaBlockWrapper { + private block: SolanaBlock; + + constructor(buffer: Uint8Array) { + const bb = new flatbuffers.ByteBuffer(buffer); + this.block = SolanaBlock.getRootAsSolanaBlock(bb); + } + + get height(): number { + return Number(this.block.height() || 0); + } + get network(): string { + return this.block.network() || ''; + } + + get timestamp(): number { + return Number(this.block.timestamp() || 0); + } + + get hash(): number { + return Number(this.block.hash || 0); + } + + get block_data() { + const bd = this.block.blockData(); + if (!bd) return null; + + return { + slot: bd.slot() || '', + parentSlot: bd.parentSlot() || '', + previousBlockhash: bd.previousBlockhash() || '', + maliciousAddresses: this.getStringArray( + bd.maliciousAddressesLength(), + (i) => bd.maliciousAddresses(i) + ), + sanctionedAddresses: this.getStringArray( + bd.sanctionedAddressesLength(), + (i) => bd.sanctionedAddresses(i) + ), + blacklistedAddresses: this.getStringArray( + bd.blacklistedAddressesLength(), + (i) => bd.blacklistedAddresses(i) + ), + }; + } + + get transactions() { + const txs: any[] = []; + for (let i = 0; i < this.block.transactionsLength(); i++) { + const solanaTx = this.block.transactions(i)!; + const tx = solanaTx.transaction()!; + const msg = tx.message()!; + const meta = solanaTx.meta()!; + + txs.push({ + transaction: { + signatures: this.getStringArray(tx.signaturesLength(), (i) => + tx.signatures(i) + ), + message: { + accountKeys: this.getAccountKeys(msg), + instructions: this.getInstructions(msg), + }, + }, + meta: { + fee: Number(meta.fee()), + computeUnitsConsumed: Number(meta.computeUnitsConsumed()), + logMessages: this.getStringArray(meta.logMessagesLength(), (i) => + meta.logMessages(i) + ), + preTokenBalances: this.getTokenBalances( + meta.preTokenBalancesLength(), + (i) => meta.preTokenBalances(i) + ), + postTokenBalances: this.getTokenBalances( + meta.postTokenBalancesLength(), + (i) => meta.postTokenBalances(i) + ), + preBalances: this.getBalances(meta.preBalancesLength(), (i) => + meta.preBalances(i) + ), + postBalances: this.getBalances(meta.postBalancesLength(), (i) => + meta.postBalances(i) + ), + innerInstructions: this.getInnerInstructions(meta), + }, + }); + } + return txs; + } + + private getAccountKeys(msg: Message) { + const keys: any[] = []; + for (let i = 0; i < msg.accountKeysLength(); i++) { + const key = msg.accountKeys(i)!; + keys.push({ + pubkey: key.pubkey() || '', + signer: key.signer(), + writable: key.writable(), + source: key.source() || '', + }); + } + return keys; + } + + private getInstructions(msg: Message) { + const insts: any[] = []; + for (let i = 0; i < msg.instructionsLength(); i++) { + const inst = msg.instructions(i)!; + insts.push({ + programId: inst.programId() || '', + program: inst.program() || '', + data: inst.data() || '', + parsed: this.safeParse(inst.parsed()), + accounts: this.getStringArray(inst.accountsLength(), (j) => + inst.accounts(j) + ), + }); + } + return insts; + } + + private getStringArray( + len: number, + getter: (i: number) => string | null + ): string[] { + const result: string[] = []; + for (let i = 0; i < len; i++) { + result.push(getter(i) || ''); + } + return result; + } + + private getTokenBalances( + len: number, + getter: (i: number) => any | null + ): any[] { + const result: any[] = []; + for (let i = 0; i < len; i++) { + const tokenBalance = getter(i); + if (tokenBalance) { + result.push({ + accountIndex: tokenBalance.accountIndex(), + mint: tokenBalance.mint() || '', + owner: tokenBalance.owner() || '', + programId: tokenBalance.programId() || '', + uiTokenAmount: { + amount: tokenBalance.uiTokenAmount()?.amount() || '0', + decimals: tokenBalance.uiTokenAmount()?.decimals() || 0, + uiAmount: tokenBalance.uiTokenAmount()?.uiAmount() || 0, + uiAmountString: + tokenBalance.uiTokenAmount()?.uiAmountString() || '0', + }, + }); + } + } + return result; + } + + private getBalances( + len: number, + getter: (i: number) => bigint | null + ): number[] { + const result: number[] = []; + for (let i = 0; i < len; i++) { + const balance = getter(i); + result.push(balance ? Number(balance) : 0); + } + return result; + } + + private getInnerInstructions(meta: any): any[] { + const result: any[] = []; + for (let i = 0; i < meta.innerInstructionsLength(); i++) { + const innerIx = meta.innerInstructions(i); + if (innerIx) { + const instructions: any[] = []; + for (let j = 0; j < innerIx.instructionsLength(); j++) { + const inst = innerIx.instructions(j); + if (inst) { + instructions.push({ + programId: inst.programId() || '', + program: inst.program() || '', + data: inst.data() || '', + parsed: this.safeParse(inst.parsed()), + accounts: this.getStringArray(inst.accountsLength(), (k) => + inst.accounts(k) + ), + }); + } + } + result.push({ + index: innerIx.index(), + instructions, + }); + } + } + return result; + } + + private safeParse(json?: string | null) { + if (!json) return null; + try { + return JSON.parse(json); + } catch { + return null; + } + } +} + +function convertJsonTokenBalanceToT(tb: any): TokenBalanceT { + const tokenBalanceT = new TokenBalanceT(); + tokenBalanceT.accountIndex = tb.accountIndex ?? 0; + tokenBalanceT.mint = tb.mint || ''; + tokenBalanceT.owner = tb.owner || ''; + tokenBalanceT.programId = tb.programId || ''; + if (tb.uiTokenAmount) { + const uiT = new UiTokenAmountT(); + uiT.amount = tb.uiTokenAmount.amount || '0'; + uiT.decimals = tb.uiTokenAmount.decimals || 0; + uiT.uiAmount = tb.uiTokenAmount.uiAmount || 0; + uiT.uiAmountString = tb.uiTokenAmount.uiAmountString || '0'; + tokenBalanceT.uiTokenAmount = uiT; + } + return tokenBalanceT; +} + +function convertJsonTransactionToT(jsonTx: any): SolanaTransactionT { + // Create TransactionT with custom pack method to handle string arrays properly + const transactionT = new TransactionT(); + if (jsonTx.transaction?.signatures) { + transactionT.signatures = jsonTx.transaction.signatures; + } + + // Override the pack method to handle string arrays correctly + transactionT.pack = function ( + builder: flatbuffers.Builder + ): flatbuffers.Offset { + const message = this.message !== null ? this.message!.pack(builder) : 0; + // Create string offsets for signatures array + const signatureOffsets = this.signatures.map((sig: string) => + builder.createString(sig) + ); + const signatures = Transaction.createSignaturesVector( + builder, + signatureOffsets + ); + return Transaction.createTransaction(builder, message, signatures); + }; + + // Create MessageT with instructions + if (jsonTx.transaction?.message) { + const messageT = new MessageT(); + + // Convert instructions + if (jsonTx.transaction.message.instructions) { + messageT.instructions = jsonTx.transaction.message.instructions.map( + (ix: any) => { + const instructionT = new InstructionT(); + instructionT.programId = ix.programId || ''; + instructionT.program = ix.program || ix.programId || ''; + instructionT.data = ix.data || ''; + instructionT.parsed = ix.parsed ? JSON.stringify(ix.parsed) : ''; + instructionT.accounts = ix.accounts || []; + instructionT.stackHeight = ix.stackHeight || 0; + + // Override pack method for instruction to handle accounts string array + instructionT.pack = function ( + builder: flatbuffers.Builder + ): flatbuffers.Offset { + const parsed = + this.parsed !== null ? builder.createString(this.parsed!) : 0; + const programId = + this.programId !== null + ? builder.createString(this.programId!) + : 0; + const program = + this.program !== null ? builder.createString(this.program!) : 0; + // Create string offsets for accounts array + const accountOffsets = this.accounts.map((acc: string) => + builder.createString(acc) + ); + const accounts = Instruction.createAccountsVector( + builder, + accountOffsets + ); + const data = + this.data !== null ? builder.createString(this.data!) : 0; + + return Instruction.createInstruction( + builder, + parsed, + programId, + program, + accounts, + data, + this.stackHeight + ); + }; + + return instructionT; + } + ); + } + + // Convert account keys + if (jsonTx.transaction.message.accountKeys) { + messageT.accountKeys = jsonTx.transaction.message.accountKeys.map( + (key: any) => { + const accountKeyT = new AccountKeyT(); + accountKeyT.pubkey = key.pubkey || ''; + accountKeyT.signer = key.signer || false; + accountKeyT.writable = key.writable || false; + accountKeyT.source = key.source || ''; + return accountKeyT; + } + ); + } + + transactionT.message = messageT; + } + + // Create TransactionMetaT with custom pack method + const metaT = new TransactionMetaT(); + if (jsonTx.meta?.fee) { + metaT.fee = BigInt(jsonTx.meta.fee); + } + if (jsonTx.meta?.computeUnitsConsumed) { + metaT.computeUnitsConsumed = BigInt(jsonTx.meta.computeUnitsConsumed); + } + if (jsonTx.meta?.logMessages) { + metaT.logMessages = jsonTx.meta.logMessages; + } + if (jsonTx.meta?.err) { + metaT.err = JSON.stringify(jsonTx.meta.err); + } + if (jsonTx.meta?.preBalances) { + metaT.preBalances = jsonTx.meta.preBalances.map((b: any) => BigInt(b)); + } + if (jsonTx.meta?.postBalances) { + metaT.postBalances = jsonTx.meta.postBalances.map((b: any) => BigInt(b)); + } + if (jsonTx.meta?.preTokenBalances) { + metaT.preTokenBalances = jsonTx.meta.preTokenBalances.map((tb: any) => + convertJsonTokenBalanceToT(tb) + ); + } + if (jsonTx.meta?.postTokenBalances) { + metaT.postTokenBalances = jsonTx.meta.postTokenBalances.map((tb: any) => + convertJsonTokenBalanceToT(tb) + ); + } + if (jsonTx.meta?.innerInstructions) { + metaT.innerInstructions = jsonTx.meta.innerInstructions.map( + (group: any) => { + const innerT = new InnerInstructionT(); + innerT.index = group.index ?? 0; + innerT.instructions = (group.instructions || []).map((ix: any) => { + const instructionT = new InstructionT(); + instructionT.programId = ix.programId || ''; + instructionT.program = ix.program || ix.programId || ''; + instructionT.data = ix.data || ''; + instructionT.parsed = ix.parsed ? JSON.stringify(ix.parsed) : ''; + instructionT.accounts = ix.accounts || []; + instructionT.stackHeight = ix.stackHeight || 0; + + // Override pack method for instruction to handle accounts string array + instructionT.pack = function ( + builder: flatbuffers.Builder + ): flatbuffers.Offset { + const parsed = + this.parsed !== null ? builder.createString(this.parsed!) : 0; + const programId = + this.programId !== null + ? builder.createString(this.programId!) + : 0; + const program = + this.program !== null ? builder.createString(this.program!) : 0; + const accountOffsets = this.accounts.map((acc: string) => + builder.createString(acc) + ); + const accounts = Instruction.createAccountsVector( + builder, + accountOffsets + ); + const data = + this.data !== null ? builder.createString(this.data!) : 0; + + return Instruction.createInstruction( + builder, + parsed, + programId, + program, + accounts, + data, + this.stackHeight + ); + }; + + return instructionT; + }); + return innerT; + } + ); + } + + // Override pack method to handle logMessages string array + metaT.pack = function (builder: flatbuffers.Builder): flatbuffers.Offset { + const err = this.err !== null ? builder.createString(this.err!) : 0; + const innerInstructions = TransactionMeta.createInnerInstructionsVector( + builder, + builder.createObjectOffsetList(this.innerInstructions) + ); + // Create string offsets for logMessages array + const logMessageOffsets = this.logMessages.map((msg: string) => + builder.createString(msg) + ); + const logMessages = TransactionMeta.createLogMessagesVector( + builder, + logMessageOffsets + ); + const preBalances = TransactionMeta.createPreBalancesVector( + builder, + this.preBalances + ); + const postBalances = TransactionMeta.createPostBalancesVector( + builder, + this.postBalances + ); + const preTokenBalances = TransactionMeta.createPreTokenBalancesVector( + builder, + builder.createObjectOffsetList(this.preTokenBalances) + ); + const postTokenBalances = TransactionMeta.createPostTokenBalancesVector( + builder, + builder.createObjectOffsetList(this.postTokenBalances) + ); + + return TransactionMeta.createTransactionMeta( + builder, + this.computeUnitsConsumed, + err, + this.fee, + innerInstructions, + logMessages, + preBalances, + postBalances, + preTokenBalances, + postTokenBalances + ); + }; + + // Create SolanaTransactionT + return new SolanaTransactionT(transactionT, metaT); +} + +export function createSolanaBlockFromJson(jsonData: any): Uint8Array { + const blockT = new SolanaBlockT(); + + // Manually populate SolanaBlockT from JSON data + if (jsonData.height) blockT.height = jsonData.height; + if (jsonData.hash) blockT.hash = jsonData.hash; + if (jsonData.timestamp) blockT.timestamp = jsonData.timestamp; + if (jsonData.network) blockT.network = jsonData.network; + + // Handle blockData + if (jsonData.blockData) { + const blockDataT = new BlockDataT(); + blockDataT.slot = jsonData.blockData.slot || ''; + blockDataT.parentSlot = jsonData.blockData.parentSlot || ''; + blockDataT.previousBlockhash = jsonData.blockData.previousBlockhash || ''; + blockDataT.maliciousAddresses = jsonData.blockData.maliciousAddresses || []; + blockDataT.sanctionedAddresses = + jsonData.blockData.sanctionedAddresses || []; + blockDataT.blacklistedAddresses = + jsonData.blockData.blacklistedAddresses || []; + blockT.blockData = blockDataT; + } + + if (jsonData.transactions) { + blockT.transactions = jsonData.transactions.map(convertJsonTransactionToT); + } + + // Estimate buffer size more accurately to reduce allocations + // Base size + estimated size per transaction + const estimatedSize = Math.max( + 1024, // Minimum size + Math.min( + 100 * 1024 * 1024, // Maximum 100MB + 1024 + (jsonData.transactions?.length || 0) * 2048 // 2KB per transaction estimate + ) + ); + + // Create FlatBuffer builder with estimated size + const builder = new flatbuffers.Builder(estimatedSize); + + // Pack the object into FlatBuffer + const blockOffset = blockT.pack(builder); + + // Finish the buffer + builder.finish(blockOffset); + + // Return the buffer as Uint8Array + return builder.asUint8Array(); +} + +export const convertSolanaBlockJsonToBuffer = createSolanaBlockFromJson; diff --git a/tests/cosmosClient.ts b/tests/cosmosClient.ts deleted file mode 100644 index cd6e27ee..00000000 --- a/tests/cosmosClient.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { CosmosClient } from '../src/cosmos/CosmosClient'; - -async function main() { - const rpcEndpoint = ''; - const client = new CosmosClient(rpcEndpoint); - - console.assert( - await client.balance( - 'osmo1ql5dgyyeqnvljg0l8xl986j5zxwjaskg24nztq', - 'uosmo', - ), - ); - - console.assert( - await client.validator( - 'osmovaloper1clpqr4nrk4khgkxj78fcwwh6dl3uw4ep88n0y4', - ), - ); - - console.assert(await client.supply('uosmo')); - - console.assert( - await client.contractInfo( - 'osmo1mypljhatv0prfr9cjzzvamxdf2ctg34xkt50sudxads9zhqnyneqjuvy26', - ), - ); - - console.assert( - await client.fetchContractQuery( - 'osmo1lqyn9ncwkcqj8e0pnugu72tyyfehe2tre98c5qfzjg4d3vdw7n5q5a0x37', - { - list_proposals: {}, - }, - ), - ); - console.assert(await client.fetchLatestHeight()); - - console.assert(await client.getValidators()); -} -main(); diff --git a/tests/env.ts b/tests/env.ts deleted file mode 100644 index e9fdbe7b..00000000 --- a/tests/env.ts +++ /dev/null @@ -1,4 +0,0 @@ -export const test_env = { - KAFKA_TOPIC: 'range-task-topic', - KAFKA_BROKER: 'localhost:9092', -}; diff --git a/tests/pushBlock.ts b/tests/pushBlock.ts deleted file mode 100644 index d867f484..00000000 --- a/tests/pushBlock.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { Kafka, Partitioners } from 'kafkajs'; -import { test_env } from './env'; - -async function main() { - const kafka = new Kafka({ - clientId: 'test-pusher', - brokers: [test_env.KAFKA_BROKER], - }); - - const producer = kafka.producer({ - createPartitioner: Partitioners.LegacyPartitioner, - }); - await producer.connect(); - - const task = { - block: { - height: '1', - network: 'osmosis-1', - }, - ruleGroupId: '1', - }; - - await producer.send({ - topic: test_env.KAFKA_TOPIC, - messages: [ - { - value: JSON.stringify(task), - }, - ], - }); - - await producer.disconnect(); - - console.log('Successfully published task: ', task); -} -main(); diff --git a/tests/testBlock.ts b/tests/testBlock.ts deleted file mode 100644 index 2c644d6a..00000000 --- a/tests/testBlock.ts +++ /dev/null @@ -1,78 +0,0 @@ -export const block = { - hash: '7DBAC837D89155ABFC734E62A65D26AA47CDEB39A5822D829EC8AEF7AEC2BE4E', - height: '1740053', - network: 'osmosis-1', - timestamp: '2023-07-18T18:38:24.244Z', - transactions: [ - { - hash: 'CB2DAD664569B9D48BD592C11722032273FB6D3EDDBF0B319D67B805B03ED2FD', - logs: [], - height: '1740038', - success: true, - messages: [ - { - hash: 'CB2DAD664569B9D48BD592C11722032273FB6D3EDDBF0B319D67B805B03ED2FD', - type: 'cosmwasm.wasm.v1.MsgExecuteContract', - value: { - msg: { - send: { - msg: 'eyJvcGVuX3Bvc2l0aW9uIjp7InNsaXBwYWdlX2Fzc2VydCI6bnVsbCwibGV2ZXJhZ2UiOiI1IiwiZGlyZWN0aW9uIjoic2hvcnQiLCJtYXhfZ2FpbnMiOiIyIiwic3RvcF9sb3NzX292ZXJyaWRlIjpudWxsLCJ0YWtlX3Byb2ZpdF9vdmVycmlkZSI6bnVsbH19', - amount: '140000000', - contract: - 'osmo1vhg6h7mp04dwm0wxeemyarg0g9nktcgpg9xrcmca8y5ulwd00dzsvvy4r5', - }, - }, - funds: [], - sender: 'osmo1s6jghp8g388v78dwz0k6nt09yftggwpxlzwfrj', - contract: - 'osmo1g68w56vq9q0vr2mdlzp2l80j0lelnffkn7y3zhek5pavtxzznuks8wkv6k', - }, - height: '1740038', - addresses: ['osmo1s6jghp8g388v78dwz0k6nt09yftggwpxlzwfrj'], - }, - ], - }, - { - hash: 'CB2DAD664569B9D48BD592C11722032273FB6D3EDDBF0B319D67B805B03ED2FD', - logs: [], - height: '1740038', - success: false, - messages: [ - { - hash: 'CB2DAD664569B9D48BD592C11722032273FB6D3EDDBF0B319D67B805B03ED2FD', - type: 'cosmwasm.wasm.v1.MsgExecuteContract', - value: { - msg: { - send: { - msg: 'eyJvcGVuX3Bvc2l0aW9uIjp7InNsaXBwYWdlX2Fzc2VydCI6bnVsbCwibGV2ZXJhZ2UiOiI1IiwiZGlyZWN0aW9uIjoic2hvcnQiLCJtYXhfZ2FpbnMiOiIyIiwic3RvcF9sb3NzX292ZXJyaWRlIjpudWxsLCJ0YWtlX3Byb2ZpdF9vdmVycmlkZSI6bnVsbH19', - amount: '140000000', - contract: - 'osmo1vhg6h7mp04dwm0wxeemyarg0g9nktcgpg9xrcmca8y5ulwd00dzsvvy4r5', - }, - }, - funds: [], - sender: 'osmo1s6jghp8g388v78dwz0k6nt09yftggwpxlzwfrj', - contract: - 'osmo1g68w56vq9q0vr2mdlzp2l80j0lelnffkn7y3zhek5pavtxzznuks8wkv6k', - }, - height: '1740038', - addresses: ['osmo1s6jghp8g388v78dwz0k6nt09yftggwpxlzwfrj'], - }, - { - hash: 'CB2DAD664569B9D48BD592C11722032273FB6D3EDDBF0B319D67B805B03ED2FD', - type: 'cosmos.bank.v1beta1.MsgSend', - value: { - amount: [{ denom: 'uosmo', amount: '380000000' }], - to_address: 'osmo129uhlqcsvmehxgzcsdxksnsyz94dvea907e575', - from_address: 'osmo1rdcknhy6g90ueuwd7kzepuzv06dkgm8wh25ljc', - }, - height: '1740038', - addresses: [ - 'osmo129uhlqcsvmehxgzcsdxksnsyz94dvea907e575', - 'osmo1rdcknhy6g90ueuwd7kzepuzv06dkgm8wh25ljc', - ], - }, - ], - }, - ], -}; diff --git a/tsconfig.json b/tsconfig.json index 8e368af9..10919391 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,16 +1,26 @@ { "compilerOptions": { - "target": "ES2021", - "lib": ["ES2021"], "module": "commonjs", + "declaration": true, + "removeComments": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "target": "ES2022", + "sourceMap": true, "outDir": "./dist", - "rootDir": ".", - "strict": true, + "rootDir": "./src", + "baseUrl": "./", + "incremental": true, "skipLibCheck": true, - "typeRoots": ["node_modules/@types", "types"], - "types": ["node"], - "esModuleInterop": true, - "resolveJsonModule": true + "strictNullChecks": true, + "noImplicitAny": true, + "strictBindCallApply": false, + "forceConsistentCasingInFileNames": false, + "noFallthroughCasesInSwitch": false, + "resolveJsonModule": true, + "types": ["node"] }, - "include": ["src", "package.json", "examples/*"] + "exclude": ["dist", "example", "src/benchmarking", "push-event.ts", "**/*.spec.ts", "**/*.test.ts", "jest.config.ts"] } diff --git a/tsconfig.test.json b/tsconfig.test.json new file mode 100644 index 00000000..5a894bfe --- /dev/null +++ b/tsconfig.test.json @@ -0,0 +1,7 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "types": ["node", "jest"] + }, + "include": ["src"] +} diff --git a/yarn.lock b/yarn.lock index c92561e5..4134f5dd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,22 +2,305 @@ # yarn lockfile v1 -"@aashutoshrathi/word-wrap@^1.2.3": - version "1.2.6" - resolved "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz" - integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== +"@adraffy/ens-normalize@1.10.1": + version "1.10.1" + resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz#63430d04bd8c5e74f8d7d049338f1cd9d4f02069" + integrity sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw== + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.27.1", "@babel/code-frame@^7.28.6", "@babel/code-frame@^7.29.0": + version "7.29.0" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.29.0.tgz#7cd7a59f15b3cc0dcd803038f7792712a7d0b15c" + integrity sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw== + dependencies: + "@babel/helper-validator-identifier" "^7.28.5" + js-tokens "^4.0.0" + picocolors "^1.1.1" + +"@babel/compat-data@^7.28.6": + version "7.29.0" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.29.0.tgz#00d03e8c0ac24dd9be942c5370990cbe1f17d88d" + integrity sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg== + +"@babel/core@^7.23.9", "@babel/core@^7.27.4": + version "7.29.0" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.29.0.tgz#5286ad785df7f79d656e88ce86e650d16ca5f322" + integrity sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA== + dependencies: + "@babel/code-frame" "^7.29.0" + "@babel/generator" "^7.29.0" + "@babel/helper-compilation-targets" "^7.28.6" + "@babel/helper-module-transforms" "^7.28.6" + "@babel/helpers" "^7.28.6" + "@babel/parser" "^7.29.0" + "@babel/template" "^7.28.6" + "@babel/traverse" "^7.29.0" + "@babel/types" "^7.29.0" + "@jridgewell/remapping" "^2.3.5" + convert-source-map "^2.0.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.3" + semver "^6.3.1" + +"@babel/generator@^7.27.5", "@babel/generator@^7.29.0": + version "7.29.1" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.29.1.tgz#d09876290111abbb00ef962a7b83a5307fba0d50" + integrity sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw== + dependencies: + "@babel/parser" "^7.29.0" + "@babel/types" "^7.29.0" + "@jridgewell/gen-mapping" "^0.3.12" + "@jridgewell/trace-mapping" "^0.3.28" + jsesc "^3.0.2" + +"@babel/helper-compilation-targets@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz#32c4a3f41f12ed1532179b108a4d746e105c2b25" + integrity sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA== + dependencies: + "@babel/compat-data" "^7.28.6" + "@babel/helper-validator-option" "^7.27.1" + browserslist "^4.24.0" + lru-cache "^5.1.1" + semver "^6.3.1" + +"@babel/helper-globals@^7.28.0": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/helper-globals/-/helper-globals-7.28.0.tgz#b9430df2aa4e17bc28665eadeae8aa1d985e6674" + integrity sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw== + +"@babel/helper-module-imports@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz#60632cbd6ffb70b22823187201116762a03e2d5c" + integrity sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw== + dependencies: + "@babel/traverse" "^7.28.6" + "@babel/types" "^7.28.6" + +"@babel/helper-module-transforms@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz#9312d9d9e56edc35aeb6e95c25d4106b50b9eb1e" + integrity sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA== + dependencies: + "@babel/helper-module-imports" "^7.28.6" + "@babel/helper-validator-identifier" "^7.28.5" + "@babel/traverse" "^7.28.6" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.28.6", "@babel/helper-plugin-utils@^7.8.0": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz#6f13ea251b68c8532e985fd532f28741a8af9ac8" + integrity sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug== + +"@babel/helper-string-parser@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz#54da796097ab19ce67ed9f88b47bb2ec49367687" + integrity sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA== + +"@babel/helper-validator-identifier@^7.28.5": + version "7.28.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz#010b6938fab7cb7df74aa2bbc06aa503b8fe5fb4" + integrity sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q== + +"@babel/helper-validator-option@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz#fa52f5b1e7db1ab049445b421c4471303897702f" + integrity sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg== + +"@babel/helpers@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.28.6.tgz#fca903a313ae675617936e8998b814c415cbf5d7" + integrity sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw== + dependencies: + "@babel/template" "^7.28.6" + "@babel/types" "^7.28.6" + +"@babel/parser@^7.1.0", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.28.6", "@babel/parser@^7.29.0": + version "7.29.0" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.29.0.tgz#669ef345add7d057e92b7ed15f0bac07611831b6" + integrity sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww== + dependencies: + "@babel/types" "^7.29.0" + +"@babel/plugin-syntax-async-generators@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-bigint@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" + integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" + integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-class-static-block@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406" + integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-import-attributes@^7.24.7": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz#b71d5914665f60124e133696f17cd7669062c503" + integrity sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw== + dependencies: + "@babel/helper-plugin-utils" "^7.28.6" + +"@babel/plugin-syntax-import-meta@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" + integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-jsx@^7.27.1": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz#f8ca28bbd84883b5fea0e447c635b81ba73997ee" + integrity sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w== + dependencies: + "@babel/helper-plugin-utils" "^7.28.6" + +"@babel/plugin-syntax-logical-assignment-operators@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" + integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" + integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-private-property-in-object@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" + integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-top-level-await@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-typescript@^7.27.1": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz#c7b2ddf1d0a811145b1de800d1abd146af92e3a2" + integrity sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A== + dependencies: + "@babel/helper-plugin-utils" "^7.28.6" + +"@babel/runtime@^7.25.0": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.28.6.tgz#d267a43cb1836dc4d182cce93ae75ba954ef6d2b" + integrity sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA== + +"@babel/template@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.28.6.tgz#0e7e56ecedb78aeef66ce7972b082fce76a23e57" + integrity sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ== + dependencies: + "@babel/code-frame" "^7.28.6" + "@babel/parser" "^7.28.6" + "@babel/types" "^7.28.6" + +"@babel/traverse@^7.28.6", "@babel/traverse@^7.29.0": + version "7.29.0" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.29.0.tgz#f323d05001440253eead3c9c858adbe00b90310a" + integrity sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA== + dependencies: + "@babel/code-frame" "^7.29.0" + "@babel/generator" "^7.29.0" + "@babel/helper-globals" "^7.28.0" + "@babel/parser" "^7.29.0" + "@babel/template" "^7.28.6" + "@babel/types" "^7.29.0" + debug "^4.3.1" + +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.27.3", "@babel/types@^7.28.2", "@babel/types@^7.28.6", "@babel/types@^7.29.0": + version "7.29.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.29.0.tgz#9f5b1e838c446e72cf3cd4b918152b8c605e37c7" + integrity sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A== + dependencies: + "@babel/helper-string-parser" "^7.27.1" + "@babel/helper-validator-identifier" "^7.28.5" + +"@balena/dockerignore@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@balena/dockerignore/-/dockerignore-1.0.2.tgz#9ffe4726915251e8eb69f44ef3547e0da2c03e0d" + integrity sha512-wMue2Sy4GAVTk6Ic4tJVcnfdau+gx2EnG7S+uAEe+TWJFqE4YoWN4/H8MSLj4eYJKxGg26lZwboEniNiNwZQ6Q== + +"@bcoe/v8-coverage@^0.2.3": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" + integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== + +"@colors/colors@1.6.0", "@colors/colors@^1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.6.0.tgz#ec6cd237440700bc23ca23087f513c75508958b0" + integrity sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA== "@confio/ics23@^0.6.8": version "0.6.8" - resolved "https://registry.npmjs.org/@confio/ics23/-/ics23-0.6.8.tgz" + resolved "https://registry.yarnpkg.com/@confio/ics23/-/ics23-0.6.8.tgz#2a6b4f1f2b7b20a35d9a0745bb5a446e72930b3d" integrity sha512-wB6uo+3A50m0sW/EWcU64xpV/8wShZ6bMTa7pF8eYsTrSkQA7oLUIJcs/wb8g4y2Oyq701BaGiO6n/ak5WXO1w== dependencies: "@noble/hashes" "^1.0.0" protobufjs "^6.8.8" -"@cosmjs/amino@0.32.3", "@cosmjs/amino@^0.32.3": +"@cosmjs/amino@0.32.3": version "0.32.3" - resolved "https://registry.npmjs.org/@cosmjs/amino/-/amino-0.32.3.tgz" + resolved "https://registry.yarnpkg.com/@cosmjs/amino/-/amino-0.32.3.tgz#b81d4a2b8d61568431a1afcd871e1344a19d97ff" integrity sha512-G4zXl+dJbqrz1sSJ56H/25l5NJEk/pAPIr8piAHgbXYw88OdAOlpA26PQvk2IbSN/rRgVbvlLTNgX2tzz1dyUA== dependencies: "@cosmjs/crypto" "^0.32.3" @@ -25,93 +308,56 @@ "@cosmjs/math" "^0.32.3" "@cosmjs/utils" "^0.32.3" -"@cosmjs/amino@^0.31.0": - version "0.31.0" - resolved "https://registry.npmjs.org/@cosmjs/amino/-/amino-0.31.0.tgz" - integrity sha512-xJ5CCEK7H79FTpOuEmlpSzVI+ZeYESTVvO3wHDgbnceIyAne3C68SvyaKqLUR4uJB0Z4q4+DZHbqW6itUiv4lA== - dependencies: - "@cosmjs/crypto" "^0.31.0" - "@cosmjs/encoding" "^0.31.0" - "@cosmjs/math" "^0.31.0" - "@cosmjs/utils" "^0.31.0" - -"@cosmjs/crypto@^0.31.0": - version "0.31.0" - resolved "https://registry.npmjs.org/@cosmjs/crypto/-/crypto-0.31.0.tgz" - integrity sha512-UaqCe6Tgh0pe1QlZ66E13t6FlIF86QrnBXXq+EN7Xe1Rouza3fJ1ojGlPleJZkBoq3tAyYVIOOqdZIxtVj/sIQ== +"@cosmjs/amino@^0.32.3", "@cosmjs/amino@^0.32.4": + version "0.32.4" + resolved "https://registry.yarnpkg.com/@cosmjs/amino/-/amino-0.32.4.tgz#3908946c0394e6d431694c8992c5147079a1c860" + integrity sha512-zKYOt6hPy8obIFtLie/xtygCkH9ZROiQ12UHfKsOkWaZfPQUvVbtgmu6R4Kn1tFLI/SRkw7eqhaogmW/3NYu/Q== dependencies: - "@cosmjs/encoding" "^0.31.0" - "@cosmjs/math" "^0.31.0" - "@cosmjs/utils" "^0.31.0" - "@noble/hashes" "^1" - bn.js "^5.2.0" - elliptic "^6.5.4" - libsodium-wrappers-sumo "^0.7.11" + "@cosmjs/crypto" "^0.32.4" + "@cosmjs/encoding" "^0.32.4" + "@cosmjs/math" "^0.32.4" + "@cosmjs/utils" "^0.32.4" -"@cosmjs/crypto@^0.32.3": - version "0.32.3" - resolved "https://registry.npmjs.org/@cosmjs/crypto/-/crypto-0.32.3.tgz" - integrity sha512-niQOWJHUtlJm2GG4F00yGT7sGPKxfUwz+2qQ30uO/E3p58gOusTcH2qjiJNVxb8vScYJhFYFqpm/OA/mVqoUGQ== +"@cosmjs/crypto@^0.32.3", "@cosmjs/crypto@^0.32.4": + version "0.32.4" + resolved "https://registry.yarnpkg.com/@cosmjs/crypto/-/crypto-0.32.4.tgz#5d29633b661eaf092ddb3e7ea6299cfd6f4507a2" + integrity sha512-zicjGU051LF1V9v7bp8p7ovq+VyC91xlaHdsFOTo2oVry3KQikp8L/81RkXmUIT8FxMwdx1T7DmFwVQikcSDIw== dependencies: - "@cosmjs/encoding" "^0.32.3" - "@cosmjs/math" "^0.32.3" - "@cosmjs/utils" "^0.32.3" + "@cosmjs/encoding" "^0.32.4" + "@cosmjs/math" "^0.32.4" + "@cosmjs/utils" "^0.32.4" "@noble/hashes" "^1" bn.js "^5.2.0" elliptic "^6.5.4" libsodium-wrappers-sumo "^0.7.11" -"@cosmjs/encoding@^0.31.0": - version "0.31.0" - resolved "https://registry.npmjs.org/@cosmjs/encoding/-/encoding-0.31.0.tgz" - integrity sha512-NYGQDRxT7MIRSlcbAezwxK0FqnaSPKCH7O32cmfpHNWorFxhy9lwmBoCvoe59Kd0HmArI4h+NGzLEfX3OLnA4Q== - dependencies: - base64-js "^1.3.0" - bech32 "^1.1.4" - readonly-date "^1.0.0" - -"@cosmjs/encoding@^0.32.3": - version "0.32.3" - resolved "https://registry.npmjs.org/@cosmjs/encoding/-/encoding-0.32.3.tgz" - integrity sha512-p4KF7hhv8jBQX3MkB3Defuhz/W0l3PwWVYU2vkVuBJ13bJcXyhU9nJjiMkaIv+XP+W2QgRceqNNgFUC5chNR7w== +"@cosmjs/encoding@^0.32.3", "@cosmjs/encoding@^0.32.4": + version "0.32.4" + resolved "https://registry.yarnpkg.com/@cosmjs/encoding/-/encoding-0.32.4.tgz#646e0e809f7f4f1414d8fa991fb0ffe6c633aede" + integrity sha512-tjvaEy6ZGxJchiizzTn7HVRiyTg1i4CObRRaTRPknm5EalE13SV+TCHq38gIDfyUeden4fCuaBVEdBR5+ti7Hw== dependencies: base64-js "^1.3.0" bech32 "^1.1.4" readonly-date "^1.0.0" -"@cosmjs/json-rpc@^0.31.0": - version "0.31.0" - resolved "https://registry.npmjs.org/@cosmjs/json-rpc/-/json-rpc-0.31.0.tgz" - integrity sha512-Ix2Cil2qysiLNrX+E0w3vtwCrqxGVq8jklpLA7B2vtMrw7tru/rS65fdFSy8ep0wUNLL6Ud32VXa5K0YObDOMA== +"@cosmjs/json-rpc@^0.32.3", "@cosmjs/json-rpc@^0.32.4": + version "0.32.4" + resolved "https://registry.yarnpkg.com/@cosmjs/json-rpc/-/json-rpc-0.32.4.tgz#be91eb89ea78bd5dc02d0a9fa184dd6790790f0b" + integrity sha512-/jt4mBl7nYzfJ2J/VJ+r19c92mUKF0Lt0JxM3MXEJl7wlwW5haHAWtzRujHkyYMXOwIR+gBqT2S0vntXVBRyhQ== dependencies: - "@cosmjs/stream" "^0.31.0" + "@cosmjs/stream" "^0.32.4" xstream "^11.14.0" -"@cosmjs/json-rpc@^0.32.3": - version "0.32.3" - resolved "https://registry.npmjs.org/@cosmjs/json-rpc/-/json-rpc-0.32.3.tgz" - integrity sha512-JwFRWZa+Y95KrAG8CuEbPVOSnXO2uMSEBcaAB/FBU3Mo4jQnDoUjXvt3vwtFWxfAytrWCn1I4YDFaOAinnEG/Q== - dependencies: - "@cosmjs/stream" "^0.32.3" - xstream "^11.14.0" - -"@cosmjs/math@^0.31.0": - version "0.31.0" - resolved "https://registry.npmjs.org/@cosmjs/math/-/math-0.31.0.tgz" - integrity sha512-Sb/8Ry/+gKJaYiV6X8q45kxXC9FoV98XCY1WXtu0JQwOi61VCG2VXsURQnVvZ/EhR/CuT/swOlNKrqEs3da0fw== - dependencies: - bn.js "^5.2.0" - -"@cosmjs/math@^0.32.3": - version "0.32.3" - resolved "https://registry.npmjs.org/@cosmjs/math/-/math-0.32.3.tgz" - integrity sha512-amumUtZs8hCCnV+lSBaJIiZkGabQm22QGg/IotYrhcmoOEOjt82n7hMNlNXRs7V6WLMidGrGYcswB5zcmp0Meg== +"@cosmjs/math@^0.32.3", "@cosmjs/math@^0.32.4": + version "0.32.4" + resolved "https://registry.yarnpkg.com/@cosmjs/math/-/math-0.32.4.tgz#87ac9eadc06696e30a30bdb562a495974bfd0a1a" + integrity sha512-++dqq2TJkoB8zsPVYCvrt88oJWsy1vMOuSOKcdlnXuOA/ASheTJuYy4+oZlTQ3Fr8eALDLGGPhJI02W2HyAQaw== dependencies: bn.js "^5.2.0" -"@cosmjs/proto-signing@0.32.3", "@cosmjs/proto-signing@^0.32.3": +"@cosmjs/proto-signing@0.32.3": version "0.32.3" - resolved "https://registry.npmjs.org/@cosmjs/proto-signing/-/proto-signing-0.32.3.tgz" + resolved "https://registry.yarnpkg.com/@cosmjs/proto-signing/-/proto-signing-0.32.3.tgz#91ae149b747d18666a6ccc924165b306431f7c0d" integrity sha512-kSZ0ZUY0DwcRT0NcIn2HkadH4NKlwjfZgbLj1ABwh/4l0RgeT84QCscZCu63tJYq3K6auwqTiZSZERwlO4/nbg== dependencies: "@cosmjs/amino" "^0.32.3" @@ -121,42 +367,31 @@ "@cosmjs/utils" "^0.32.3" cosmjs-types "^0.9.0" -"@cosmjs/proto-signing@^0.31.0": - version "0.31.0" - resolved "https://registry.npmjs.org/@cosmjs/proto-signing/-/proto-signing-0.31.0.tgz" - integrity sha512-JNlyOJRkn8EKB9mCthkjr6lVX6eyVQ09PFdmB4/DR874E62dFTvQ+YvyKMAgN7K7Dcjj26dVlAD3f6Xs7YOGDg== - dependencies: - "@cosmjs/amino" "^0.31.0" - "@cosmjs/crypto" "^0.31.0" - "@cosmjs/encoding" "^0.31.0" - "@cosmjs/math" "^0.31.0" - "@cosmjs/utils" "^0.31.0" - cosmjs-types "^0.8.0" - long "^4.0.0" - -"@cosmjs/socket@^0.31.0": - version "0.31.0" - resolved "https://registry.npmjs.org/@cosmjs/socket/-/socket-0.31.0.tgz" - integrity sha512-WDh9gTyiP3OCXvSAJJn33+Ef3XqMWag+bpR1TdMBxTmlTxuvU+kPy4cf6P2OF+jkkUBEA5Se2EAju0eFbJMT+w== +"@cosmjs/proto-signing@^0.32.3": + version "0.32.4" + resolved "https://registry.yarnpkg.com/@cosmjs/proto-signing/-/proto-signing-0.32.4.tgz#5a06e087c6d677439c8c9b25b5223d5e72c4cd93" + integrity sha512-QdyQDbezvdRI4xxSlyM1rSVBO2st5sqtbEIl3IX03uJ7YiZIQHyv6vaHVf1V4mapusCqguiHJzm4N4gsFdLBbQ== dependencies: - "@cosmjs/stream" "^0.31.0" - isomorphic-ws "^4.0.1" - ws "^7" - xstream "^11.14.0" + "@cosmjs/amino" "^0.32.4" + "@cosmjs/crypto" "^0.32.4" + "@cosmjs/encoding" "^0.32.4" + "@cosmjs/math" "^0.32.4" + "@cosmjs/utils" "^0.32.4" + cosmjs-types "^0.9.0" -"@cosmjs/socket@^0.32.3": - version "0.32.3" - resolved "https://registry.npmjs.org/@cosmjs/socket/-/socket-0.32.3.tgz" - integrity sha512-F2WwNmaUPdZ4SsH6Uyreq3wQk7jpaEkb3wfOP951f5Jt6HCW/PxbxhKzHkAAf6+Sqks6SPhkbWoE8XaZpjL2KA== +"@cosmjs/socket@^0.32.3", "@cosmjs/socket@^0.32.4": + version "0.32.4" + resolved "https://registry.yarnpkg.com/@cosmjs/socket/-/socket-0.32.4.tgz#86ab6adf3a442314774c0810b7a7cfcddf4f2082" + integrity sha512-davcyYziBhkzfXQTu1l5NrpDYv0K9GekZCC9apBRvL1dvMc9F/ygM7iemHjUA+z8tJkxKxrt/YPjJ6XNHzLrkw== dependencies: - "@cosmjs/stream" "^0.32.3" + "@cosmjs/stream" "^0.32.4" isomorphic-ws "^4.0.1" ws "^7" xstream "^11.14.0" "@cosmjs/stargate@0.32.3": version "0.32.3" - resolved "https://registry.npmjs.org/@cosmjs/stargate/-/stargate-0.32.3.tgz" + resolved "https://registry.yarnpkg.com/@cosmjs/stargate/-/stargate-0.32.3.tgz#5a92b222ada960ebecea72cc9f366370763f4b66" integrity sha512-OQWzO9YWKerUinPIxrO1MARbe84XkeXJAW0lyMIjXIEikajuXZ+PwftiKA5yA+8OyditVmHVLtPud6Pjna2s5w== dependencies: "@confio/ics23" "^0.6.8" @@ -170,41 +405,16 @@ cosmjs-types "^0.9.0" xstream "^11.14.0" -"@cosmjs/stargate@^0.31.0": - version "0.31.0" - resolved "https://registry.npmjs.org/@cosmjs/stargate/-/stargate-0.31.0.tgz" - integrity sha512-GYhk9lzZPj/QmYHC0VV/4AMoRzVcOP+EnB1YZCoWlBdLuVmpBYKRagJqWIrIwdk1E0gF2ZoESd2TYfdh1fqIpg== - dependencies: - "@confio/ics23" "^0.6.8" - "@cosmjs/amino" "^0.31.0" - "@cosmjs/encoding" "^0.31.0" - "@cosmjs/math" "^0.31.0" - "@cosmjs/proto-signing" "^0.31.0" - "@cosmjs/stream" "^0.31.0" - "@cosmjs/tendermint-rpc" "^0.31.0" - "@cosmjs/utils" "^0.31.0" - cosmjs-types "^0.8.0" - long "^4.0.0" - protobufjs "~6.11.3" - xstream "^11.14.0" - -"@cosmjs/stream@^0.31.0": - version "0.31.0" - resolved "https://registry.npmjs.org/@cosmjs/stream/-/stream-0.31.0.tgz" - integrity sha512-Y+aSHwhHkLGIaQOdqRob+yga2zr9ifl9gZDKD+B7+R5pdWN5f2TTDhYWxA6YZcZ6xRmfr7u8a7tDh7iYLC/zKA== +"@cosmjs/stream@^0.32.3", "@cosmjs/stream@^0.32.4": + version "0.32.4" + resolved "https://registry.yarnpkg.com/@cosmjs/stream/-/stream-0.32.4.tgz#83e1f2285807467c56d9ea0e1113f79d9fa63802" + integrity sha512-Gih++NYHEiP+oyD4jNEUxU9antoC0pFSg+33Hpp0JlHwH0wXhtD3OOKnzSfDB7OIoEbrzLJUpEjOgpCp5Z+W3A== dependencies: xstream "^11.14.0" -"@cosmjs/stream@^0.32.3": +"@cosmjs/tendermint-rpc@0.32.3": version "0.32.3" - resolved "https://registry.npmjs.org/@cosmjs/stream/-/stream-0.32.3.tgz" - integrity sha512-J2zVWDojkynYifAUcRmVczzmp6STEpyiAARq0rSsviqjreGIfspfuws/8rmkPa6qQBZvpQOBQCm2HyZZwYplIw== - dependencies: - xstream "^11.14.0" - -"@cosmjs/tendermint-rpc@0.32.3", "@cosmjs/tendermint-rpc@^0.32.3": - version "0.32.3" - resolved "https://registry.npmjs.org/@cosmjs/tendermint-rpc/-/tendermint-rpc-0.32.3.tgz" + resolved "https://registry.yarnpkg.com/@cosmjs/tendermint-rpc/-/tendermint-rpc-0.32.3.tgz#f0406b9f0233e588fb924dca8c614972f9038aff" integrity sha512-xeprW+VR9xKGstqZg0H/KBZoUp8/FfFyS9ljIUTLM/UINjP2MhiwncANPS2KScfJVepGufUKk0/phHUeIBSEkw== dependencies: "@cosmjs/crypto" "^0.32.3" @@ -218,151 +428,657 @@ readonly-date "^1.0.0" xstream "^11.14.0" -"@cosmjs/tendermint-rpc@^0.31.0": - version "0.31.0" - resolved "https://registry.npmjs.org/@cosmjs/tendermint-rpc/-/tendermint-rpc-0.31.0.tgz" - integrity sha512-yo9xbeuI6UoEKIhFZ9g0dvUKLqnBzwdpEc/uldQygQc51j38gQVwFko+6sjmhieJqRYYvrYumcbJMiV6GFM9aA== - dependencies: - "@cosmjs/crypto" "^0.31.0" - "@cosmjs/encoding" "^0.31.0" - "@cosmjs/json-rpc" "^0.31.0" - "@cosmjs/math" "^0.31.0" - "@cosmjs/socket" "^0.31.0" - "@cosmjs/stream" "^0.31.0" - "@cosmjs/utils" "^0.31.0" - axios "^0.21.2" +"@cosmjs/tendermint-rpc@^0.32.3": + version "0.32.4" + resolved "https://registry.yarnpkg.com/@cosmjs/tendermint-rpc/-/tendermint-rpc-0.32.4.tgz#b36f9ec657498e42c97e21bb7368798ef6279752" + integrity sha512-MWvUUno+4bCb/LmlMIErLypXxy7ckUuzEmpufYYYd9wgbdCXaTaO08SZzyFM5PI8UJ/0S2AmUrgWhldlbxO8mw== + dependencies: + "@cosmjs/crypto" "^0.32.4" + "@cosmjs/encoding" "^0.32.4" + "@cosmjs/json-rpc" "^0.32.4" + "@cosmjs/math" "^0.32.4" + "@cosmjs/socket" "^0.32.4" + "@cosmjs/stream" "^0.32.4" + "@cosmjs/utils" "^0.32.4" + axios "^1.6.0" readonly-date "^1.0.0" xstream "^11.14.0" -"@cosmjs/utils@^0.31.0": - version "0.31.0" - resolved "https://registry.npmjs.org/@cosmjs/utils/-/utils-0.31.0.tgz" - integrity sha512-nNcycZWUYLNJlrIXgpcgVRqdl6BXjF4YlXdxobQWpW9Tikk61bEGeAFhDYtC0PwHlokCNw0KxWiHGJL4nL7Q5A== - -"@cosmjs/utils@^0.32.3": - version "0.32.3" - resolved "https://registry.npmjs.org/@cosmjs/utils/-/utils-0.32.3.tgz" - integrity sha512-WCZK4yksj2hBDz4w7xFZQTRZQ/RJhBX26uFHmmQFIcNUUVAihrLO+RerqJgk0dZqC42wstM9pEUQGtPmLcIYvg== +"@cosmjs/utils@^0.32.3", "@cosmjs/utils@^0.32.4": + version "0.32.4" + resolved "https://registry.yarnpkg.com/@cosmjs/utils/-/utils-0.32.4.tgz#a9a717c9fd7b1984d9cefdd0ef6c6f254060c671" + integrity sha512-D1Yc+Zy8oL/hkUkFUL/bwxvuDBzRGpc4cF7/SkdhxX4iHpSLgdOuTt1mhCh9+kl6NQREy9t7SYZ6xeW5gFe60w== "@cosmology/lcd@^0.13.3": - version "0.13.3" - resolved "https://registry.npmjs.org/@cosmology/lcd/-/lcd-0.13.3.tgz" - integrity sha512-lihAHCoap0GN/32qcOhiMp6HcoZP8A7GeScZMlmmvBtBk6ocGAStNHjvBR4MayrvyHSCOZCvCAWPh36iFTT8Sw== + version "0.13.5" + resolved "https://registry.yarnpkg.com/@cosmology/lcd/-/lcd-0.13.5.tgz#1bc4d43d525ecd68d09211d2ce17332a149a1a00" + integrity sha512-CI8KFsJcgp0RINF8wHpv3Y9yR4Fb9ZnGucyoUICjtX2XT4NVBK+fvZuRFj5TP34km8TpEOb+WV2T7IN/pZsD7Q== dependencies: - axios "1.6.0" + axios "1.7.4" -"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": - version "4.4.0" - resolved "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz" - integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== +"@cspotcode/source-map-support@^0.8.0": + version "0.8.1" + resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" + integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== dependencies: - eslint-visitor-keys "^3.3.0" + "@jridgewell/trace-mapping" "0.3.9" -"@eslint-community/regexpp@^4.5.1", "@eslint-community/regexpp@^4.6.1": - version "4.8.1" - resolved "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.8.1.tgz" - integrity sha512-PWiOzLIUAjN/w5K17PoF4n6sKBw0gqLHPhywmYHP4t1VFQQVYeb1yWsJwnMVEMl3tUHME7X/SJPZLmtG7XBDxQ== +"@dabh/diagnostics@^2.0.8": + version "2.0.8" + resolved "https://registry.yarnpkg.com/@dabh/diagnostics/-/diagnostics-2.0.8.tgz#ead97e72ca312cf0e6dd7af0d300b58993a31a5e" + integrity sha512-R4MSXTVnuMzGD7bzHdW2ZhhdPC/igELENcq5IjEverBvq5hn1SXCWcsi6eSsdWP0/Ur+SItRRjAktmdoX/8R/Q== + dependencies: + "@so-ric/colorspace" "^1.1.6" + enabled "2.0.x" + kuler "^2.0.0" -"@eslint/eslintrc@^2.1.2": - version "2.1.2" - resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz" - integrity sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g== +"@emnapi/core@^1.4.3": + version "1.8.1" + resolved "https://registry.yarnpkg.com/@emnapi/core/-/core-1.8.1.tgz#fd9efe721a616288345ffee17a1f26ac5dd01349" + integrity sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg== dependencies: - ajv "^6.12.4" - debug "^4.3.2" - espree "^9.6.0" - globals "^13.19.0" - ignore "^5.2.0" - import-fresh "^3.2.1" - js-yaml "^4.1.0" - minimatch "^3.1.2" - strip-json-comments "^3.1.1" + "@emnapi/wasi-threads" "1.1.0" + tslib "^2.4.0" -"@eslint/js@8.49.0": - version "8.49.0" - resolved "https://registry.npmjs.org/@eslint/js/-/js-8.49.0.tgz" - integrity sha512-1S8uAY/MTJqVx0SC4epBq+N2yhuwtNwLbJYNZyhL2pO1ZVKn5HFXav5T41Ryzy9K9V7ZId2JB2oy/W4aCd9/2w== +"@emnapi/runtime@^1.4.3": + version "1.8.1" + resolved "https://registry.yarnpkg.com/@emnapi/runtime/-/runtime-1.8.1.tgz#550fa7e3c0d49c5fb175a116e8cd70614f9a22a5" + integrity sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg== + dependencies: + tslib "^2.4.0" -"@humanwhocodes/config-array@^0.11.11": - version "0.11.11" - resolved "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz" - integrity sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA== +"@emnapi/wasi-threads@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz#60b2102fddc9ccb78607e4a3cf8403ea69be41bf" + integrity sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ== dependencies: - "@humanwhocodes/object-schema" "^1.2.1" - debug "^4.1.1" - minimatch "^3.0.5" + tslib "^2.4.0" + +"@eslint-community/eslint-utils@^4.8.0", "@eslint-community/eslint-utils@^4.9.1": + version "4.9.1" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz#4e90af67bc51ddee6cdef5284edf572ec376b595" + integrity sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ== + dependencies: + eslint-visitor-keys "^3.4.3" + +"@eslint-community/regexpp@^4.12.2": + version "4.12.2" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.2.tgz#bccdf615bcf7b6e8db830ec0b8d21c9a25de597b" + integrity sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew== + +"@eslint/config-array@^0.23.3": + version "0.23.3" + resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.23.3.tgz#3f4a93dd546169c09130cbd10f2415b13a20a219" + integrity sha512-j+eEWmB6YYLwcNOdlwQ6L2OsptI/LO6lNBuLIqe5R7RetD658HLoF+Mn7LzYmAWWNNzdC6cqP+L6r8ujeYXWLw== + dependencies: + "@eslint/object-schema" "^3.0.3" + debug "^4.3.1" + minimatch "^10.2.4" + +"@eslint/config-helpers@^0.5.2": + version "0.5.3" + resolved "https://registry.yarnpkg.com/@eslint/config-helpers/-/config-helpers-0.5.3.tgz#721fe6bbb90d74b0c80d6ff2428e5bbcb002becb" + integrity sha512-lzGN0onllOZCGroKJmRwY6QcEHxbjBw1gwB8SgRSqK8YbbtEXMvKynsXc3553ckIEBxsbMBU7oOZXKIPGZNeZw== + dependencies: + "@eslint/core" "^1.1.1" + +"@eslint/core@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@eslint/core/-/core-1.1.1.tgz#450f3d2be2d463ccd51119544092256b4e88df32" + integrity sha512-QUPblTtE51/7/Zhfv8BDwO0qkkzQL7P/aWWbqcf4xWLEYn1oKjdO0gglQBB4GAsu7u6wjijbCmzsUTy6mnk6oQ== + dependencies: + "@types/json-schema" "^7.0.15" + +"@eslint/js@^10.0.0": + version "10.0.1" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-10.0.1.tgz#1e8a876f50117af8ab67e47d5ad94d38d6622583" + integrity sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA== + +"@eslint/object-schema@^3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-3.0.3.tgz#5bf671e52e382e4adc47a9906f2699374637db6b" + integrity sha512-iM869Pugn9Nsxbh/YHRqYiqd23AmIbxJOcpUMOuWCVNdoQJ5ZtwL6h3t0bcZzJUlC3Dq9jCFCESBZnX0GTv7iQ== + +"@eslint/plugin-kit@^0.6.1": + version "0.6.1" + resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.6.1.tgz#eb9e6689b56ce8bc1855bb33090e63f3fc115e8e" + integrity sha512-iH1B076HoAshH1mLpHMgwdGeTs0CYwL0SPMkGuSebZrwBp16v415e9NZXg2jtrqPVQjf6IANe2Vtlr5KswtcZQ== + dependencies: + "@eslint/core" "^1.1.1" + levn "^0.4.1" + +"@grpc/grpc-js@^1.11.1": + version "1.14.3" + resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.14.3.tgz#4c9b817a900ae4020ddc28515ae4b52c78cfb8da" + integrity sha512-Iq8QQQ/7X3Sac15oB6p0FmUg/klxQvXLeileoqrTRGJYLV+/9tubbr9ipz0GKHjmXVsgFPo/+W+2cA8eNcR+XA== + dependencies: + "@grpc/proto-loader" "^0.8.0" + "@js-sdsl/ordered-map" "^4.4.2" + +"@grpc/proto-loader@^0.7.13": + version "0.7.15" + resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.7.15.tgz#4cdfbf35a35461fc843abe8b9e2c0770b5095e60" + integrity sha512-tMXdRCfYVixjuFK+Hk0Q1s38gV9zDiDJfWL3h1rv4Qc39oILCu1TRTDt7+fGUI8K4G1Fj125Hx/ru3azECWTyQ== + dependencies: + lodash.camelcase "^4.3.0" + long "^5.0.0" + protobufjs "^7.2.5" + yargs "^17.7.2" + +"@grpc/proto-loader@^0.8.0": + version "0.8.0" + resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.8.0.tgz#b6c324dd909c458a0e4aa9bfd3d69cf78a4b9bd8" + integrity sha512-rc1hOQtjIWGxcxpb9aHAfLpIctjEnsDehj0DAiVfBlmT84uvR0uUtN2hEi/ecvWVjXUGf5qPF4qEgiLOx1YIMQ== + dependencies: + lodash.camelcase "^4.3.0" + long "^5.0.0" + protobufjs "^7.5.3" + yargs "^17.7.2" + +"@humanfs/core@^0.19.1": + version "0.19.1" + resolved "https://registry.yarnpkg.com/@humanfs/core/-/core-0.19.1.tgz#17c55ca7d426733fe3c561906b8173c336b40a77" + integrity sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA== + +"@humanfs/node@^0.16.6": + version "0.16.7" + resolved "https://registry.yarnpkg.com/@humanfs/node/-/node-0.16.7.tgz#822cb7b3a12c5a240a24f621b5a2413e27a45f26" + integrity sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ== + dependencies: + "@humanfs/core" "^0.19.1" + "@humanwhocodes/retry" "^0.4.0" "@humanwhocodes/module-importer@^1.0.1": version "1.0.1" - resolved "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== -"@humanwhocodes/object-schema@^1.2.1": - version "1.2.1" - resolved "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz" - integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== +"@humanwhocodes/retry@^0.4.0", "@humanwhocodes/retry@^0.4.2": + version "0.4.3" + resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.4.3.tgz#c2b9d2e374ee62c586d3adbea87199b1d7a7a6ba" + integrity sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ== -"@noble/hashes@^1", "@noble/hashes@^1.0.0": - version "1.3.1" - resolved "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.1.tgz" - integrity sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA== +"@isaacs/cliui@^8.0.2": + version "8.0.2" + resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" + integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== + dependencies: + string-width "^5.1.2" + string-width-cjs "npm:string-width@^4.2.0" + strip-ansi "^7.0.1" + strip-ansi-cjs "npm:strip-ansi@^6.0.1" + wrap-ansi "^8.1.0" + wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" -"@nodelib/fs.scandir@2.1.5": - version "2.1.5" - resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz" - integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== +"@istanbuljs/load-nyc-config@^1.0.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" + integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== + dependencies: + camelcase "^5.3.1" + find-up "^4.1.0" + get-package-type "^0.1.0" + js-yaml "^3.13.1" + resolve-from "^5.0.0" + +"@istanbuljs/schema@^0.1.2", "@istanbuljs/schema@^0.1.3": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== + +"@jest/console@30.2.0": + version "30.2.0" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-30.2.0.tgz#c52fcd5b58fdd2e8eb66b2fd8ae56f2f64d05b28" + integrity sha512-+O1ifRjkvYIkBqASKWgLxrpEhQAAE7hY77ALLUufSk5717KfOShg6IbqLmdsLMPdUiFvA2kTs0R7YZy+l0IzZQ== + dependencies: + "@jest/types" "30.2.0" + "@types/node" "*" + chalk "^4.1.2" + jest-message-util "30.2.0" + jest-util "30.2.0" + slash "^3.0.0" + +"@jest/core@30.2.0": + version "30.2.0" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-30.2.0.tgz#813d59faa5abd5510964a8b3a7b17cc77b775275" + integrity sha512-03W6IhuhjqTlpzh/ojut/pDB2LPRygyWX8ExpgHtQA8H/3K7+1vKmcINx5UzeOX1se6YEsBsOHQ1CRzf3fOwTQ== + dependencies: + "@jest/console" "30.2.0" + "@jest/pattern" "30.0.1" + "@jest/reporters" "30.2.0" + "@jest/test-result" "30.2.0" + "@jest/transform" "30.2.0" + "@jest/types" "30.2.0" + "@types/node" "*" + ansi-escapes "^4.3.2" + chalk "^4.1.2" + ci-info "^4.2.0" + exit-x "^0.2.2" + graceful-fs "^4.2.11" + jest-changed-files "30.2.0" + jest-config "30.2.0" + jest-haste-map "30.2.0" + jest-message-util "30.2.0" + jest-regex-util "30.0.1" + jest-resolve "30.2.0" + jest-resolve-dependencies "30.2.0" + jest-runner "30.2.0" + jest-runtime "30.2.0" + jest-snapshot "30.2.0" + jest-util "30.2.0" + jest-validate "30.2.0" + jest-watcher "30.2.0" + micromatch "^4.0.8" + pretty-format "30.2.0" + slash "^3.0.0" + +"@jest/diff-sequences@30.0.1": + version "30.0.1" + resolved "https://registry.yarnpkg.com/@jest/diff-sequences/-/diff-sequences-30.0.1.tgz#0ededeae4d071f5c8ffe3678d15f3a1be09156be" + integrity sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw== + +"@jest/environment@30.2.0": + version "30.2.0" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-30.2.0.tgz#1e673cdb8b93ded707cf6631b8353011460831fa" + integrity sha512-/QPTL7OBJQ5ac09UDRa3EQes4gt1FTEG/8jZ/4v5IVzx+Cv7dLxlVIvfvSVRiiX2drWyXeBjkMSR8hvOWSog5g== + dependencies: + "@jest/fake-timers" "30.2.0" + "@jest/types" "30.2.0" + "@types/node" "*" + jest-mock "30.2.0" + +"@jest/expect-utils@30.2.0": + version "30.2.0" + resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-30.2.0.tgz#4f95413d4748454fdb17404bf1141827d15e6011" + integrity sha512-1JnRfhqpD8HGpOmQp180Fo9Zt69zNtC+9lR+kT7NVL05tNXIi+QC8Csz7lfidMoVLPD3FnOtcmp0CEFnxExGEA== + dependencies: + "@jest/get-type" "30.1.0" + +"@jest/expect@30.2.0": + version "30.2.0" + resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-30.2.0.tgz#9a5968499bb8add2bbb09136f69f7df5ddbf3185" + integrity sha512-V9yxQK5erfzx99Sf+7LbhBwNWEZ9eZay8qQ9+JSC0TrMR1pMDHLMY+BnVPacWU6Jamrh252/IKo4F1Xn/zfiqA== + dependencies: + expect "30.2.0" + jest-snapshot "30.2.0" + +"@jest/fake-timers@30.2.0": + version "30.2.0" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-30.2.0.tgz#0941ddc28a339b9819542495b5408622dc9e94ec" + integrity sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw== + dependencies: + "@jest/types" "30.2.0" + "@sinonjs/fake-timers" "^13.0.0" + "@types/node" "*" + jest-message-util "30.2.0" + jest-mock "30.2.0" + jest-util "30.2.0" + +"@jest/get-type@30.1.0": + version "30.1.0" + resolved "https://registry.yarnpkg.com/@jest/get-type/-/get-type-30.1.0.tgz#4fcb4dc2ebcf0811be1c04fd1cb79c2dba431cbc" + integrity sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA== + +"@jest/globals@30.2.0": + version "30.2.0" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-30.2.0.tgz#2f4b696d5862664b89c4ee2e49ae24d2bb7e0988" + integrity sha512-b63wmnKPaK+6ZZfpYhz9K61oybvbI1aMcIs80++JI1O1rR1vaxHUCNqo3ITu6NU0d4V34yZFoHMn/uoKr/Rwfw== + dependencies: + "@jest/environment" "30.2.0" + "@jest/expect" "30.2.0" + "@jest/types" "30.2.0" + jest-mock "30.2.0" + +"@jest/pattern@30.0.1": + version "30.0.1" + resolved "https://registry.yarnpkg.com/@jest/pattern/-/pattern-30.0.1.tgz#d5304147f49a052900b4b853dedb111d080e199f" + integrity sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA== + dependencies: + "@types/node" "*" + jest-regex-util "30.0.1" + +"@jest/reporters@30.2.0": + version "30.2.0" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-30.2.0.tgz#a36b28fcbaf0c4595250b108e6f20e363348fd91" + integrity sha512-DRyW6baWPqKMa9CzeiBjHwjd8XeAyco2Vt8XbcLFjiwCOEKOvy82GJ8QQnJE9ofsxCMPjH4MfH8fCWIHHDKpAQ== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@jest/console" "30.2.0" + "@jest/test-result" "30.2.0" + "@jest/transform" "30.2.0" + "@jest/types" "30.2.0" + "@jridgewell/trace-mapping" "^0.3.25" + "@types/node" "*" + chalk "^4.1.2" + collect-v8-coverage "^1.0.2" + exit-x "^0.2.2" + glob "^10.3.10" + graceful-fs "^4.2.11" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-instrument "^6.0.0" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^5.0.0" + istanbul-reports "^3.1.3" + jest-message-util "30.2.0" + jest-util "30.2.0" + jest-worker "30.2.0" + slash "^3.0.0" + string-length "^4.0.2" + v8-to-istanbul "^9.0.1" + +"@jest/schemas@30.0.5": + version "30.0.5" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-30.0.5.tgz#7bdf69fc5a368a5abdb49fd91036c55225846473" + integrity sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA== dependencies: - "@nodelib/fs.stat" "2.0.5" - run-parallel "^1.1.9" + "@sinclair/typebox" "^0.34.0" -"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": - version "2.0.5" - resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz" - integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== +"@jest/snapshot-utils@30.2.0": + version "30.2.0" + resolved "https://registry.yarnpkg.com/@jest/snapshot-utils/-/snapshot-utils-30.2.0.tgz#387858eb90c2f98f67bff327435a532ac5309fbe" + integrity sha512-0aVxM3RH6DaiLcjj/b0KrIBZhSX1373Xci4l3cW5xiUWPctZ59zQ7jj4rqcJQ/Z8JuN/4wX3FpJSa3RssVvCug== + dependencies: + "@jest/types" "30.2.0" + chalk "^4.1.2" + graceful-fs "^4.2.11" + natural-compare "^1.4.0" -"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": - version "1.2.8" - resolved "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz" - integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== +"@jest/source-map@30.0.1": + version "30.0.1" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-30.0.1.tgz#305ebec50468f13e658b3d5c26f85107a5620aaa" + integrity sha512-MIRWMUUR3sdbP36oyNyhbThLHyJ2eEDClPCiHVbrYAe5g3CHRArIVpBw7cdSB5fr+ofSfIb2Tnsw8iEHL0PYQg== + dependencies: + "@jridgewell/trace-mapping" "^0.3.25" + callsites "^3.1.0" + graceful-fs "^4.2.11" + +"@jest/test-result@30.2.0": + version "30.2.0" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-30.2.0.tgz#9c0124377fb7996cdffb86eda3dbc56eacab363d" + integrity sha512-RF+Z+0CCHkARz5HT9mcQCBulb1wgCP3FBvl9VFokMX27acKphwyQsNuWH3c+ojd1LeWBLoTYoxF0zm6S/66mjg== + dependencies: + "@jest/console" "30.2.0" + "@jest/types" "30.2.0" + "@types/istanbul-lib-coverage" "^2.0.6" + collect-v8-coverage "^1.0.2" + +"@jest/test-sequencer@30.2.0": + version "30.2.0" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-30.2.0.tgz#bf0066bc72e176d58f5dfa7f212b6e7eee44f221" + integrity sha512-wXKgU/lk8fKXMu/l5Hog1R61bL4q5GCdT6OJvdAFz1P+QrpoFuLU68eoKuVc4RbrTtNnTL5FByhWdLgOPSph+Q== + dependencies: + "@jest/test-result" "30.2.0" + graceful-fs "^4.2.11" + jest-haste-map "30.2.0" + slash "^3.0.0" + +"@jest/transform@30.2.0": + version "30.2.0" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-30.2.0.tgz#54bef1a4510dcbd58d5d4de4fe2980a63077ef2a" + integrity sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA== + dependencies: + "@babel/core" "^7.27.4" + "@jest/types" "30.2.0" + "@jridgewell/trace-mapping" "^0.3.25" + babel-plugin-istanbul "^7.0.1" + chalk "^4.1.2" + convert-source-map "^2.0.0" + fast-json-stable-stringify "^2.1.0" + graceful-fs "^4.2.11" + jest-haste-map "30.2.0" + jest-regex-util "30.0.1" + jest-util "30.2.0" + micromatch "^4.0.8" + pirates "^4.0.7" + slash "^3.0.0" + write-file-atomic "^5.0.1" + +"@jest/types@30.2.0": + version "30.2.0" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-30.2.0.tgz#1c678a7924b8f59eafd4c77d56b6d0ba976d62b8" + integrity sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg== + dependencies: + "@jest/pattern" "30.0.1" + "@jest/schemas" "30.0.5" + "@types/istanbul-lib-coverage" "^2.0.6" + "@types/istanbul-reports" "^3.0.4" + "@types/node" "*" + "@types/yargs" "^17.0.33" + chalk "^4.1.2" + +"@jridgewell/gen-mapping@^0.3.12", "@jridgewell/gen-mapping@^0.3.5": + version "0.3.13" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz#6342a19f44347518c93e43b1ac69deb3c4656a1f" + integrity sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA== + dependencies: + "@jridgewell/sourcemap-codec" "^1.5.0" + "@jridgewell/trace-mapping" "^0.3.24" + +"@jridgewell/remapping@^2.3.5": + version "2.3.5" + resolved "https://registry.yarnpkg.com/@jridgewell/remapping/-/remapping-2.3.5.tgz#375c476d1972947851ba1e15ae8f123047445aa1" + integrity sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ== + dependencies: + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.24" + +"@jridgewell/resolve-uri@^3.0.3", "@jridgewell/resolve-uri@^3.1.0": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== + +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.5.0": + version "1.5.5" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz#6912b00d2c631c0d15ce1a7ab57cd657f2a8f8ba" + integrity sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og== + +"@jridgewell/trace-mapping@0.3.9": + version "0.3.9" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" + integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== dependencies: - "@nodelib/fs.scandir" "2.1.5" - fastq "^1.6.0" + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" -"@pkgr/utils@^2.3.1": - version "2.4.2" - resolved "https://registry.npmjs.org/@pkgr/utils/-/utils-2.4.2.tgz" - integrity sha512-POgTXhjrTfbTV63DiFXav4lBHiICLKKwDeaKn9Nphwj7WH6m0hMMCaJkMyRWjgtPFyRKRVoMXXjczsTQRDEhYw== +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.23", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25", "@jridgewell/trace-mapping@^0.3.28": + version "0.3.31" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz#db15d6781c931f3a251a3dac39501c98a6082fd0" + integrity sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw== dependencies: - cross-spawn "^7.0.3" - fast-glob "^3.3.0" - is-glob "^4.0.3" - open "^9.1.0" - picocolors "^1.0.0" - tslib "^2.6.0" + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + +"@js-sdsl/ordered-map@^4.4.2": + version "4.4.2" + resolved "https://registry.yarnpkg.com/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz#9299f82874bab9e4c7f9c48d865becbfe8d6907c" + integrity sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw== + +"@kwsites/file-exists@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@kwsites/file-exists/-/file-exists-1.1.1.tgz#ad1efcac13e1987d8dbaf235ef3be5b0d96faa99" + integrity sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw== + dependencies: + debug "^4.1.1" + +"@napi-rs/nice-android-arm-eabi@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@napi-rs/nice-android-arm-eabi/-/nice-android-arm-eabi-1.1.1.tgz#4ebd966821cd6c2cc7cc020eb468de397bb9b40f" + integrity sha512-kjirL3N6TnRPv5iuHw36wnucNqXAO46dzK9oPb0wj076R5Xm8PfUVA9nAFB5ZNMmfJQJVKACAPd/Z2KYMppthw== + +"@napi-rs/nice-android-arm64@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@napi-rs/nice-android-arm64/-/nice-android-arm64-1.1.1.tgz#e183ba874512bc005852daab8b78c63e0a4288a8" + integrity sha512-blG0i7dXgbInN5urONoUCNf+DUEAavRffrO7fZSeoRMJc5qD+BJeNcpr54msPF6qfDD6kzs9AQJogZvT2KD5nw== + +"@napi-rs/nice-darwin-arm64@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@napi-rs/nice-darwin-arm64/-/nice-darwin-arm64-1.1.1.tgz#64b1585809774cbb8bf95cea3d4c8827c9897394" + integrity sha512-s/E7w45NaLqTGuOjC2p96pct4jRfo61xb9bU1unM/MJ/RFkKlJyJDx7OJI/O0ll/hrfpqKopuAFDV8yo0hfT7A== + +"@napi-rs/nice-darwin-x64@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@napi-rs/nice-darwin-x64/-/nice-darwin-x64-1.1.1.tgz#99c0c7f62cb1e23ca76881bb29cc6000aeccc6f0" + integrity sha512-dGoEBnVpsdcC+oHHmW1LRK5eiyzLwdgNQq3BmZIav+9/5WTZwBYX7r5ZkQC07Nxd3KHOCkgbHSh4wPkH1N1LiQ== + +"@napi-rs/nice-freebsd-x64@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@napi-rs/nice-freebsd-x64/-/nice-freebsd-x64-1.1.1.tgz#9a5ca0e3ced86207887c98a5a560de8cde5a909e" + integrity sha512-kHv4kEHAylMYmlNwcQcDtXjklYp4FCf0b05E+0h6nDHsZ+F0bDe04U/tXNOqrx5CmIAth4vwfkjjUmp4c4JktQ== + +"@napi-rs/nice-linux-arm-gnueabihf@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@napi-rs/nice-linux-arm-gnueabihf/-/nice-linux-arm-gnueabihf-1.1.1.tgz#b8a6a1bc88d0de3e99ac3fdea69980dc6e20b502" + integrity sha512-E1t7K0efyKXZDoZg1LzCOLxgolxV58HCkaEkEvIYQx12ht2pa8hoBo+4OB3qh7e+QiBlp1SRf+voWUZFxyhyqg== + +"@napi-rs/nice-linux-arm64-gnu@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@napi-rs/nice-linux-arm64-gnu/-/nice-linux-arm64-gnu-1.1.1.tgz#226f1ef30fcb80fa40370e843b75cc86e39e1183" + integrity sha512-CIKLA12DTIZlmTaaKhQP88R3Xao+gyJxNWEn04wZwC2wmRapNnxCUZkVwggInMJvtVElA+D4ZzOU5sX4jV+SmQ== + +"@napi-rs/nice-linux-arm64-musl@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@napi-rs/nice-linux-arm64-musl/-/nice-linux-arm64-musl-1.1.1.tgz#01345c3db79210ba5406c8729e8db75ed11c5f14" + integrity sha512-+2Rzdb3nTIYZ0YJF43qf2twhqOCkiSrHx2Pg6DJaCPYhhaxbLcdlV8hCRMHghQ+EtZQWGNcS2xF4KxBhSGeutg== + +"@napi-rs/nice-linux-ppc64-gnu@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@napi-rs/nice-linux-ppc64-gnu/-/nice-linux-ppc64-gnu-1.1.1.tgz#ce7a1025227daab491ded40784b561394d688fcb" + integrity sha512-4FS8oc0GeHpwvv4tKciKkw3Y4jKsL7FRhaOeiPei0X9T4Jd619wHNe4xCLmN2EMgZoeGg+Q7GY7BsvwKpL22Tg== + +"@napi-rs/nice-linux-riscv64-gnu@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@napi-rs/nice-linux-riscv64-gnu/-/nice-linux-riscv64-gnu-1.1.1.tgz#9bef5dc89a0425d03163853b4968dbb686d98fd5" + integrity sha512-HU0nw9uD4FO/oGCCk409tCi5IzIZpH2agE6nN4fqpwVlCn5BOq0MS1dXGjXaG17JaAvrlpV5ZeyZwSon10XOXw== + +"@napi-rs/nice-linux-s390x-gnu@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@napi-rs/nice-linux-s390x-gnu/-/nice-linux-s390x-gnu-1.1.1.tgz#247c8c7c45876877bdb337cfeb290ff4fd82de62" + integrity sha512-2YqKJWWl24EwrX0DzCQgPLKQBxYDdBxOHot1KWEq7aY2uYeX+Uvtv4I8xFVVygJDgf6/92h9N3Y43WPx8+PAgQ== + +"@napi-rs/nice-linux-x64-gnu@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@napi-rs/nice-linux-x64-gnu/-/nice-linux-x64-gnu-1.1.1.tgz#7fd1f5e037cb44ab4f5f95a3b3225a99e3248f12" + integrity sha512-/gaNz3R92t+dcrfCw/96pDopcmec7oCcAQ3l/M+Zxr82KT4DljD37CpgrnXV+pJC263JkW572pdbP3hP+KjcIg== + +"@napi-rs/nice-linux-x64-musl@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@napi-rs/nice-linux-x64-musl/-/nice-linux-x64-musl-1.1.1.tgz#d447cd7157ae5da5c0b15fc618bf61f0c344ff6f" + integrity sha512-xScCGnyj/oppsNPMnevsBe3pvNaoK7FGvMjT35riz9YdhB2WtTG47ZlbxtOLpjeO9SqqQ2J2igCmz6IJOD5JYw== + +"@napi-rs/nice-openharmony-arm64@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@napi-rs/nice-openharmony-arm64/-/nice-openharmony-arm64-1.1.1.tgz#1120e457d2cc6b2bc86ef0a697faefe2e194dfce" + integrity sha512-6uJPRVwVCLDeoOaNyeiW0gp2kFIM4r7PL2MczdZQHkFi9gVlgm+Vn+V6nTWRcu856mJ2WjYJiumEajfSm7arPQ== + +"@napi-rs/nice-win32-arm64-msvc@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@napi-rs/nice-win32-arm64-msvc/-/nice-win32-arm64-msvc-1.1.1.tgz#91e4cfecf339b43fa7934f0c8b19d04f4cdd9bc0" + integrity sha512-uoTb4eAvM5B2aj/z8j+Nv8OttPf2m+HVx3UjA5jcFxASvNhQriyCQF1OB1lHL43ZhW+VwZlgvjmP5qF3+59atA== + +"@napi-rs/nice-win32-ia32-msvc@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@napi-rs/nice-win32-ia32-msvc/-/nice-win32-ia32-msvc-1.1.1.tgz#ed9300bba074d3e3b0a077d6b157f2b4ff70af0e" + integrity sha512-CNQqlQT9MwuCsg1Vd/oKXiuH+TcsSPJmlAFc5frFyX/KkOh0UpBLEj7aoY656d5UKZQMQFP7vJNa1DNUNORvug== + +"@napi-rs/nice-win32-x64-msvc@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@napi-rs/nice-win32-x64-msvc/-/nice-win32-x64-msvc-1.1.1.tgz#8292b82fb46458618ccff5b8130f78974349541e" + integrity sha512-vB+4G/jBQCAh0jelMTY3+kgFy00Hlx2f2/1zjMoH821IbplbWZOkLiTYXQkygNTzQJTq5cvwBDgn2ppHD+bglQ== + +"@napi-rs/nice@^1.0.4": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@napi-rs/nice/-/nice-1.1.1.tgz#c1aacd631ecd4c500c959e3e7cfedd5c73bffe2a" + integrity sha512-xJIPs+bYuc9ASBl+cvGsKbGrJmS6fAKaSZCnT0lhahT5rhA2VVy9/EcIgd2JhtEuFOJNx7UHNn/qiTPTY4nrQw== + optionalDependencies: + "@napi-rs/nice-android-arm-eabi" "1.1.1" + "@napi-rs/nice-android-arm64" "1.1.1" + "@napi-rs/nice-darwin-arm64" "1.1.1" + "@napi-rs/nice-darwin-x64" "1.1.1" + "@napi-rs/nice-freebsd-x64" "1.1.1" + "@napi-rs/nice-linux-arm-gnueabihf" "1.1.1" + "@napi-rs/nice-linux-arm64-gnu" "1.1.1" + "@napi-rs/nice-linux-arm64-musl" "1.1.1" + "@napi-rs/nice-linux-ppc64-gnu" "1.1.1" + "@napi-rs/nice-linux-riscv64-gnu" "1.1.1" + "@napi-rs/nice-linux-s390x-gnu" "1.1.1" + "@napi-rs/nice-linux-x64-gnu" "1.1.1" + "@napi-rs/nice-linux-x64-musl" "1.1.1" + "@napi-rs/nice-openharmony-arm64" "1.1.1" + "@napi-rs/nice-win32-arm64-msvc" "1.1.1" + "@napi-rs/nice-win32-ia32-msvc" "1.1.1" + "@napi-rs/nice-win32-x64-msvc" "1.1.1" + +"@napi-rs/wasm-runtime@^0.2.11": + version "0.2.12" + resolved "https://registry.yarnpkg.com/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz#3e78a8b96e6c33a6c517e1894efbd5385a7cb6f2" + integrity sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ== + dependencies: + "@emnapi/core" "^1.4.3" + "@emnapi/runtime" "^1.4.3" + "@tybys/wasm-util" "^0.10.0" + +"@noble/curves@1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.2.0.tgz#92d7e12e4e49b23105a2555c6984d41733d65c35" + integrity sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw== + dependencies: + "@noble/hashes" "1.3.2" + +"@noble/curves@^1.4.2": + version "1.9.7" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.9.7.tgz#79d04b4758a43e4bca2cbdc62e7771352fa6b951" + integrity sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw== + dependencies: + "@noble/hashes" "1.8.0" + +"@noble/hashes@1.3.2": + version "1.3.2" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.2.tgz#6f26dbc8fbc7205873ce3cee2f690eba0d421b39" + integrity sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ== + +"@noble/hashes@1.8.0", "@noble/hashes@^1", "@noble/hashes@^1.0.0", "@noble/hashes@^1.4.0": + version "1.8.0" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.8.0.tgz#cee43d801fcef9644b11b8194857695acd5f815a" + integrity sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A== + +"@opentelemetry/api@^1.4.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/api/-/api-1.9.0.tgz#d03eba68273dc0f7509e2a3d5cba21eae10379fe" + integrity sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg== + +"@pkgjs/parseargs@^0.11.0": + version "0.11.0" + resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" + integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== + +"@pkgr/core@^0.2.9": + version "0.2.9" + resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.2.9.tgz#d229a7b7f9dac167a156992ef23c7f023653f53b" + integrity sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA== "@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": version "1.1.2" - resolved "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz" + resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" integrity sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ== "@protobufjs/base64@^1.1.2": version "1.1.2" - resolved "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz" + resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735" integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg== "@protobufjs/codegen@^2.0.4": version "2.0.4" - resolved "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz" + resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb" integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg== "@protobufjs/eventemitter@^1.1.0": version "1.1.0" - resolved "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz" + resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70" integrity sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q== "@protobufjs/fetch@^1.1.0": version "1.1.0" - resolved "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz" + resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45" integrity sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ== dependencies: "@protobufjs/aspromise" "^1.1.1" @@ -370,508 +1086,1530 @@ "@protobufjs/float@^1.0.2": version "1.0.2" - resolved "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1" integrity sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ== "@protobufjs/inquire@^1.1.0": version "1.1.0" - resolved "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz" + resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089" integrity sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q== "@protobufjs/path@^1.1.2": version "1.1.2" - resolved "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz" + resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d" integrity sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA== "@protobufjs/pool@^1.1.0": version "1.1.0" - resolved "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz" + resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54" integrity sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw== "@protobufjs/utf8@^1.1.0": version "1.1.0" - resolved "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz" + resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== -"@types/json-schema@^7.0.12": - version "7.0.13" - resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.13.tgz" - integrity sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ== +"@redis/bloom@1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@redis/bloom/-/bloom-1.2.0.tgz#d3fd6d3c0af3ef92f26767b56414a370c7b63b71" + integrity sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg== + +"@redis/client@1.6.1": + version "1.6.1" + resolved "https://registry.yarnpkg.com/@redis/client/-/client-1.6.1.tgz#c4636b7cb34e96008a988409b7e787364ae761a2" + integrity sha512-/KCsg3xSlR+nCK8/8ZYSknYxvXHwubJrU82F3Lm1Fp6789VQ0/3RJKfsmRXjqfaTA++23CvC3hqmqe/2GEt6Kw== + dependencies: + cluster-key-slot "1.1.2" + generic-pool "3.9.0" + yallist "4.0.0" + +"@redis/graph@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@redis/graph/-/graph-1.1.1.tgz#8c10df2df7f7d02741866751764031a957a170ea" + integrity sha512-FEMTcTHZozZciLRl6GiiIB4zGm5z5F3F6a6FZCyrfxdKOhFlGkiAqlexWMBzCi4DcRoyiOsuLfW+cjlGWyExOw== + +"@redis/json@1.0.7": + version "1.0.7" + resolved "https://registry.yarnpkg.com/@redis/json/-/json-1.0.7.tgz#016257fcd933c4cbcb9c49cde8a0961375c6893b" + integrity sha512-6UyXfjVaTBTJtKNG4/9Z8PSpKE6XgSyEb8iwaqDcy+uKrd/DGYHTWkUdnQDyzm727V7p21WUMhsqz5oy65kPcQ== + +"@redis/search@1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@redis/search/-/search-1.2.0.tgz#50976fd3f31168f585666f7922dde111c74567b8" + integrity sha512-tYoDBbtqOVigEDMAcTGsRlMycIIjwMCgD8eR2t0NANeQmgK/lvxNAvYyb6bZDD4frHRhIHkJu2TBRvB0ERkOmw== + +"@redis/time-series@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@redis/time-series/-/time-series-1.1.0.tgz#cba454c05ec201bd5547aaf55286d44682ac8eb5" + integrity sha512-c1Q99M5ljsIuc4YdaCwfUEXsofakb9c8+Zse2qxTadu8TalLXuAESzLvFAvNVbkmSlvlzIQOLpBCmWI9wTOt+g== + +"@sinclair/typebox@^0.34.0": + version "0.34.48" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.34.48.tgz#75b0ead87e59e1adbd6dccdc42bad4fddee73b59" + integrity sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA== + +"@sinonjs/commons@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-3.0.1.tgz#1029357e44ca901a615585f6d27738dbc89084cd" + integrity sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ== + dependencies: + type-detect "4.0.8" + +"@sinonjs/fake-timers@^13.0.0": + version "13.0.5" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-13.0.5.tgz#36b9dbc21ad5546486ea9173d6bea063eb1717d5" + integrity sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw== + dependencies: + "@sinonjs/commons" "^3.0.1" + +"@so-ric/colorspace@^1.1.6": + version "1.1.6" + resolved "https://registry.yarnpkg.com/@so-ric/colorspace/-/colorspace-1.1.6.tgz#62515d8b9f27746b76950a83bde1af812d91923b" + integrity sha512-/KiKkpHNOBgkFJwu9sh48LkHSMYGyuTcSFK/qMBdnOAlrRJzRSXAOFB5qwzaVQuDl8wAvHVMkaASQDReTahxuw== + dependencies: + color "^5.0.2" + text-hex "1.0.x" + +"@solana/buffer-layout@^4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@solana/buffer-layout/-/buffer-layout-4.0.1.tgz#b996235eaec15b1e0b5092a8ed6028df77fa6c15" + integrity sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA== + dependencies: + buffer "~6.0.3" + +"@solana/codecs-core@2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@solana/codecs-core/-/codecs-core-2.3.0.tgz#6bf2bb565cb1ae880f8018635c92f751465d8695" + integrity sha512-oG+VZzN6YhBHIoSKgS5ESM9VIGzhWjEHEGNPSibiDTxFhsFWxNaz8LbMDPjBUE69r9wmdGLkrQ+wVPbnJcZPvw== + dependencies: + "@solana/errors" "2.3.0" + +"@solana/codecs-numbers@^2.1.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@solana/codecs-numbers/-/codecs-numbers-2.3.0.tgz#ac7e7f38aaf7fcd22ce2061fbdcd625e73828dc6" + integrity sha512-jFvvwKJKffvG7Iz9dmN51OGB7JBcy2CJ6Xf3NqD/VP90xak66m/Lg48T01u5IQ/hc15mChVHiBm+HHuOFDUrQg== + dependencies: + "@solana/codecs-core" "2.3.0" + "@solana/errors" "2.3.0" + +"@solana/errors@2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@solana/errors/-/errors-2.3.0.tgz#4ac9380343dbeffb9dffbcb77c28d0e457c5fa31" + integrity sha512-66RI9MAbwYV0UtP7kGcTBVLxJgUxoZGm8Fbc0ah+lGiAw17Gugco6+9GrJCV83VyF2mDWyYnYM9qdI3yjgpnaQ== + dependencies: + chalk "^5.4.1" + commander "^14.0.0" + +"@solana/web3.js@^1.68.0": + version "1.98.4" + resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.98.4.tgz#df51d78be9d865181ec5138b4e699d48e6895bbe" + integrity sha512-vv9lfnvjUsRiq//+j5pBdXig0IQdtzA0BRZ3bXEP4KaIyF1CcaydWqgyzQgfZMNIsWNWmG+AUHwPy4AHOD6gpw== + dependencies: + "@babel/runtime" "^7.25.0" + "@noble/curves" "^1.4.2" + "@noble/hashes" "^1.4.0" + "@solana/buffer-layout" "^4.0.1" + "@solana/codecs-numbers" "^2.1.0" + agentkeepalive "^4.5.0" + bn.js "^5.2.1" + borsh "^0.7.0" + bs58 "^4.0.1" + buffer "6.0.3" + fast-stable-stringify "^1.0.0" + jayson "^4.1.1" + node-fetch "^2.7.0" + rpc-websockets "^9.0.2" + superstruct "^2.0.2" + +"@swc/helpers@^0.5.11": + version "0.5.19" + resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.19.tgz#9a8c8a0bdaecfdfb9b8ae5421c0c8e09246dfee9" + integrity sha512-QamiFeIK3txNjgUTNppE6MiG3p7TdninpZu0E0PbqVh1a9FNLT2FRhisaa4NcaX52XVhA5l7Pk58Ft7Sqi/2sA== + dependencies: + tslib "^2.8.0" + +"@tsconfig/node10@^1.0.7": + version "1.0.12" + resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.12.tgz#be57ceac1e4692b41be9de6be8c32a106636dba4" + integrity sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ== + +"@tsconfig/node12@^1.0.7": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d" + integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== + +"@tsconfig/node14@^1.0.0": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" + integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== + +"@tsconfig/node16@^1.0.2": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" + integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== + +"@tybys/wasm-util@^0.10.0": + version "0.10.1" + resolved "https://registry.yarnpkg.com/@tybys/wasm-util/-/wasm-util-0.10.1.tgz#ecddd3205cf1e2d5274649ff0eedd2991ed7f414" + integrity sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg== + dependencies: + tslib "^2.4.0" + +"@types/babel__core@^7.20.5": + version "7.20.5" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017" + integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA== + dependencies: + "@babel/parser" "^7.20.7" + "@babel/types" "^7.20.7" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.27.0" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.27.0.tgz#b5819294c51179957afaec341442f9341e4108a9" + integrity sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.4.tgz#5672513701c1b2199bc6dad636a9d7491586766f" + integrity sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.28.0.tgz#07d713d6cce0d265c9849db0cbe62d3f61f36f74" + integrity sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q== + dependencies: + "@babel/types" "^7.28.2" + +"@types/body-parser@*": + version "1.19.6" + resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.6.tgz#1859bebb8fd7dac9918a45d54c1971ab8b5af474" + integrity sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g== + dependencies: + "@types/connect" "*" + "@types/node" "*" + +"@types/connect@*", "@types/connect@^3.4.33": + version "3.4.38" + resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.38.tgz#5ba7f3bc4fbbdeaff8dded952e5ff2cc53f8d858" + integrity sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug== + dependencies: + "@types/node" "*" + +"@types/docker-modem@*": + version "3.0.6" + resolved "https://registry.yarnpkg.com/@types/docker-modem/-/docker-modem-3.0.6.tgz#1f9262fcf85425b158ca725699a03eb23cddbf87" + integrity sha512-yKpAGEuKRSS8wwx0joknWxsmLha78wNMe9R2S3UNsVOkZded8UqOrV8KoeDXoXsjndxwyF3eIhyClGbO1SEhEg== + dependencies: + "@types/node" "*" + "@types/ssh2" "*" + +"@types/dockerode@^4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@types/dockerode/-/dockerode-4.0.1.tgz#26a44995a86322b4489090efd97890a5585a63a5" + integrity sha512-cmUpB+dPN955PxBEuXE3f6lKO1hHiIGYJA46IVF3BJpNsZGvtBDcRnlrHYHtOH/B6vtDOyl2kZ2ShAu3mgc27Q== + dependencies: + "@types/docker-modem" "*" + "@types/node" "*" + "@types/ssh2" "*" + +"@types/esrecurse@^4.3.1": + version "4.3.1" + resolved "https://registry.yarnpkg.com/@types/esrecurse/-/esrecurse-4.3.1.tgz#6f636af962fbe6191b830bd676ba5986926bccec" + integrity sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw== + +"@types/estree@^1.0.6", "@types/estree@^1.0.8": + version "1.0.8" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.8.tgz#958b91c991b1867ced318bedea0e215ee050726e" + integrity sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w== + +"@types/express-serve-static-core@^5.0.0": + version "5.1.1" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-5.1.1.tgz#1a77faffee9572d39124933259be2523837d7eaa" + integrity sha512-v4zIMr/cX7/d2BpAEX3KNKL/JrT1s43s96lLvvdTmza1oEvDudCqK9aF/djc/SWgy8Yh0h30TZx5VpzqFCxk5A== + dependencies: + "@types/node" "*" + "@types/qs" "*" + "@types/range-parser" "*" + "@types/send" "*" + +"@types/express@^5.0.6": + version "5.0.6" + resolved "https://registry.yarnpkg.com/@types/express/-/express-5.0.6.tgz#2d724b2c990dcb8c8444063f3580a903f6d500cc" + integrity sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA== + dependencies: + "@types/body-parser" "*" + "@types/express-serve-static-core" "^5.0.0" + "@types/serve-static" "^2" + +"@types/http-errors@*": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.5.tgz#5b749ab2b16ba113423feb1a64a95dcd30398472" + integrity sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg== + +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.1", "@types/istanbul-lib-coverage@^2.0.6": + version "2.0.6" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz#7739c232a1fee9b4d3ce8985f314c0c6d33549d7" + integrity sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w== + +"@types/istanbul-lib-report@*": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz#53047614ae72e19fc0401d872de3ae2b4ce350bf" + integrity sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA== + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^3.0.4": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz#0f03e3d2f670fbdac586e34b433783070cc16f54" + integrity sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ== + dependencies: + "@types/istanbul-lib-report" "*" + +"@types/jest@^30.0.0": + version "30.0.0" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-30.0.0.tgz#5e85ae568006712e4ad66f25433e9bdac8801f1d" + integrity sha512-XTYugzhuwqWjws0CVz8QpM36+T+Dz5mTEBKhNs/esGLnCIlGdRy+Dq78NRjd7ls7r8BC8ZRMOrKlkO1hU0JOwA== + dependencies: + expect "^30.0.0" + pretty-format "^30.0.0" + +"@types/json-schema@^7.0.15": + version "7.0.15" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== "@types/long@^4.0.1": version "4.0.2" - resolved "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz" + resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.2.tgz#b74129719fc8d11c01868010082d483b7545591a" integrity sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA== -"@types/mocha@^10.0.1": - version "10.0.1" - resolved "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.1.tgz" - integrity sha512-/fvYntiO1GeICvqbQ3doGDIP97vWmvFt83GKguJ6prmQM2iXZfFcq6YE8KteFyRtX2/h5Hf91BYvPodJKFYv5Q== - -"@types/node@>=13.7.0", "@types/node@^20.4.5": - version "20.4.5" - resolved "https://registry.npmjs.org/@types/node/-/node-20.4.5.tgz" - integrity sha512-rt40Nk13II9JwQBdeYqmbn2Q6IVTA5uPhvSO+JVqdXw/6/4glI6oR9ezty/A9Hg5u7JH4OmYmuQ+XvjKm0Datg== - -"@types/semver@^7.5.0": - version "7.5.2" - resolved "https://registry.npmjs.org/@types/semver/-/semver-7.5.2.tgz" - integrity sha512-7aqorHYgdNO4DM36stTiGO3DvKoex9TQRwsJU6vMaFGyqpBA1MNZkz+PG3gaNUPpTAOYhT1WR7M1JyA3fbS9Cw== - -"@typescript-eslint/eslint-plugin@^6.7.2": - version "6.7.2" - resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.2.tgz" - integrity sha512-ooaHxlmSgZTM6CHYAFRlifqh1OAr3PAQEwi7lhYhaegbnXrnh7CDcHmc3+ihhbQC7H0i4JF0psI5ehzkF6Yl6Q== - dependencies: - "@eslint-community/regexpp" "^4.5.1" - "@typescript-eslint/scope-manager" "6.7.2" - "@typescript-eslint/type-utils" "6.7.2" - "@typescript-eslint/utils" "6.7.2" - "@typescript-eslint/visitor-keys" "6.7.2" - debug "^4.3.4" - graphemer "^1.4.0" - ignore "^5.2.4" - natural-compare "^1.4.0" - semver "^7.5.4" - ts-api-utils "^1.0.1" - -"@typescript-eslint/parser@^6.7.2": - version "6.7.2" - resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.7.2.tgz" - integrity sha512-KA3E4ox0ws+SPyxQf9iSI25R6b4Ne78ORhNHeVKrPQnoYsb9UhieoiRoJgrzgEeKGOXhcY1i8YtOeCHHTDa6Fw== - dependencies: - "@typescript-eslint/scope-manager" "6.7.2" - "@typescript-eslint/types" "6.7.2" - "@typescript-eslint/typescript-estree" "6.7.2" - "@typescript-eslint/visitor-keys" "6.7.2" - debug "^4.3.4" - -"@typescript-eslint/scope-manager@6.7.2": - version "6.7.2" - resolved "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.7.2.tgz" - integrity sha512-bgi6plgyZjEqapr7u2mhxGR6E8WCzKNUFWNh6fkpVe9+yzRZeYtDTbsIBzKbcxI+r1qVWt6VIoMSNZ4r2A+6Yw== - dependencies: - "@typescript-eslint/types" "6.7.2" - "@typescript-eslint/visitor-keys" "6.7.2" - -"@typescript-eslint/type-utils@6.7.2": - version "6.7.2" - resolved "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.7.2.tgz" - integrity sha512-36F4fOYIROYRl0qj95dYKx6kybddLtsbmPIYNK0OBeXv2j9L5nZ17j9jmfy+bIDHKQgn2EZX+cofsqi8NPATBQ== - dependencies: - "@typescript-eslint/typescript-estree" "6.7.2" - "@typescript-eslint/utils" "6.7.2" - debug "^4.3.4" - ts-api-utils "^1.0.1" - -"@typescript-eslint/types@6.7.2": - version "6.7.2" - resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.2.tgz" - integrity sha512-flJYwMYgnUNDAN9/GAI3l8+wTmvTYdv64fcH8aoJK76Y+1FCZ08RtI5zDerM/FYT5DMkAc+19E4aLmd5KqdFyg== - -"@typescript-eslint/typescript-estree@6.7.2": - version "6.7.2" - resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.2.tgz" - integrity sha512-kiJKVMLkoSciGyFU0TOY0fRxnp9qq1AzVOHNeN1+B9erKFCJ4Z8WdjAkKQPP+b1pWStGFqezMLltxO+308dJTQ== - dependencies: - "@typescript-eslint/types" "6.7.2" - "@typescript-eslint/visitor-keys" "6.7.2" - debug "^4.3.4" - globby "^11.1.0" - is-glob "^4.0.3" - semver "^7.5.4" - ts-api-utils "^1.0.1" - -"@typescript-eslint/utils@6.7.2": - version "6.7.2" - resolved "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.7.2.tgz" - integrity sha512-ZCcBJug/TS6fXRTsoTkgnsvyWSiXwMNiPzBUani7hDidBdj1779qwM1FIAmpH4lvlOZNF3EScsxxuGifjpLSWQ== - dependencies: - "@eslint-community/eslint-utils" "^4.4.0" - "@types/json-schema" "^7.0.12" - "@types/semver" "^7.5.0" - "@typescript-eslint/scope-manager" "6.7.2" - "@typescript-eslint/types" "6.7.2" - "@typescript-eslint/typescript-estree" "6.7.2" - semver "^7.5.4" +"@types/node@*", "@types/node@>=13.7.0": + version "25.3.5" + resolved "https://registry.yarnpkg.com/@types/node/-/node-25.3.5.tgz#beccb5915561f7a9970ace547ad44d6cdbf39b46" + integrity sha512-oX8xrhvpiyRCQkG1MFchB09f+cXftgIXb3a7UUa4Y3wpmZPw5tyZGTLWhlESOLq1Rq6oDlc8npVU2/9xiCuXMA== + dependencies: + undici-types "~7.18.0" + +"@types/node@22.7.5": + version "22.7.5" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.7.5.tgz#cfde981727a7ab3611a481510b473ae54442b92b" + integrity sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ== + dependencies: + undici-types "~6.19.2" + +"@types/node@^12.12.54": + version "12.20.55" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.55.tgz#c329cbd434c42164f846b909bd6f85b5537f6240" + integrity sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ== + +"@types/node@^18.11.18": + version "18.19.130" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.19.130.tgz#da4c6324793a79defb7a62cba3947ec5add00d59" + integrity sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg== + dependencies: + undici-types "~5.26.4" -"@typescript-eslint/visitor-keys@6.7.2": - version "6.7.2" - resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.2.tgz" - integrity sha512-uVw9VIMFBUTz8rIeaUT3fFe8xIUx8r4ywAdlQv1ifH+6acn/XF8Y6rwJ7XNmkNMDrTW+7+vxFFPIF40nJCVsMQ== +"@types/node@^20.5.0": + version "20.19.37" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.19.37.tgz#b4fb4033408dd97becce63ec932c9ec57a9e2919" + integrity sha512-8kzdPJ3FsNsVIurqBs7oodNnCEVbni9yUEkaHbgptDACOPW04jimGagZ51E6+lXUwJjgnBw+hyko/lkFWCldqw== dependencies: - "@typescript-eslint/types" "6.7.2" - eslint-visitor-keys "^3.4.1" + undici-types "~6.21.0" + +"@types/qs@*": + version "6.15.0" + resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.15.0.tgz#963ab61779843fe910639a50661b48f162bc7f79" + integrity sha512-JawvT8iBVWpzTrz3EGw9BTQFg3BQNmwERdKE22vlTxawwtbyUSlMppvZYKLZzB5zgACXdXxbD3m1bXaMqP/9ow== + +"@types/range-parser@*": + version "1.2.7" + resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.7.tgz#50ae4353eaaddc04044279812f52c8c65857dbcb" + integrity sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ== + +"@types/send@*": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@types/send/-/send-1.2.1.tgz#6a784e45543c18c774c049bff6d3dbaf045c9c74" + integrity sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ== + dependencies: + "@types/node" "*" + +"@types/serve-static@^2": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-2.2.0.tgz#d4a447503ead0d1671132d1ab6bd58b805d8de6a" + integrity sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ== + dependencies: + "@types/http-errors" "*" + "@types/node" "*" + +"@types/ssh2-streams@*": + version "0.1.13" + resolved "https://registry.yarnpkg.com/@types/ssh2-streams/-/ssh2-streams-0.1.13.tgz#f8d34a22be50fb8dbafbb2bbc289add0d22daa51" + integrity sha512-faHyY3brO9oLEA0QlcO8N2wT7R0+1sHWZvQ+y3rMLwdY1ZyS1z0W3t65j9PqT4HmQ6ALzNe7RZlNuCNE0wBSWA== + dependencies: + "@types/node" "*" + +"@types/ssh2@*": + version "1.15.5" + resolved "https://registry.yarnpkg.com/@types/ssh2/-/ssh2-1.15.5.tgz#6d8f45db2f39519b8d9377268fa71ed77d969686" + integrity sha512-N1ASjp/nXH3ovBHddRJpli4ozpk6UdDYIX4RJWFa9L1YKnzdhTlVmiGHm4DZnj/jLbqZpes4aeR30EFGQtvhQQ== + dependencies: + "@types/node" "^18.11.18" + +"@types/ssh2@^0.5.48": + version "0.5.52" + resolved "https://registry.yarnpkg.com/@types/ssh2/-/ssh2-0.5.52.tgz#9dbd8084e2a976e551d5e5e70b978ed8b5965741" + integrity sha512-lbLLlXxdCZOSJMCInKH2+9V/77ET2J6NPQHpFI0kda61Dd1KglJs+fPQBchizmzYSOJBgdTajhPqBO1xxLywvg== + dependencies: + "@types/node" "*" + "@types/ssh2-streams" "*" + +"@types/stack-utils@^2.0.3": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8" + integrity sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw== + +"@types/triple-beam@^1.3.2": + version "1.3.5" + resolved "https://registry.yarnpkg.com/@types/triple-beam/-/triple-beam-1.3.5.tgz#74fef9ffbaa198eb8b588be029f38b00299caa2c" + integrity sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw== + +"@types/uuid@^10.0.0": + version "10.0.0" + resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-10.0.0.tgz#e9c07fe50da0f53dc24970cca94d619ff03f6f6d" + integrity sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ== + +"@types/ws@^7.4.4": + version "7.4.7" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.4.7.tgz#f7c390a36f7a0679aa69de2d501319f4f8d9b702" + integrity sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww== + dependencies: + "@types/node" "*" + +"@types/ws@^8.2.2": + version "8.18.1" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.18.1.tgz#48464e4bf2ddfd17db13d845467f6070ffea4aa9" + integrity sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg== + dependencies: + "@types/node" "*" + +"@types/yargs-parser@*": + version "21.0.3" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.3.tgz#815e30b786d2e8f0dcd85fd5bcf5e1a04d008f15" + integrity sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ== + +"@types/yargs@^17.0.33": + version "17.0.35" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.35.tgz#07013e46aa4d7d7d50a49e15604c1c5340d4eb24" + integrity sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg== + dependencies: + "@types/yargs-parser" "*" + +"@typescript-eslint/eslint-plugin@8.56.1": + version "8.56.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.56.1.tgz#b1ce606d87221daec571e293009675992f0aae76" + integrity sha512-Jz9ZztpB37dNC+HU2HI28Bs9QXpzCz+y/twHOwhyrIRdbuVDxSytJNDl6z/aAKlaRIwC7y8wJdkBv7FxYGgi0A== + dependencies: + "@eslint-community/regexpp" "^4.12.2" + "@typescript-eslint/scope-manager" "8.56.1" + "@typescript-eslint/type-utils" "8.56.1" + "@typescript-eslint/utils" "8.56.1" + "@typescript-eslint/visitor-keys" "8.56.1" + ignore "^7.0.5" + natural-compare "^1.4.0" + ts-api-utils "^2.4.0" + +"@typescript-eslint/parser@8.56.1": + version "8.56.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.56.1.tgz#21d13b3d456ffb08614c1d68bb9a4f8d9237cdc7" + integrity sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg== + dependencies: + "@typescript-eslint/scope-manager" "8.56.1" + "@typescript-eslint/types" "8.56.1" + "@typescript-eslint/typescript-estree" "8.56.1" + "@typescript-eslint/visitor-keys" "8.56.1" + debug "^4.4.3" + +"@typescript-eslint/project-service@8.56.1": + version "8.56.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/project-service/-/project-service-8.56.1.tgz#65c8d645f028b927bfc4928593b54e2ecd809244" + integrity sha512-TAdqQTzHNNvlVFfR+hu2PDJrURiwKsUvxFn1M0h95BB8ah5jejas08jUWG4dBA68jDMI988IvtfdAI53JzEHOQ== + dependencies: + "@typescript-eslint/tsconfig-utils" "^8.56.1" + "@typescript-eslint/types" "^8.56.1" + debug "^4.4.3" + +"@typescript-eslint/scope-manager@8.56.1": + version "8.56.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.56.1.tgz#254df93b5789a871351335dd23e20bc164060f24" + integrity sha512-YAi4VDKcIZp0O4tz/haYKhmIDZFEUPOreKbfdAN3SzUDMcPhJ8QI99xQXqX+HoUVq8cs85eRKnD+rne2UAnj2w== + dependencies: + "@typescript-eslint/types" "8.56.1" + "@typescript-eslint/visitor-keys" "8.56.1" + +"@typescript-eslint/tsconfig-utils@8.56.1", "@typescript-eslint/tsconfig-utils@^8.56.1": + version "8.56.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.56.1.tgz#1afa830b0fada5865ddcabdc993b790114a879b7" + integrity sha512-qOtCYzKEeyr3aR9f28mPJqBty7+DBqsdd63eO0yyDwc6vgThj2UjWfJIcsFeSucYydqcuudMOprZ+x1SpF3ZuQ== + +"@typescript-eslint/type-utils@8.56.1": + version "8.56.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.56.1.tgz#7a6c4fabf225d674644931e004302cbbdd2f2e24" + integrity sha512-yB/7dxi7MgTtGhZdaHCemf7PuwrHMenHjmzgUW1aJpO+bBU43OycnM3Wn+DdvDO/8zzA9HlhaJ0AUGuvri4oGg== + dependencies: + "@typescript-eslint/types" "8.56.1" + "@typescript-eslint/typescript-estree" "8.56.1" + "@typescript-eslint/utils" "8.56.1" + debug "^4.4.3" + ts-api-utils "^2.4.0" + +"@typescript-eslint/types@8.56.1", "@typescript-eslint/types@^8.56.1": + version "8.56.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.56.1.tgz#975e5942bf54895291337c91b9191f6eb0632ab9" + integrity sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw== + +"@typescript-eslint/typescript-estree@8.56.1": + version "8.56.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.56.1.tgz#3b9e57d8129a860c50864c42188f761bdef3eab0" + integrity sha512-qzUL1qgalIvKWAf9C1HpvBjif+Vm6rcT5wZd4VoMb9+Km3iS3Cv9DY6dMRMDtPnwRAFyAi7YXJpTIEXLvdfPxg== + dependencies: + "@typescript-eslint/project-service" "8.56.1" + "@typescript-eslint/tsconfig-utils" "8.56.1" + "@typescript-eslint/types" "8.56.1" + "@typescript-eslint/visitor-keys" "8.56.1" + debug "^4.4.3" + minimatch "^10.2.2" + semver "^7.7.3" + tinyglobby "^0.2.15" + ts-api-utils "^2.4.0" + +"@typescript-eslint/utils@8.56.1": + version "8.56.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.56.1.tgz#5a86acaf9f1b4c4a85a42effb217f73059f6deb7" + integrity sha512-HPAVNIME3tABJ61siYlHzSWCGtOoeP2RTIaHXFMPqjrQKCGB9OgUVdiNgH7TJS2JNIQ5qQ4RsAUDuGaGme/KOA== + dependencies: + "@eslint-community/eslint-utils" "^4.9.1" + "@typescript-eslint/scope-manager" "8.56.1" + "@typescript-eslint/types" "8.56.1" + "@typescript-eslint/typescript-estree" "8.56.1" + +"@typescript-eslint/visitor-keys@8.56.1": + version "8.56.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.56.1.tgz#50e03475c33a42d123dc99e63acf1841c0231f87" + integrity sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw== + dependencies: + "@typescript-eslint/types" "8.56.1" + eslint-visitor-keys "^5.0.0" + +"@ungap/structured-clone@^1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.3.0.tgz#d06bbb384ebcf6c505fde1c3d0ed4ddffe0aaff8" + integrity sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g== + +"@unrs/resolver-binding-android-arm-eabi@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz#9f5b04503088e6a354295e8ea8fe3cb99e43af81" + integrity sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw== + +"@unrs/resolver-binding-android-arm64@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.11.1.tgz#7414885431bd7178b989aedc4d25cccb3865bc9f" + integrity sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g== + +"@unrs/resolver-binding-darwin-arm64@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz#b4a8556f42171fb9c9f7bac8235045e82aa0cbdf" + integrity sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g== + +"@unrs/resolver-binding-darwin-x64@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.11.1.tgz#fd4d81257b13f4d1a083890a6a17c00de571f0dc" + integrity sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ== + +"@unrs/resolver-binding-freebsd-x64@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.11.1.tgz#d2513084d0f37c407757e22f32bd924a78cfd99b" + integrity sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw== + +"@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.11.1.tgz#844d2605d057488d77fab09705f2866b86164e0a" + integrity sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw== + +"@unrs/resolver-binding-linux-arm-musleabihf@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.11.1.tgz#204892995cefb6bd1d017d52d097193bc61ddad3" + integrity sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw== + +"@unrs/resolver-binding-linux-arm64-gnu@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.11.1.tgz#023eb0c3aac46066a10be7a3f362e7b34f3bdf9d" + integrity sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ== + +"@unrs/resolver-binding-linux-arm64-musl@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.11.1.tgz#9e6f9abb06424e3140a60ac996139786f5d99be0" + integrity sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w== + +"@unrs/resolver-binding-linux-ppc64-gnu@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.11.1.tgz#b111417f17c9d1b02efbec8e08398f0c5527bb44" + integrity sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA== + +"@unrs/resolver-binding-linux-riscv64-gnu@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.11.1.tgz#92ffbf02748af3e99873945c9a8a5ead01d508a9" + integrity sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ== + +"@unrs/resolver-binding-linux-riscv64-musl@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.11.1.tgz#0bec6f1258fc390e6b305e9ff44256cb207de165" + integrity sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew== + +"@unrs/resolver-binding-linux-s390x-gnu@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.11.1.tgz#577843a084c5952f5906770633ccfb89dac9bc94" + integrity sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg== + +"@unrs/resolver-binding-linux-x64-gnu@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz#36fb318eebdd690f6da32ac5e0499a76fa881935" + integrity sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w== + +"@unrs/resolver-binding-linux-x64-musl@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.1.tgz#bfb9af75f783f98f6a22c4244214efe4df1853d6" + integrity sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA== + +"@unrs/resolver-binding-wasm32-wasi@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.11.1.tgz#752c359dd875684b27429500d88226d7cc72f71d" + integrity sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ== + dependencies: + "@napi-rs/wasm-runtime" "^0.2.11" + +"@unrs/resolver-binding-win32-arm64-msvc@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.11.1.tgz#ce5735e600e4c2fbb409cd051b3b7da4a399af35" + integrity sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw== + +"@unrs/resolver-binding-win32-ia32-msvc@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.11.1.tgz#72fc57bc7c64ec5c3de0d64ee0d1810317bc60a6" + integrity sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ== + +"@unrs/resolver-binding-win32-x64-msvc@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz#538b1e103bf8d9864e7b85cc96fa8d6fb6c40777" + integrity sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g== abort-controller@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== dependencies: event-target-shim "^5.0.0" +accepts@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-2.0.0.tgz#bbcf4ba5075467f3f2131eab3cffc73c2f5d7895" + integrity sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng== + dependencies: + mime-types "^3.0.0" + negotiator "^1.0.0" + acorn-jsx@^5.3.2: version "5.3.2" - resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== -acorn@^8.9.0: - version "8.10.0" - resolved "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz" - integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw== +acorn-walk@^8.1.1: + version "8.3.5" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.5.tgz#8a6b8ca8fc5b34685af15dabb44118663c296496" + integrity sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw== + dependencies: + acorn "^8.11.0" -ajv@^6.12.4: - version "6.12.6" - resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" - integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== +acorn@^8.11.0, acorn@^8.16.0, acorn@^8.4.1: + version "8.16.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.16.0.tgz#4ce79c89be40afe7afe8f3adb902a1f1ce9ac08a" + integrity sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw== + +aes-js@4.0.0-beta.5: + version "4.0.0-beta.5" + resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-4.0.0-beta.5.tgz#8d2452c52adedebc3a3e28465d858c11ca315873" + integrity sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q== + +agentkeepalive@^4.5.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.6.0.tgz#35f73e94b3f40bf65f105219c623ad19c136ea6a" + integrity sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ== + dependencies: + humanize-ms "^1.2.1" + +ajv@^6.14.0: + version "6.14.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.14.0.tgz#fd067713e228210636ebb08c60bd3765d6dbe73a" + integrity sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw== dependencies: fast-deep-equal "^3.1.1" fast-json-stable-stringify "^2.0.0" json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ansi-colors@4.1.1: - version "4.1.1" - resolved "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz" - integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== +ansi-escapes@^4.3.2: + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + +ansi-escapes@^7.0.0: + version "7.3.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-7.3.0.tgz#5395bb74b2150a4a1d6e3c2565f4aeca78d28627" + integrity sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg== + dependencies: + environment "^1.0.0" ansi-regex@^5.0.1: version "5.0.1" - resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== +ansi-regex@^6.2.2: + version "6.2.2" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.2.2.tgz#60216eea464d864597ce2832000738a0589650c1" + integrity sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg== + ansi-styles@^4.0.0, ansi-styles@^4.1.0: version "4.3.0" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== dependencies: color-convert "^2.0.1" -anymatch@~3.1.2: +ansi-styles@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" + integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== + +ansi-styles@^6.1.0, ansi-styles@^6.2.1, ansi-styles@^6.2.3: + version "6.2.3" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.3.tgz#c044d5dcc521a076413472597a1acb1f103c4041" + integrity sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg== + +anymatch@^3.1.3: version "3.1.3" - resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== dependencies: normalize-path "^3.0.0" picomatch "^2.0.4" -argparse@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz" - integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== +archiver-utils@^5.0.0, archiver-utils@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/archiver-utils/-/archiver-utils-5.0.2.tgz#63bc719d951803efc72cf961a56ef810760dd14d" + integrity sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA== + dependencies: + glob "^10.0.0" + graceful-fs "^4.2.0" + is-stream "^2.0.1" + lazystream "^1.0.0" + lodash "^4.17.15" + normalize-path "^3.0.0" + readable-stream "^4.0.0" -array-union@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz" - integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== +archiver@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/archiver/-/archiver-7.0.1.tgz#c9d91c350362040b8927379c7aa69c0655122f61" + integrity sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ== + dependencies: + archiver-utils "^5.0.2" + async "^3.2.4" + buffer-crc32 "^1.0.0" + readable-stream "^4.0.0" + readdir-glob "^1.1.2" + tar-stream "^3.0.0" + zip-stream "^6.0.1" + +arg@^4.1.0: + version "4.1.3" + resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" + integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +asn1@^0.2.6: + version "0.2.6" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.6.tgz#0d3a7bb6e64e02a90c0303b31f292868ea09a08d" + integrity sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ== + dependencies: + safer-buffer "~2.1.0" + +async-lock@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/async-lock/-/async-lock-1.4.1.tgz#56b8718915a9b68b10fce2f2a9a3dddf765ef53f" + integrity sha512-Az2ZTpuytrtqENulXwO3GGv1Bztugx6TT37NIo7imr/Qo0gsYiGtSdBa2B6fsXhTpVZDNfu1Qn3pk531e3q+nQ== + +async@^3.2.3, async@^3.2.4: + version "3.2.6" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.6.tgz#1b0728e14929d51b85b449b7f06e27c1145e38ce" + integrity sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA== asynckit@^0.4.0: version "0.4.0" - resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== -atomic-sleep@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz" - integrity sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ== +axios@1.7.4: + version "1.7.4" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.4.tgz#4c8ded1b43683c8dd362973c393f3ede24052aa2" + integrity sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw== + dependencies: + follow-redirects "^1.15.6" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + +axios@^1.11.0, axios@^1.6.0: + version "1.13.6" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.13.6.tgz#c3f92da917dc209a15dd29936d20d5089b6b6c98" + integrity sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ== + dependencies: + follow-redirects "^1.15.11" + form-data "^4.0.5" + proxy-from-env "^1.1.0" + +b4a@^1.6.4: + version "1.8.0" + resolved "https://registry.yarnpkg.com/b4a/-/b4a-1.8.0.tgz#1ca3ba0edc9469aaabef5647e769a83d50180b1a" + integrity sha512-qRuSmNSkGQaHwNbM7J78Wwy+ghLEYF1zNrSeMxj4Kgw6y33O3mXcQ6Ie9fRvfU/YnxWkOchPXbaLb73TkIsfdg== + +babel-jest@30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-30.2.0.tgz#fd44a1ec9552be35ead881f7381faa7d8f3b95ac" + integrity sha512-0YiBEOxWqKkSQWL9nNGGEgndoeL0ZpWrbLMNL5u/Kaxrli3Eaxlt3ZtIDktEvXt4L/R9r3ODr2zKwGM/2BjxVw== + dependencies: + "@jest/transform" "30.2.0" + "@types/babel__core" "^7.20.5" + babel-plugin-istanbul "^7.0.1" + babel-preset-jest "30.2.0" + chalk "^4.1.2" + graceful-fs "^4.2.11" + slash "^3.0.0" + +babel-plugin-istanbul@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-7.0.1.tgz#d8b518c8ea199364cf84ccc82de89740236daf92" + integrity sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@istanbuljs/load-nyc-config" "^1.0.0" + "@istanbuljs/schema" "^0.1.3" + istanbul-lib-instrument "^6.0.2" + test-exclude "^6.0.0" + +babel-plugin-jest-hoist@30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-30.2.0.tgz#94c250d36b43f95900f3a219241e0f4648191ce2" + integrity sha512-ftzhzSGMUnOzcCXd6WHdBGMyuwy15Wnn0iyyWGKgBDLxf9/s5ABuraCSpBX2uG0jUg4rqJnxsLc5+oYBqoxVaA== + dependencies: + "@types/babel__core" "^7.20.5" + +babel-preset-current-node-syntax@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz#20730d6cdc7dda5d89401cab10ac6a32067acde6" + integrity sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg== + dependencies: + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-bigint" "^7.8.3" + "@babel/plugin-syntax-class-properties" "^7.12.13" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + "@babel/plugin-syntax-import-attributes" "^7.24.7" + "@babel/plugin-syntax-import-meta" "^7.10.4" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + "@babel/plugin-syntax-top-level-await" "^7.14.5" + +babel-preset-jest@30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-30.2.0.tgz#04717843e561347781d6d7f69c81e6bcc3ed11ce" + integrity sha512-US4Z3NOieAQumwFnYdUWKvUKh8+YSnS/gB3t6YBiz0bskpu7Pine8pPCheNxlPEW4wnUkma2a94YuW2q3guvCQ== + dependencies: + babel-plugin-jest-hoist "30.2.0" + babel-preset-current-node-syntax "^1.2.0" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== -axios@1.6.0: - version "1.6.0" - resolved "https://registry.npmjs.org/axios/-/axios-1.6.0.tgz" - integrity sha512-EZ1DYihju9pwVB+jg67ogm+Tmqc6JmhamRN6I4Zt8DfZu5lbcQGw3ozH9lFejSJgs/ibaef3A9PMXPLeefFGJg== +balanced-match@^4.0.2: + version "4.0.4" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-4.0.4.tgz#bfb10662feed8196a2c62e7c68e17720c274179a" + integrity sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA== + +bare-events@^2.5.4, bare-events@^2.7.0: + version "2.8.2" + resolved "https://registry.yarnpkg.com/bare-events/-/bare-events-2.8.2.tgz#7b3e10bd8e1fc80daf38bb516921678f566ab89f" + integrity sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ== + +bare-fs@^4.0.1, bare-fs@^4.5.5: + version "4.5.5" + resolved "https://registry.yarnpkg.com/bare-fs/-/bare-fs-4.5.5.tgz#589a8f87a32af0266aa474413c8d7d11d50e4a65" + integrity sha512-XvwYM6VZqKoqDll8BmSww5luA5eflDzY0uEFfBJtFKe4PAAtxBjU3YIxzIBzhyaEQBy1VXEQBto4cpN5RZJw+w== + dependencies: + bare-events "^2.5.4" + bare-path "^3.0.0" + bare-stream "^2.6.4" + bare-url "^2.2.2" + fast-fifo "^1.3.2" + +bare-os@^3.0.1: + version "3.7.1" + resolved "https://registry.yarnpkg.com/bare-os/-/bare-os-3.7.1.tgz#ec06b7b91a6638e307859803456a49760740a58f" + integrity sha512-ebvMaS5BgZKmJlvuWh14dg9rbUI84QeV3WlWn6Ph6lFI8jJoh7ADtVTyD2c93euwbe+zgi0DVrl4YmqXeM9aIA== + +bare-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/bare-path/-/bare-path-3.0.0.tgz#b59d18130ba52a6af9276db3e96a2e3d3ea52178" + integrity sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw== dependencies: - follow-redirects "^1.15.0" - form-data "^4.0.0" - proxy-from-env "^1.1.0" + bare-os "^3.0.1" -axios@^0.21.2: - version "0.21.4" - resolved "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz" - integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg== +bare-stream@^2.6.4: + version "2.8.0" + resolved "https://registry.yarnpkg.com/bare-stream/-/bare-stream-2.8.0.tgz#3ac6141a65d097fd2bf6e472c848c5d800d47df9" + integrity sha512-reUN0M2sHRqCdG4lUK3Fw8w98eeUIZHL5c3H7Mbhk2yVBL+oofgaIp0ieLfD5QXwPCypBpmEEKU2WZKzbAk8GA== dependencies: - follow-redirects "^1.14.0" + streamx "^2.21.0" + teex "^1.0.1" -axios@^1.4.0: - version "1.6.1" - resolved "https://registry.npmjs.org/axios/-/axios-1.6.1.tgz" - integrity sha512-vfBmhDpKafglh0EldBEbVuoe7DyAavGSLWhuSm5ZSEKQnHhBf0xAAwybbNH1IkrJNGnS/VG4I5yxig1pCEXE4g== +bare-url@^2.2.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/bare-url/-/bare-url-2.3.2.tgz#4aef382efa662b2180a6fe4ca07a71b39bdf7ca3" + integrity sha512-ZMq4gd9ngV5aTMa5p9+UfY0b3skwhHELaDkhEHetMdX0LRkW9kzaym4oo/Eh+Ghm0CCDuMTsRIGM/ytUc1ZYmw== dependencies: - follow-redirects "^1.15.0" - form-data "^4.0.0" - proxy-from-env "^1.1.0" + bare-path "^3.0.0" -axios@^1.6.0: - version "1.6.7" - resolved "https://registry.npmjs.org/axios/-/axios-1.6.7.tgz" - integrity sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA== +base-x@^3.0.2: + version "3.0.11" + resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.11.tgz#40d80e2a1aeacba29792ccc6c5354806421287ff" + integrity sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA== dependencies: - follow-redirects "^1.15.4" - form-data "^4.0.0" - proxy-from-env "^1.1.0" - -balanced-match@^1.0.0: - version "1.0.2" - resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" - integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + safe-buffer "^5.0.1" base64-js@^1.3.0, base64-js@^1.3.1: version "1.5.1" - resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== +baseline-browser-mapping@^2.9.0: + version "2.10.0" + resolved "https://registry.yarnpkg.com/baseline-browser-mapping/-/baseline-browser-mapping-2.10.0.tgz#5b09935025bf8a80e29130251e337c6a7fc8cbb9" + integrity sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA== + +bcrypt-pbkdf@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + integrity sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w== + dependencies: + tweetnacl "^0.14.3" + bech32@^1.1.4: version "1.1.4" - resolved "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz" + resolved "https://registry.yarnpkg.com/bech32/-/bech32-1.1.4.tgz#e38c9f37bf179b8eb16ae3a772b40c356d4832e9" integrity sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ== -big-integer@^1.6.44: - version "1.6.51" - resolved "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz" - integrity sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg== +bintrees@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/bintrees/-/bintrees-1.0.2.tgz#49f896d6e858a4a499df85c38fb399b9aff840f8" + integrity sha512-VOMgTMwjAaUG580SXn3LacVgjurrbMme7ZZNYGSSV7mmtY6QQRh0Eg3pwIcntQ77DErK1L0NxkbetjcoXzVwKw== -binary-extensions@^2.0.0: - version "2.2.0" - resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz" - integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== +bl@^4.0.3: + version "4.1.0" + resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" + integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== + dependencies: + buffer "^5.5.0" + inherits "^2.0.4" + readable-stream "^3.4.0" bn.js@^4.11.9: - version "4.12.0" - resolved "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz" - integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== - -bn.js@^5.2.0: - version "5.2.1" - resolved "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz" - integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== - -bplist-parser@^0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz" - integrity sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw== + version "4.12.3" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.3.tgz#2cc2c679188eb35b006f2d0d4710bed8437a769e" + integrity sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g== + +bn.js@^5.2.0, bn.js@^5.2.1: + version "5.2.3" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.3.tgz#16a9e409616b23fef3ccbedb8d42f13bff80295e" + integrity sha512-EAcmnPkxpntVL+DS7bO1zhcZNvCkxqtkd0ZY53h06GNQ3DEkkGZ/gKgmDv6DdZQGj9BgfSPKtJJ7Dp1GPP8f7w== + +body-parser@^2.2.1: + version "2.2.2" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-2.2.2.tgz#1a32cdb966beaf68de50a9dfbe5b58f83cb8890c" + integrity sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA== + dependencies: + bytes "^3.1.2" + content-type "^1.0.5" + debug "^4.4.3" + http-errors "^2.0.0" + iconv-lite "^0.7.0" + on-finished "^2.4.1" + qs "^6.14.1" + raw-body "^3.0.1" + type-is "^2.0.1" + +borsh@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/borsh/-/borsh-0.7.0.tgz#6e9560d719d86d90dc589bca60ffc8a6c51fec2a" + integrity sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA== dependencies: - big-integer "^1.6.44" + bn.js "^5.2.0" + bs58 "^4.0.0" + text-encoding-utf-8 "^1.0.2" brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + version "1.1.12" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.12.tgz#ab9b454466e5a8cc3a187beaad580412a9c5b843" + integrity sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg== dependencies: balanced-match "^1.0.0" concat-map "0.0.1" -brace-expansion@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz" - integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== +brace-expansion@^2.0.1, brace-expansion@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.2.tgz#54fc53237a613d854c7bd37463aad17df87214e7" + integrity sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ== dependencies: balanced-match "^1.0.0" -braces@^3.0.2, braces@~3.0.2: +brace-expansion@^5.0.2: + version "5.0.4" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-5.0.4.tgz#614daaecd0a688f660bbbc909a8748c3d80d4336" + integrity sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg== + dependencies: + balanced-match "^4.0.2" + +braces@^3.0.3: version "3.0.3" - resolved "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== dependencies: fill-range "^7.1.1" brorand@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w== -browser-stdout@1.3.1: - version "1.3.1" - resolved "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz" - integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== +browserslist@^4.24.0: + version "4.28.1" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.28.1.tgz#7f534594628c53c63101079e27e40de490456a95" + integrity sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA== + dependencies: + baseline-browser-mapping "^2.9.0" + caniuse-lite "^1.0.30001759" + electron-to-chromium "^1.5.263" + node-releases "^2.0.27" + update-browserslist-db "^1.2.0" + +bs-logger@^0.2.6: + version "0.2.6" + resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" + integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== + dependencies: + fast-json-stable-stringify "2.x" + +bs58@^4.0.0, bs58@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a" + integrity sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw== + dependencies: + base-x "^3.0.2" + +bser@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" + integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== + dependencies: + node-int64 "^0.4.0" + +buffer-crc32@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-1.0.0.tgz#a10993b9055081d55304bd9feb4a072de179f405" + integrity sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w== + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== -buffer@^6.0.3: +buffer@6.0.3, buffer@^6.0.3, buffer@~6.0.3: version "6.0.3" - resolved "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== dependencies: base64-js "^1.3.1" ieee754 "^1.2.1" -bundle-name@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/bundle-name/-/bundle-name-3.0.0.tgz" - integrity sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw== +buffer@^5.5.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.1.13" + +bufferutil@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.1.0.tgz#a4623541dd23867626bb08a051ec0d2ec0b70294" + integrity sha512-ZMANVnAixE6AWWnPzlW2KpUrxhm9woycYvPOo67jWHyFowASTEd9s+QN1EIMsSDtwhIxN4sWE1jotpuDUIgyIw== + dependencies: + node-gyp-build "^4.3.0" + +buildcheck@~0.0.6: + version "0.0.7" + resolved "https://registry.yarnpkg.com/buildcheck/-/buildcheck-0.0.7.tgz#07a5e76c10ead8fa67d9e4c587b68f49e8f29d61" + integrity sha512-lHblz4ahamxpTmnsk+MNTRWsjYKv965MwOrSJyeD588rR3Jcu7swE+0wN5F+PbL5cjgu/9ObkhfzEPuofEMwLA== + +byline@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/byline/-/byline-5.0.0.tgz#741c5216468eadc457b03410118ad77de8c1ddb1" + integrity sha512-s6webAy+R4SR8XVuJWt2V2rGvhnrhxN+9S15GNuTK3wKPOXFF6RNc+8ug2XhH+2s4f+uudG4kUVYmYOQWL2g0Q== + +bytes@^3.1.2, bytes@~3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" + integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== + +call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz#4b5428c222be985d79c3d82657479dbe0b59b2d6" + integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + +call-bound@^1.0.2: + version "1.0.4" + resolved "https://registry.yarnpkg.com/call-bound/-/call-bound-1.0.4.tgz#238de935d2a2a692928c538c7ccfa91067fd062a" + integrity sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg== dependencies: - run-applescript "^5.0.0" + call-bind-apply-helpers "^1.0.2" + get-intrinsic "^1.3.0" -callsites@^3.0.0: +callsites@^3.1.0: version "3.1.0" - resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== -camelcase@^6.0.0: +camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +camelcase@^6.3.0: version "6.3.0" - resolved "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== -chalk@^4.0.0, chalk@^4.1.0: +caniuse-lite@^1.0.30001759: + version "1.0.30001777" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001777.tgz#028f21e4b2718d138b55e692583e6810ccf60691" + integrity sha512-tmN+fJxroPndC74efCdp12j+0rk0RHwV5Jwa1zWaFVyw2ZxAuPeG8ZgWC3Wz7uSjT3qMRQ5XHZ4COgQmsCMJAQ== + +chalk@^4.1.2: version "4.1.2" - resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== dependencies: ansi-styles "^4.1.0" supports-color "^7.1.0" -chokidar@3.5.3: - version "3.5.3" - resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz" - integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== - dependencies: - anymatch "~3.1.2" - braces "~3.0.2" - glob-parent "~5.1.2" - is-binary-path "~2.1.0" - is-glob "~4.0.1" - normalize-path "~3.0.0" - readdirp "~3.6.0" - optionalDependencies: - fsevents "~2.3.2" +chalk@^5.4.1: + version "5.6.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.6.2.tgz#b1238b6e23ea337af71c7f8a295db5af0c158aea" + integrity sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA== + +char-regex@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" + integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== + +chownr@^1.1.1: + version "1.1.4" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" + integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== + +ci-info@^4.2.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-4.4.0.tgz#7d54eff9f54b45b62401c26032696eb59c8bd18c" + integrity sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg== + +cjs-module-lexer@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-2.2.0.tgz#b3ca5101843389259ade7d88c77bd06ce55849ca" + integrity sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ== + +cli-cursor@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-5.0.0.tgz#24a4831ecf5a6b01ddeb32fb71a4b2088b0dce38" + integrity sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw== + dependencies: + restore-cursor "^5.0.0" + +cli-truncate@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-5.2.0.tgz#c8e72aaca8339c773d128c36e0a17c6315b694eb" + integrity sha512-xRwvIOMGrfOAnM1JYtqQImuaNtDEv9v6oIYAs4LIHwTiKee8uwvIi363igssOC0O5U04i4AlENs79LQLu9tEMw== + dependencies: + slice-ansi "^8.0.0" + string-width "^8.2.0" cliui@^7.0.2: version "7.0.4" - resolved "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== dependencies: string-width "^4.2.0" strip-ansi "^6.0.0" wrap-ansi "^7.0.0" +cliui@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + +cluster-key-slot@1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz#88ddaa46906e303b5de30d3153b7d9fe0a0c19ac" + integrity sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA== + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== + +collect-v8-coverage@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz#cc1f01eb8d02298cbc9a437c74c70ab4e5210b80" + integrity sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw== + color-convert@^2.0.1: version "2.0.1" - resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== dependencies: color-name "~1.1.4" +color-convert@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-3.1.3.tgz#db6627b97181cb8facdfce755ae26f97ab0711f1" + integrity sha512-fasDH2ont2GqF5HpyO4w0+BcewlhHEZOFn9c1ckZdHpJ56Qb7MHhH/IcJZbBGgvdtwdwNbLvxiBEdg336iA9Sg== + dependencies: + color-name "^2.0.0" + +color-name@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-2.1.0.tgz#0b677385c1c4b4edfdeaf77e38fa338e3a40b693" + integrity sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg== + color-name@~1.1.4: version "1.1.4" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +color-string@^2.1.3: + version "2.1.4" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-2.1.4.tgz#9dcf566ff976e23368c8bd673f5c35103ab41058" + integrity sha512-Bb6Cq8oq0IjDOe8wJmi4JeNn763Xs9cfrBcaylK1tPypWzyoy2G3l90v9k64kjphl/ZJjPIShFztenRomi8WTg== + dependencies: + color-name "^2.0.0" + +color@^5.0.2: + version "5.0.3" + resolved "https://registry.yarnpkg.com/color/-/color-5.0.3.tgz#f79390b1b778e222ffbb54304d3dbeaef633f97f" + integrity sha512-ezmVcLR3xAVp8kYOm4GS45ZLLgIE6SPAFoduLr6hTDajwb3KZ2F46gulK3XpcwRFb5KKGCSezCBAY4Dw4HsyXA== + dependencies: + color-convert "^3.1.3" + color-string "^2.1.3" + +colorette@^2.0.20: + version "2.0.20" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" + integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== + combined-stream@^1.0.8: version "1.0.8" - resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== dependencies: delayed-stream "~1.0.0" +commander@^14.0.0, commander@^14.0.3: + version "14.0.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-14.0.3.tgz#425d79b48f9af82fcd9e4fc1ea8af6c5ec07bbc2" + integrity sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw== + +commander@^2.20.3: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +compress-commons@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-6.0.2.tgz#26d31251a66b9d6ba23a84064ecd3a6a71d2609e" + integrity sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg== + dependencies: + crc-32 "^1.2.0" + crc32-stream "^6.0.0" + is-stream "^2.0.1" + normalize-path "^3.0.0" + readable-stream "^4.0.0" + concat-map@0.0.1: version "0.0.1" - resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== -cosmjs-types@^0.8.0: - version "0.8.0" - resolved "https://registry.npmjs.org/cosmjs-types/-/cosmjs-types-0.8.0.tgz" - integrity sha512-Q2Mj95Fl0PYMWEhA2LuGEIhipF7mQwd9gTQ85DdP9jjjopeoGaDxvmPa5nakNzsq7FnO1DMTatXTAx6bxMH7Lg== - dependencies: - long "^4.0.0" - protobufjs "~6.11.2" +content-disposition@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-1.0.1.tgz#a8b7bbeb2904befdfb6787e5c0c086959f605f9b" + integrity sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q== + +content-type@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" + integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== + +convert-source-map@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" + integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== + +cookie-signature@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.2.2.tgz#57c7fc3cc293acab9fec54d73e15690ebe4a1793" + integrity sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg== + +cookie@^0.7.1: + version "0.7.2" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.7.2.tgz#556369c472a2ba910f2979891b526b3436237ed7" + integrity sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w== + +copyfiles@^2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/copyfiles/-/copyfiles-2.4.1.tgz#d2dcff60aaad1015f09d0b66e7f0f1c5cd3c5da5" + integrity sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg== + dependencies: + glob "^7.0.5" + minimatch "^3.0.3" + mkdirp "^1.0.4" + noms "0.0.0" + through2 "^2.0.1" + untildify "^4.0.0" + yargs "^16.1.0" + +core-util-is@~1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== cosmjs-types@^0.9.0: version "0.9.0" - resolved "https://registry.npmjs.org/cosmjs-types/-/cosmjs-types-0.9.0.tgz" + resolved "https://registry.yarnpkg.com/cosmjs-types/-/cosmjs-types-0.9.0.tgz#c3bc482d28c7dfa25d1445093fdb2d9da1f6cfcc" integrity sha512-MN/yUe6mkJwHnCFfsNPeCfXVhyxHYW6c/xDUzrSbBycYzw++XvWDMJArXp2pLdgD6FQ8DW79vkPjeNKVrXaHeQ== -cross-spawn@^7.0.2, cross-spawn@^7.0.3: - version "7.0.3" - resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz" - integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== +cpu-features@~0.0.10: + version "0.0.10" + resolved "https://registry.yarnpkg.com/cpu-features/-/cpu-features-0.0.10.tgz#9aae536db2710c7254d7ed67cb3cbc7d29ad79c5" + integrity sha512-9IkYqtX3YHPCzoVg1Py+o9057a3i0fp7S530UWokCSaFVTc7CwXPRiOjRjBQQ18ZCNafx78YfnG+HALxtVmOGA== + dependencies: + buildcheck "~0.0.6" + nan "^2.19.0" + +crc-32@^1.2.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.2.tgz#3cad35a934b8bf71f25ca524b6da51fb7eace2ff" + integrity sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ== + +crc32-stream@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/crc32-stream/-/crc32-stream-6.0.0.tgz#8529a3868f8b27abb915f6c3617c0fadedbf9430" + integrity sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g== + dependencies: + crc-32 "^1.2.0" + readable-stream "^4.0.0" + +create-require@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" + integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== + +cross-spawn@^7.0.3, cross-spawn@^7.0.6: + version "7.0.6" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" + integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== dependencies: path-key "^3.1.0" shebang-command "^2.0.0" which "^2.0.1" -dayjs@^1.11.10: - version "1.11.10" - resolved "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz" - integrity sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ== +dayjs@^1.11.13: + version "1.11.19" + resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.19.tgz#15dc98e854bb43917f12021806af897c58ae2938" + integrity sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw== -debug@4.3.4, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4: - version "4.3.4" - resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== +debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.4.0, debug@^4.4.3: + version "4.4.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.3.tgz#c6ae432d9bd9662582fce08709b038c58e9e3d6a" + integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA== dependencies: - ms "2.1.2" + ms "^2.1.3" -decamelize@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz" - integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== +dedent@^1.6.0: + version "1.7.2" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.7.2.tgz#34e2264ab538301e27cf7b07bf2369c19baa8dd9" + integrity sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA== deep-is@^0.1.3: version "0.1.4" - resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== -default-browser-id@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/default-browser-id/-/default-browser-id-3.0.0.tgz" - integrity sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA== - dependencies: - bplist-parser "^0.2.0" - untildify "^4.0.0" +deepmerge@^4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" + integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== -default-browser@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/default-browser/-/default-browser-4.0.0.tgz" - integrity sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA== +define-data-property@^1.0.1: + version "1.1.4" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" + integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== dependencies: - bundle-name "^3.0.0" - default-browser-id "^3.0.0" - execa "^7.1.1" - titleize "^3.0.0" - -define-lazy-prop@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz" - integrity sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg== + es-define-property "^1.0.0" + es-errors "^1.3.0" + gopd "^1.0.1" -define-properties@^1.1.3: - version "1.2.0" - resolved "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz" - integrity sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA== +define-properties@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" + integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== dependencies: + define-data-property "^1.0.1" has-property-descriptors "^1.0.0" object-keys "^1.1.1" +delay@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/delay/-/delay-5.0.0.tgz#137045ef1b96e5071060dd5be60bf9334436bd1d" + integrity sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw== + delayed-stream@~1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== -diff@5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz" - integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== +depd@^2.0.0, depd@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" + integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== -dir-glob@^3.0.1: - version "3.0.1" - resolved "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz" - integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== +detect-newline@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" + integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== + +diff@^4.0.1: + version "4.0.4" + resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.4.tgz#7a6dbfda325f25f07517e9b518f897c08332e07d" + integrity sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ== + +docker-compose@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/docker-compose/-/docker-compose-1.3.1.tgz#92928c4e564fb6eefc311ef1fea75afe9dcbc20b" + integrity sha512-rF0wH69G3CCcmkN9J1RVMQBaKe8o77LT/3XmqcLIltWWVxcWAzp2TnO7wS3n/umZHN3/EVrlT3exSBMal+Ou1w== dependencies: - path-type "^4.0.0" + yaml "^2.2.2" -doctrine@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz" - integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== +docker-modem@^5.0.6: + version "5.0.6" + resolved "https://registry.yarnpkg.com/docker-modem/-/docker-modem-5.0.6.tgz#cbe9d86a1fe66d7a072ac7fb99a9fc390a3e8b9a" + integrity sha512-ens7BiayssQz/uAxGzH8zGXCtiV24rRWXdjNha5V4zSOcxmAZsfGVm/PPFbwQdqEkDnhG+SyR9E3zSHUbOKXBQ== dependencies: - esutils "^2.0.2" + debug "^4.1.1" + readable-stream "^3.5.0" + split-ca "^1.0.1" + ssh2 "^1.15.0" + +dockerode@^4.0.9: + version "4.0.9" + resolved "https://registry.yarnpkg.com/dockerode/-/dockerode-4.0.9.tgz#15b32000edad25520be6fafa9ad6bc4529b06be7" + integrity sha512-iND4mcOWhPaCNh54WmK/KoSb35AFqPAUWFMffTQcp52uQt36b5uNwEJTSXntJZBbeGad72Crbi/hvDIv6us/6Q== + dependencies: + "@balena/dockerignore" "^1.0.2" + "@grpc/grpc-js" "^1.11.1" + "@grpc/proto-loader" "^0.7.13" + docker-modem "^5.0.6" + protobufjs "^7.3.2" + tar-fs "^2.1.4" + uuid "^10.0.0" + +dotenv@^17.2.1: + version "17.3.1" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-17.3.1.tgz#2706f5b0165e45a1503348187b8468f87fe6aae2" + integrity sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA== + +dunder-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a" + integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A== + dependencies: + call-bind-apply-helpers "^1.0.1" + es-errors "^1.3.0" + gopd "^1.2.0" -duplexer@~0.1.1: - version "0.1.2" - resolved "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz" - integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== +eastasianwidth@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" + integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== + +electron-to-chromium@^1.5.263: + version "1.5.307" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.307.tgz#09f8973100c39fb0d003b890393cd1d58932b1c8" + integrity sha512-5z3uFKBWjiNR44nFcYdkcXjKMbg5KXNdciu7mhTPo9tB7NbqSNP2sSnGR+fqknZSCwKkBN+oxiiajWs4dT6ORg== elliptic@^6.5.4: - version "6.5.4" - resolved "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz" - integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== + version "6.6.1" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.6.1.tgz#3b8ffb02670bf69e382c7f65bf524c97c5405c06" + integrity sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g== dependencies: bn.js "^4.11.9" brorand "^1.1.0" @@ -881,149 +2619,264 @@ elliptic@^6.5.4: minimalistic-assert "^1.0.1" minimalistic-crypto-utils "^1.0.1" +emittery@^0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.13.1.tgz#c04b8c3457490e0847ae51fced3af52d338e3dad" + integrity sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ== + +emoji-regex@^10.3.0: + version "10.6.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-10.6.0.tgz#bf3d6e8f7f8fd22a65d9703475bc0147357a6b0d" + integrity sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A== + emoji-regex@^8.0.0: version "8.0.0" - resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== -escalade@^3.1.1: - version "3.1.1" - resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz" - integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== +emoji-regex@^9.2.2: + version "9.2.2" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" + integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== + +enabled@2.0.x: + version "2.0.0" + resolved "https://registry.yarnpkg.com/enabled/-/enabled-2.0.0.tgz#f9dd92ec2d6f4bbc0d5d1e64e21d61cd4665e7c2" + integrity sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ== + +encodeurl@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58" + integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg== + +end-of-stream@^1.1.0, end-of-stream@^1.4.1: + version "1.4.5" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.5.tgz#7344d711dea40e0b74abc2ed49778743ccedb08c" + integrity sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg== + dependencies: + once "^1.4.0" + +environment@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/environment/-/environment-1.1.0.tgz#8e86c66b180f363c7ab311787e0259665f45a9f1" + integrity sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q== + +error-ex@^1.3.1: + version "1.3.4" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.4.tgz#b3a8d8bb6f92eecc1629e3e27d3c8607a8a32414" + integrity sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ== + dependencies: + is-arrayish "^0.2.1" + +es-define-property@^1.0.0, es-define-property@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa" + integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g== + +es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + +es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz#1c4f2c4837327597ce69d2ca190a7fdd172338c1" + integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA== + dependencies: + es-errors "^1.3.0" + +es-set-tostringtag@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz#f31dbbe0c183b00a6d26eb6325c810c0fd18bd4d" + integrity sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA== + dependencies: + es-errors "^1.3.0" + get-intrinsic "^1.2.6" + has-tostringtag "^1.0.2" + hasown "^2.0.2" + +es6-promise@^4.0.3: + version "4.2.8" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" + integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== + +es6-promisify@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" + integrity sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ== + dependencies: + es6-promise "^4.0.3" + +escalade@^3.1.1, escalade@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== + +escape-html@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== -escape-string-regexp@4.0.0, escape-string-regexp@^4.0.0: +escape-string-regexp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + +escape-string-regexp@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== -eslint-config-prettier@^9.0.0: - version "9.0.0" - resolved "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.0.0.tgz" - integrity sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw== +eslint-config-prettier@^10.1.5: + version "10.1.8" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz#15734ce4af8c2778cc32f0b01b37b0b5cd1ecb97" + integrity sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w== -eslint-plugin-prettier@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.0.0.tgz" - integrity sha512-AgaZCVuYDXHUGxj/ZGu1u8H8CYgDY3iG6w5kUFw4AzMVXzB7VvbKgYR4nATIN+OvUrghMbiDLeimVjVY5ilq3w== +eslint-plugin-prettier@^5.5.4: + version "5.5.5" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.5.tgz#9eae11593faa108859c26f9a9c367d619a0769c0" + integrity sha512-hscXkbqUZ2sPithAuLm5MXL+Wph+U7wHngPBv9OMWwlP8iaflyxpjTYZkmdgB4/vPIhemRlBEoLrH7UC1n7aUw== dependencies: - prettier-linter-helpers "^1.0.0" - synckit "^0.8.5" + prettier-linter-helpers "^1.0.1" + synckit "^0.11.12" -eslint-scope@^7.2.2: - version "7.2.2" - resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz" - integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== +eslint-scope@^9.1.2: + version "9.1.2" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-9.1.2.tgz#b9de6ace2fab1cff24d2e58d85b74c8fcea39802" + integrity sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ== dependencies: + "@types/esrecurse" "^4.3.1" + "@types/estree" "^1.0.8" esrecurse "^4.3.0" estraverse "^5.2.0" -eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: +eslint-visitor-keys@^3.4.3: version "3.4.3" - resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== -eslint@^8.49.0: - version "8.49.0" - resolved "https://registry.npmjs.org/eslint/-/eslint-8.49.0.tgz" - integrity sha512-jw03ENfm6VJI0jA9U+8H5zfl5b+FvuU3YYvZRdZHOlU2ggJkxrlkJH4HcDrZpj6YwD8kuYqvQM8LyesoazrSOQ== - dependencies: - "@eslint-community/eslint-utils" "^4.2.0" - "@eslint-community/regexpp" "^4.6.1" - "@eslint/eslintrc" "^2.1.2" - "@eslint/js" "8.49.0" - "@humanwhocodes/config-array" "^0.11.11" +eslint-visitor-keys@^5.0.0, eslint-visitor-keys@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz#9e3c9489697824d2d4ce3a8ad12628f91e9f59be" + integrity sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA== + +eslint@^10.0.0: + version "10.0.3" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-10.0.3.tgz#360a7de7f2706eb8a32caa17ca983f0089efe694" + integrity sha512-COV33RzXZkqhG9P2rZCFl9ZmJ7WL+gQSCRzE7RhkbclbQPtLAWReL7ysA0Sh4c8Im2U9ynybdR56PV0XcKvqaQ== + dependencies: + "@eslint-community/eslint-utils" "^4.8.0" + "@eslint-community/regexpp" "^4.12.2" + "@eslint/config-array" "^0.23.3" + "@eslint/config-helpers" "^0.5.2" + "@eslint/core" "^1.1.1" + "@eslint/plugin-kit" "^0.6.1" + "@humanfs/node" "^0.16.6" "@humanwhocodes/module-importer" "^1.0.1" - "@nodelib/fs.walk" "^1.2.8" - ajv "^6.12.4" - chalk "^4.0.0" - cross-spawn "^7.0.2" + "@humanwhocodes/retry" "^0.4.2" + "@types/estree" "^1.0.6" + ajv "^6.14.0" + cross-spawn "^7.0.6" debug "^4.3.2" - doctrine "^3.0.0" escape-string-regexp "^4.0.0" - eslint-scope "^7.2.2" - eslint-visitor-keys "^3.4.3" - espree "^9.6.1" - esquery "^1.4.2" + eslint-scope "^9.1.2" + eslint-visitor-keys "^5.0.1" + espree "^11.1.1" + esquery "^1.7.0" esutils "^2.0.2" fast-deep-equal "^3.1.3" - file-entry-cache "^6.0.1" + file-entry-cache "^8.0.0" find-up "^5.0.0" glob-parent "^6.0.2" - globals "^13.19.0" - graphemer "^1.4.0" ignore "^5.2.0" imurmurhash "^0.1.4" is-glob "^4.0.0" - is-path-inside "^3.0.3" - js-yaml "^4.1.0" json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.4.1" - lodash.merge "^4.6.2" - minimatch "^3.1.2" + minimatch "^10.2.4" natural-compare "^1.4.0" optionator "^0.9.3" - strip-ansi "^6.0.1" - text-table "^0.2.0" -espree@^9.6.0, espree@^9.6.1: - version "9.6.1" - resolved "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz" - integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== +espree@^11.1.1: + version "11.2.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-11.2.0.tgz#01d5e47dc332aaba3059008362454a8cc34ccaa5" + integrity sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw== dependencies: - acorn "^8.9.0" + acorn "^8.16.0" acorn-jsx "^5.3.2" - eslint-visitor-keys "^3.4.1" + eslint-visitor-keys "^5.0.1" -esquery@^1.4.2: - version "1.5.0" - resolved "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz" - integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esquery@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.7.0.tgz#08d048f261f0ddedb5bae95f46809463d9c9496d" + integrity sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g== dependencies: estraverse "^5.1.0" esrecurse@^4.3.0: version "4.3.0" - resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== dependencies: estraverse "^5.2.0" estraverse@^5.1.0, estraverse@^5.2.0: version "5.3.0" - resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== esutils@^2.0.2: version "2.0.3" - resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== -event-stream@=3.3.4: - version "3.3.4" - resolved "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz" - integrity sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g== +etag@^1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== + +ethers@^6.15.0: + version "6.16.0" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.16.0.tgz#fff9b4f05d7a359c774ad6e91085a800f7fccf65" + integrity sha512-U1wulmetNymijEhpSEQ7Ct/P/Jw9/e7R1j5XIbPRydgV2DjLVMsULDlNksq3RQnFgKoLlZf88ijYtWEXcPa07A== dependencies: - duplexer "~0.1.1" - from "~0" - map-stream "~0.1.0" - pause-stream "0.0.11" - split "0.3" - stream-combiner "~0.0.4" - through "~2.3.1" + "@adraffy/ens-normalize" "1.10.1" + "@noble/curves" "1.2.0" + "@noble/hashes" "1.3.2" + "@types/node" "22.7.5" + aes-js "4.0.0-beta.5" + tslib "2.7.0" + ws "8.17.1" event-target-shim@^5.0.0: version "5.0.1" - resolved "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz" + resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== +eventemitter3@^5.0.1: + version "5.0.4" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-5.0.4.tgz#a86d66170433712dde814707ac52b5271ceb1feb" + integrity sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw== + +events-universal@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/events-universal/-/events-universal-1.0.1.tgz#b56a84fd611b6610e0a2d0f09f80fdf931e2dfe6" + integrity sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw== + dependencies: + bare-events "^2.7.0" + events@^3.3.0: version "3.3.0" - resolved "https://registry.npmjs.org/events/-/events-3.3.0.tgz" + resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== -execa@^5.0.0: +execa@^5.1.1: version "5.1.1" - resolved "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== dependencies: cross-spawn "^7.0.3" @@ -1036,188 +2889,309 @@ execa@^5.0.0: signal-exit "^3.0.3" strip-final-newline "^2.0.0" -execa@^7.1.1: - version "7.2.0" - resolved "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz" - integrity sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA== +exit-x@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/exit-x/-/exit-x-0.2.2.tgz#1f9052de3b8d99a696b10dad5bced9bdd5c3aa64" + integrity sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ== + +expect@30.2.0, expect@^30.0.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/expect/-/expect-30.2.0.tgz#d4013bed267013c14bc1199cec8aa57cee9b5869" + integrity sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw== dependencies: - cross-spawn "^7.0.3" - get-stream "^6.0.1" - human-signals "^4.3.0" - is-stream "^3.0.0" - merge-stream "^2.0.0" - npm-run-path "^5.1.0" - onetime "^6.0.0" - signal-exit "^3.0.7" - strip-final-newline "^3.0.0" + "@jest/expect-utils" "30.2.0" + "@jest/get-type" "30.1.0" + jest-matcher-utils "30.2.0" + jest-message-util "30.2.0" + jest-mock "30.2.0" + jest-util "30.2.0" + +express@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/express/-/express-5.2.1.tgz#8f21d15b6d327f92b4794ecf8cb08a72f956ac04" + integrity sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw== + dependencies: + accepts "^2.0.0" + body-parser "^2.2.1" + content-disposition "^1.0.0" + content-type "^1.0.5" + cookie "^0.7.1" + cookie-signature "^1.2.1" + debug "^4.4.0" + depd "^2.0.0" + encodeurl "^2.0.0" + escape-html "^1.0.3" + etag "^1.8.1" + finalhandler "^2.1.0" + fresh "^2.0.0" + http-errors "^2.0.0" + merge-descriptors "^2.0.0" + mime-types "^3.0.0" + on-finished "^2.4.1" + once "^1.4.0" + parseurl "^1.3.3" + proxy-addr "^2.0.7" + qs "^6.14.0" + range-parser "^1.2.1" + router "^2.2.0" + send "^1.1.0" + serve-static "^2.2.0" + statuses "^2.0.1" + type-is "^2.0.1" + vary "^1.1.2" + +eyes@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/eyes/-/eyes-0.1.8.tgz#62cf120234c683785d902348a800ef3e0cc20bc0" + integrity sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ== fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" - resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== fast-diff@^1.1.2: version "1.3.0" - resolved "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz" + resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.3.0.tgz#ece407fa550a64d638536cd727e129c61616e0f0" integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw== -fast-glob@^3.2.9, fast-glob@^3.3.0: - version "3.3.1" - resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz" - integrity sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg== - dependencies: - "@nodelib/fs.stat" "^2.0.2" - "@nodelib/fs.walk" "^1.2.3" - glob-parent "^5.1.2" - merge2 "^1.3.0" - micromatch "^4.0.4" +fast-fifo@^1.2.0, fast-fifo@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/fast-fifo/-/fast-fifo-1.3.2.tgz#286e31de96eb96d38a97899815740ba2a4f3640c" + integrity sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ== -fast-json-stable-stringify@^2.0.0: +fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== fast-levenshtein@^2.0.6: version "2.0.6" - resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== -fast-redact@^3.1.1: - version "3.3.0" - resolved "https://registry.npmjs.org/fast-redact/-/fast-redact-3.3.0.tgz" - integrity sha512-6T5V1QK1u4oF+ATxs1lWUmlEk6P2T9HqJG3e2DnHOdVgZy2rFJBoEnrIedcTXlkAHU/zKC+7KETJ+KGGKwxgMQ== +fast-stable-stringify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fast-stable-stringify/-/fast-stable-stringify-1.0.0.tgz#5c5543462b22aeeefd36d05b34e51c78cb86d313" + integrity sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag== -fastq@^1.6.0: - version "1.15.0" - resolved "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz" - integrity sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw== +fb-watchman@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.2.tgz#e9524ee6b5c77e9e5001af0f85f3adbb8623255c" + integrity sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA== dependencies: - reusify "^1.0.4" + bser "2.1.1" -file-entry-cache@^6.0.1: - version "6.0.1" - resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz" - integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== +fdir@^6.5.0: + version "6.5.0" + resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.5.0.tgz#ed2ab967a331ade62f18d077dae192684d50d350" + integrity sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg== + +fecha@^4.2.0: + version "4.2.3" + resolved "https://registry.yarnpkg.com/fecha/-/fecha-4.2.3.tgz#4d9ccdbc61e8629b259fdca67e65891448d569fd" + integrity sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw== + +file-entry-cache@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-8.0.0.tgz#7787bddcf1131bffb92636c69457bbc0edd6d81f" + integrity sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ== dependencies: - flat-cache "^3.0.4" + flat-cache "^4.0.0" fill-range@^7.1.1: version "7.1.1" - resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== dependencies: to-regex-range "^5.0.1" -find-up@5.0.0, find-up@^5.0.0: +finalhandler@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-2.1.1.tgz#a2c517a6559852bcdb06d1f8bd7f51b68fad8099" + integrity sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA== + dependencies: + debug "^4.4.0" + encodeurl "^2.0.0" + escape-html "^1.0.3" + on-finished "^2.4.1" + parseurl "^1.3.3" + statuses "^2.0.1" + +find-up@^4.0.0, find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +find-up@^5.0.0: version "5.0.0" - resolved "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== dependencies: locate-path "^6.0.0" path-exists "^4.0.0" -flat-cache@^3.0.4: - version "3.1.0" - resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.0.tgz" - integrity sha512-OHx4Qwrrt0E4jEIcI5/Xb+f+QmJYNj2rrK8wiIdQOIrB9WrrJL8cjZvXdXuBTkkEwEqLycb5BeZDV1o2i9bTew== +flat-cache@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-4.0.1.tgz#0ece39fcb14ee012f4b0410bd33dd9c1f011127c" + integrity sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw== dependencies: - flatted "^3.2.7" - keyv "^4.5.3" - rimraf "^3.0.2" + flatted "^3.2.9" + keyv "^4.5.4" -flat@^5.0.2: - version "5.0.2" - resolved "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz" - integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== +flatbuffers@^25.2.10: + version "25.9.23" + resolved "https://registry.yarnpkg.com/flatbuffers/-/flatbuffers-25.9.23.tgz#346811557fe9312ab5647535e793c761e9c81eb1" + integrity sha512-MI1qs7Lo4Syw0EOzUl0xjs2lsoeqFku44KpngfIduHBYvzm8h2+7K8YMQh1JtVVVrUvhLpNwqVi4DERegUJhPQ== + +flatted@^3.2.9: + version "3.3.4" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.4.tgz#0986e681008f0f13f58e18656c47967682db5ff6" + integrity sha512-3+mMldrTAPdta5kjX2G2J7iX4zxtnwpdA8Tr2ZSjkyPSanvbZAcy6flmtnXbEybHrDcU9641lxrMfFuUxVz9vA== -flatted@^3.2.7: - version "3.2.9" - resolved "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz" - integrity sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ== +fn.name@1.x.x: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fn.name/-/fn.name-1.1.0.tgz#26cad8017967aea8731bc42961d04a3d5988accc" + integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw== -follow-redirects@^1.14.0, follow-redirects@^1.15.0, follow-redirects@^1.15.4: - version "1.15.6" - resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz" - integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== +follow-redirects@^1.15.11, follow-redirects@^1.15.6: + version "1.15.11" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.11.tgz#777d73d72a92f8ec4d2e410eb47352a56b8e8340" + integrity sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ== -form-data@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz" - integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== +foreground-child@^3.1.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.1.tgz#32e8e9ed1b68a3497befb9ac2b6adf92a638576f" + integrity sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw== + dependencies: + cross-spawn "^7.0.6" + signal-exit "^4.0.1" + +form-data@^4.0.0, form-data@^4.0.5: + version "4.0.5" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.5.tgz#b49e48858045ff4cbf6b03e1805cebcad3679053" + integrity sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w== dependencies: asynckit "^0.4.0" combined-stream "^1.0.8" + es-set-tostringtag "^2.1.0" + hasown "^2.0.2" mime-types "^2.1.12" -from@~0: - version "0.1.7" - resolved "https://registry.npmjs.org/from/-/from-0.1.7.tgz" - integrity sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g== +forwarded@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" + integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== + +fresh@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-2.0.0.tgz#8dd7df6a1b3a1b3a5cf186c05a5dd267622635a4" + integrity sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A== + +fs-constants@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" + integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== fs.realpath@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== -fsevents@~2.3.2: - version "2.3.2" - resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz" - integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== +fsevents@^2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== -function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +generic-pool@3.9.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/generic-pool/-/generic-pool-3.9.0.tgz#36f4a678e963f4fdb8707eab050823abc4e8f5e4" + integrity sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g== + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== get-caller-file@^2.0.5: version "2.0.5" - resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== -get-intrinsic@^1.1.1: - version "1.2.1" - resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz" - integrity sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw== +get-east-asian-width@^1.0.0, get-east-asian-width@^1.3.1, get-east-asian-width@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/get-east-asian-width/-/get-east-asian-width-1.5.0.tgz#ce7008fe345edcf5497a6f557cfa54bc318a9ce7" + integrity sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA== + +get-intrinsic@^1.2.5, get-intrinsic@^1.2.6, get-intrinsic@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01" + integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ== + dependencies: + call-bind-apply-helpers "^1.0.2" + es-define-property "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.1.1" + function-bind "^1.1.2" + get-proto "^1.0.1" + gopd "^1.2.0" + has-symbols "^1.1.0" + hasown "^2.0.2" + math-intrinsics "^1.1.0" + +get-package-type@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" + integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== + +get-port@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/get-port/-/get-port-7.1.0.tgz#d5a500ebfc7aa705294ec2b83cc38c5d0e364fec" + integrity sha512-QB9NKEeDg3xxVwCCwJQ9+xycaz6pBB6iQ76wiWMl1927n0Kir6alPiP+yuiICLLU4jpMe08dXfpebuQppFA2zw== + +get-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1" + integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g== dependencies: - function-bind "^1.1.1" - has "^1.0.3" - has-proto "^1.0.1" - has-symbols "^1.0.3" + dunder-proto "^1.0.1" + es-object-atoms "^1.0.0" -get-stream@^6.0.0, get-stream@^6.0.1: +get-stream@^6.0.0: version "6.0.1" - resolved "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== -glob-parent@^5.1.2, glob-parent@~5.1.2: - version "5.1.2" - resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" - integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== - dependencies: - is-glob "^4.0.1" - glob-parent@^6.0.2: version "6.0.2" - resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== dependencies: is-glob "^4.0.3" -glob@7.2.0: - version "7.2.0" - resolved "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz" - integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== +glob@^10.0.0, glob@^10.3.10: + version "10.5.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.5.0.tgz#8ec0355919cd3338c28428a23d4f24ecc5fe738c" + integrity sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg== dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" + foreground-child "^3.1.0" + jackspeak "^3.1.2" + minimatch "^9.0.4" + minipass "^7.1.2" + package-json-from-dist "^1.0.0" + path-scurry "^1.11.1" -glob@^7.1.3: +glob@^7.0.5, glob@^7.1.4: version "7.2.3" - resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== dependencies: fs.realpath "^1.0.0" @@ -1227,510 +3201,1146 @@ glob@^7.1.3: once "^1.3.0" path-is-absolute "^1.0.0" -globals@^13.19.0: - version "13.21.0" - resolved "https://registry.npmjs.org/globals/-/globals-13.21.0.tgz" - integrity sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg== - dependencies: - type-fest "^0.20.2" +globals@^17.0.0: + version "17.4.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-17.4.0.tgz#33d7d297ed1536b388a0e2f4bcd0ff19c8ff91b5" + integrity sha512-hjrNztw/VajQwOLsMNT1cbJiH2muO3OROCHnbehc8eY5JyD2gqz4AcMHPqgaOR59DjgUjYAYLeH699g/eWi2jw== globalthis@^1.0.1: - version "1.0.3" - resolved "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz" - integrity sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA== - dependencies: - define-properties "^1.1.3" - -globby@^11.1.0: - version "11.1.0" - resolved "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz" - integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== + version "1.0.4" + resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.4.tgz#7430ed3a975d97bfb59bcce41f5cabbafa651236" + integrity sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ== dependencies: - array-union "^2.1.0" - dir-glob "^3.0.1" - fast-glob "^3.2.9" - ignore "^5.2.0" - merge2 "^1.4.1" - slash "^3.0.0" + define-properties "^1.2.1" + gopd "^1.0.1" -graphemer@^1.4.0: - version "1.4.0" - resolved "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz" - integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== +gopd@^1.0.1, gopd@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1" + integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== + +graceful-fs@^4.2.0, graceful-fs@^4.2.11, graceful-fs@^4.2.4: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +handlebars@^4.7.8: + version "4.7.8" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.8.tgz#41c42c18b1be2365439188c77c6afae71c0cd9e9" + integrity sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ== + dependencies: + minimist "^1.2.5" + neo-async "^2.6.2" + source-map "^0.6.1" + wordwrap "^1.0.0" + optionalDependencies: + uglify-js "^3.1.4" has-flag@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== has-property-descriptors@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz" - integrity sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ== + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" + integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== dependencies: - get-intrinsic "^1.1.1" - -has-proto@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz" - integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== + es-define-property "^1.0.0" -has-symbols@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz" - integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== +has-symbols@^1.0.3, has-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338" + integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== -has@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/has/-/has-1.0.3.tgz" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== +has-tostringtag@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" + integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== dependencies: - function-bind "^1.1.1" + has-symbols "^1.0.3" hash.js@^1.0.0, hash.js@^1.0.3: version "1.1.7" - resolved "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== dependencies: inherits "^2.0.3" minimalistic-assert "^1.0.1" -he@1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/he/-/he-1.2.0.tgz" - integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== +hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" hmac-drbg@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" integrity sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg== dependencies: hash.js "^1.0.3" minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" +html-escaper@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== + +http-errors@^2.0.0, http-errors@^2.0.1, http-errors@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.1.tgz#36d2f65bc909c8790018dd36fb4d93da6caae06b" + integrity sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ== + dependencies: + depd "~2.0.0" + inherits "~2.0.4" + setprototypeof "~1.2.0" + statuses "~2.0.2" + toidentifier "~1.0.1" + human-signals@^2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== -human-signals@^4.3.0: - version "4.3.1" - resolved "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz" - integrity sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ== +humanize-ms@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" + integrity sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ== + dependencies: + ms "^2.0.0" + +husky@^9.1.7: + version "9.1.7" + resolved "https://registry.yarnpkg.com/husky/-/husky-9.1.7.tgz#d46a38035d101b46a70456a850ff4201344c0b2d" + integrity sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA== -ieee754@^1.2.1: +iconv-lite@^0.7.0, iconv-lite@~0.7.0: + version "0.7.2" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.7.2.tgz#d0bdeac3f12b4835b7359c2ad89c422a4d1cc72e" + integrity sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + +ieee754@^1.1.13, ieee754@^1.2.1: version "1.2.1" - resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== -ignore@^5.2.0, ignore@^5.2.4: - version "5.2.4" - resolved "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz" - integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== +ignore@^5.2.0: + version "5.3.2" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" + integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== -import-fresh@^3.2.1: - version "3.3.0" - resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz" - integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== +ignore@^7.0.5: + version "7.0.5" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-7.0.5.tgz#4cb5f6cd7d4c7ab0365738c7aea888baa6d7efd9" + integrity sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg== + +import-local@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.2.0.tgz#c3d5c745798c02a6f8b897726aba5100186ee260" + integrity sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA== dependencies: - parent-module "^1.0.0" - resolve-from "^4.0.0" + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" imurmurhash@^0.1.4: version "0.1.4" - resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== inflight@^1.0.4: version "1.0.6" - resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== dependencies: once "^1.3.0" wrappy "1" -inherits@2, inherits@^2.0.3, inherits@^2.0.4: +inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3, inherits@~2.0.4: version "2.0.4" - resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== -is-binary-path@~2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz" - integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== - dependencies: - binary-extensions "^2.0.0" - -is-docker@^2.0.0: - version "2.2.1" - resolved "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz" - integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== +ipaddr.js@1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== -is-docker@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz" - integrity sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ== +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== is-extglob@^2.1.1: version "2.1.1" - resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== is-fullwidth-code-point@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== -is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: +is-fullwidth-code-point@^5.0.0, is-fullwidth-code-point@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz#046b2a6d4f6b156b2233d3207d4b5a9783999b98" + integrity sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ== + dependencies: + get-east-asian-width "^1.3.1" + +is-generator-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" + integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== + +is-glob@^4.0.0, is-glob@^4.0.3: version "4.0.3" - resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== dependencies: is-extglob "^2.1.1" -is-inside-container@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz" - integrity sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA== - dependencies: - is-docker "^3.0.0" - is-number@^7.0.0: version "7.0.0" - resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== -is-path-inside@^3.0.3: - version "3.0.3" - resolved "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz" - integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== - -is-plain-obj@^2.1.0: - 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== +is-promise@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-4.0.0.tgz#42ff9f84206c1991d26debf520dd5c01042dd2f3" + integrity sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ== -is-stream@^2.0.0: +is-stream@^2.0.0, is-stream@^2.0.1: version "2.0.1" - resolved "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== -is-stream@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz" - integrity sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA== - -is-unicode-supported@^0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz" - integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + integrity sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ== -is-wsl@^2.2.0: - version "2.2.0" - resolved "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz" - integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== - dependencies: - is-docker "^2.0.0" +isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== isexe@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== isomorphic-ws@^4.0.1: version "4.0.1" - resolved "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz" + resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz#55fd4cd6c5e6491e76dc125938dd863f5cd4f2dc" integrity sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w== -js-yaml@4.1.0, js-yaml@^4.1.0: - version "4.1.0" - resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz" - integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz#2d166c4b0644d43a39f04bf6c2edd1e585f31756" + integrity sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg== + +istanbul-lib-instrument@^6.0.0, istanbul-lib-instrument@^6.0.2: + version "6.0.3" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz#fa15401df6c15874bcb2105f773325d78c666765" + integrity sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q== + dependencies: + "@babel/core" "^7.23.9" + "@babel/parser" "^7.23.9" + "@istanbuljs/schema" "^0.1.3" + istanbul-lib-coverage "^3.2.0" + semver "^7.5.4" + +istanbul-lib-report@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz#908305bac9a5bd175ac6a74489eafd0fc2445a7d" + integrity sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw== + dependencies: + istanbul-lib-coverage "^3.0.0" + make-dir "^4.0.0" + supports-color "^7.1.0" + +istanbul-lib-source-maps@^5.0.0: + version "5.0.6" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz#acaef948df7747c8eb5fbf1265cb980f6353a441" + integrity sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A== + dependencies: + "@jridgewell/trace-mapping" "^0.3.23" + debug "^4.1.1" + istanbul-lib-coverage "^3.0.0" + +istanbul-reports@^3.1.3: + version "3.2.0" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.2.0.tgz#cb4535162b5784aa623cee21a7252cf2c807ac93" + integrity sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + +jackspeak@^3.1.2: + version "3.4.3" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a" + integrity sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw== + dependencies: + "@isaacs/cliui" "^8.0.2" + optionalDependencies: + "@pkgjs/parseargs" "^0.11.0" + +jayson@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/jayson/-/jayson-4.3.0.tgz#22eb8f3dcf37a5e893830e5451f32bde6d1bde4d" + integrity sha512-AauzHcUcqs8OBnCHOkJY280VaTiCm57AbuO7lqzcw7JapGj50BisE3xhksye4zlTSR1+1tAz67wLTl8tEH1obQ== + dependencies: + "@types/connect" "^3.4.33" + "@types/node" "^12.12.54" + "@types/ws" "^7.4.4" + commander "^2.20.3" + delay "^5.0.0" + es6-promisify "^5.0.0" + eyes "^0.1.8" + isomorphic-ws "^4.0.1" + json-stringify-safe "^5.0.1" + stream-json "^1.9.1" + uuid "^8.3.2" + ws "^7.5.10" + +jest-changed-files@30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-30.2.0.tgz#602266e478ed554e1e1469944faa7efd37cee61c" + integrity sha512-L8lR1ChrRnSdfeOvTrwZMlnWV8G/LLjQ0nG9MBclwWZidA2N5FviRki0Bvh20WRMOX31/JYvzdqTJrk5oBdydQ== + dependencies: + execa "^5.1.1" + jest-util "30.2.0" + p-limit "^3.1.0" + +jest-circus@30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-30.2.0.tgz#98b8198b958748a2f322354311023d1d02e7603f" + integrity sha512-Fh0096NC3ZkFx05EP2OXCxJAREVxj1BcW/i6EWqqymcgYKWjyyDpral3fMxVcHXg6oZM7iULer9wGRFvfpl+Tg== + dependencies: + "@jest/environment" "30.2.0" + "@jest/expect" "30.2.0" + "@jest/test-result" "30.2.0" + "@jest/types" "30.2.0" + "@types/node" "*" + chalk "^4.1.2" + co "^4.6.0" + dedent "^1.6.0" + is-generator-fn "^2.1.0" + jest-each "30.2.0" + jest-matcher-utils "30.2.0" + jest-message-util "30.2.0" + jest-runtime "30.2.0" + jest-snapshot "30.2.0" + jest-util "30.2.0" + p-limit "^3.1.0" + pretty-format "30.2.0" + pure-rand "^7.0.0" + slash "^3.0.0" + stack-utils "^2.0.6" + +jest-cli@30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-30.2.0.tgz#1780f8e9d66bf84a10b369aea60aeda7697dcc67" + integrity sha512-Os9ukIvADX/A9sLt6Zse3+nmHtHaE6hqOsjQtNiugFTbKRHYIYtZXNGNK9NChseXy7djFPjndX1tL0sCTlfpAA== + dependencies: + "@jest/core" "30.2.0" + "@jest/test-result" "30.2.0" + "@jest/types" "30.2.0" + chalk "^4.1.2" + exit-x "^0.2.2" + import-local "^3.2.0" + jest-config "30.2.0" + jest-util "30.2.0" + jest-validate "30.2.0" + yargs "^17.7.2" + +jest-config@30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-30.2.0.tgz#29df8c50e2ad801cc59c406b50176c18c362a90b" + integrity sha512-g4WkyzFQVWHtu6uqGmQR4CQxz/CH3yDSlhzXMWzNjDx843gYjReZnMRanjRCq5XZFuQrGDxgUaiYWE8BRfVckA== + dependencies: + "@babel/core" "^7.27.4" + "@jest/get-type" "30.1.0" + "@jest/pattern" "30.0.1" + "@jest/test-sequencer" "30.2.0" + "@jest/types" "30.2.0" + babel-jest "30.2.0" + chalk "^4.1.2" + ci-info "^4.2.0" + deepmerge "^4.3.1" + glob "^10.3.10" + graceful-fs "^4.2.11" + jest-circus "30.2.0" + jest-docblock "30.2.0" + jest-environment-node "30.2.0" + jest-regex-util "30.0.1" + jest-resolve "30.2.0" + jest-runner "30.2.0" + jest-util "30.2.0" + jest-validate "30.2.0" + micromatch "^4.0.8" + parse-json "^5.2.0" + pretty-format "30.2.0" + slash "^3.0.0" + strip-json-comments "^3.1.1" + +jest-diff@30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-30.2.0.tgz#e3ec3a6ea5c5747f605c9e874f83d756cba36825" + integrity sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A== + dependencies: + "@jest/diff-sequences" "30.0.1" + "@jest/get-type" "30.1.0" + chalk "^4.1.2" + pretty-format "30.2.0" + +jest-docblock@30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-30.2.0.tgz#42cd98d69f887e531c7352309542b1ce4ee10256" + integrity sha512-tR/FFgZKS1CXluOQzZvNH3+0z9jXr3ldGSD8bhyuxvlVUwbeLOGynkunvlTMxchC5urrKndYiwCFC0DLVjpOCA== + dependencies: + detect-newline "^3.1.0" + +jest-each@30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-30.2.0.tgz#39e623ae71641c2ac3ee69b3ba3d258fce8e768d" + integrity sha512-lpWlJlM7bCUf1mfmuqTA8+j2lNURW9eNafOy99knBM01i5CQeY5UH1vZjgT9071nDJac1M4XsbyI44oNOdhlDQ== + dependencies: + "@jest/get-type" "30.1.0" + "@jest/types" "30.2.0" + chalk "^4.1.2" + jest-util "30.2.0" + pretty-format "30.2.0" + +jest-environment-node@30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-30.2.0.tgz#3def7980ebd2fd86e74efd4d2e681f55ab38da0f" + integrity sha512-ElU8v92QJ9UrYsKrxDIKCxu6PfNj4Hdcktcn0JX12zqNdqWHB0N+hwOnnBBXvjLd2vApZtuLUGs1QSY+MsXoNA== + dependencies: + "@jest/environment" "30.2.0" + "@jest/fake-timers" "30.2.0" + "@jest/types" "30.2.0" + "@types/node" "*" + jest-mock "30.2.0" + jest-util "30.2.0" + jest-validate "30.2.0" + +jest-haste-map@30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-30.2.0.tgz#808e3889f288603ac70ff0ac047598345a66022e" + integrity sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw== + dependencies: + "@jest/types" "30.2.0" + "@types/node" "*" + anymatch "^3.1.3" + fb-watchman "^2.0.2" + graceful-fs "^4.2.11" + jest-regex-util "30.0.1" + jest-util "30.2.0" + jest-worker "30.2.0" + micromatch "^4.0.8" + walker "^1.0.8" + optionalDependencies: + fsevents "^2.3.3" + +jest-leak-detector@30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-30.2.0.tgz#292fdca7b7c9cf594e1e570ace140b01d8beb736" + integrity sha512-M6jKAjyzjHG0SrQgwhgZGy9hFazcudwCNovY/9HPIicmNSBuockPSedAP9vlPK6ONFJ1zfyH/M2/YYJxOz5cdQ== + dependencies: + "@jest/get-type" "30.1.0" + pretty-format "30.2.0" + +jest-matcher-utils@30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-30.2.0.tgz#69a0d4c271066559ec8b0d8174829adc3f23a783" + integrity sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg== + dependencies: + "@jest/get-type" "30.1.0" + chalk "^4.1.2" + jest-diff "30.2.0" + pretty-format "30.2.0" + +jest-message-util@30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-30.2.0.tgz#fc97bf90d11f118b31e6131e2b67fc4f39f92152" + integrity sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw== + dependencies: + "@babel/code-frame" "^7.27.1" + "@jest/types" "30.2.0" + "@types/stack-utils" "^2.0.3" + chalk "^4.1.2" + graceful-fs "^4.2.11" + micromatch "^4.0.8" + pretty-format "30.2.0" + slash "^3.0.0" + stack-utils "^2.0.6" + +jest-mock@30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-30.2.0.tgz#69f991614eeb4060189459d3584f710845bff45e" + integrity sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw== + dependencies: + "@jest/types" "30.2.0" + "@types/node" "*" + jest-util "30.2.0" + +jest-pnp-resolver@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz#930b1546164d4ad5937d5540e711d4d38d4cad2e" + integrity sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w== + +jest-regex-util@30.0.1: + version "30.0.1" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-30.0.1.tgz#f17c1de3958b67dfe485354f5a10093298f2a49b" + integrity sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA== + +jest-resolve-dependencies@30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-30.2.0.tgz#3370e2c0b49cc560f6a7e8ec3a59dd99525e1a55" + integrity sha512-xTOIGug/0RmIe3mmCqCT95yO0vj6JURrn1TKWlNbhiAefJRWINNPgwVkrVgt/YaerPzY3iItufd80v3lOrFJ2w== + dependencies: + jest-regex-util "30.0.1" + jest-snapshot "30.2.0" + +jest-resolve@30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-30.2.0.tgz#2e2009cbd61e8f1f003355d5ec87225412cebcd7" + integrity sha512-TCrHSxPlx3tBY3hWNtRQKbtgLhsXa1WmbJEqBlTBrGafd5fiQFByy2GNCEoGR+Tns8d15GaL9cxEzKOO3GEb2A== + dependencies: + chalk "^4.1.2" + graceful-fs "^4.2.11" + jest-haste-map "30.2.0" + jest-pnp-resolver "^1.2.3" + jest-util "30.2.0" + jest-validate "30.2.0" + slash "^3.0.0" + unrs-resolver "^1.7.11" + +jest-runner@30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-30.2.0.tgz#c62b4c3130afa661789705e13a07bdbcec26a114" + integrity sha512-PqvZ2B2XEyPEbclp+gV6KO/F1FIFSbIwewRgmROCMBo/aZ6J1w8Qypoj2pEOcg3G2HzLlaP6VUtvwCI8dM3oqQ== + dependencies: + "@jest/console" "30.2.0" + "@jest/environment" "30.2.0" + "@jest/test-result" "30.2.0" + "@jest/transform" "30.2.0" + "@jest/types" "30.2.0" + "@types/node" "*" + chalk "^4.1.2" + emittery "^0.13.1" + exit-x "^0.2.2" + graceful-fs "^4.2.11" + jest-docblock "30.2.0" + jest-environment-node "30.2.0" + jest-haste-map "30.2.0" + jest-leak-detector "30.2.0" + jest-message-util "30.2.0" + jest-resolve "30.2.0" + jest-runtime "30.2.0" + jest-util "30.2.0" + jest-watcher "30.2.0" + jest-worker "30.2.0" + p-limit "^3.1.0" + source-map-support "0.5.13" + +jest-runtime@30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-30.2.0.tgz#395ea792cde048db1b0cd1a92dc9cb9f1921bf8a" + integrity sha512-p1+GVX/PJqTucvsmERPMgCPvQJpFt4hFbM+VN3n8TMo47decMUcJbt+rgzwrEme0MQUA/R+1de2axftTHkKckg== + dependencies: + "@jest/environment" "30.2.0" + "@jest/fake-timers" "30.2.0" + "@jest/globals" "30.2.0" + "@jest/source-map" "30.0.1" + "@jest/test-result" "30.2.0" + "@jest/transform" "30.2.0" + "@jest/types" "30.2.0" + "@types/node" "*" + chalk "^4.1.2" + cjs-module-lexer "^2.1.0" + collect-v8-coverage "^1.0.2" + glob "^10.3.10" + graceful-fs "^4.2.11" + jest-haste-map "30.2.0" + jest-message-util "30.2.0" + jest-mock "30.2.0" + jest-regex-util "30.0.1" + jest-resolve "30.2.0" + jest-snapshot "30.2.0" + jest-util "30.2.0" + slash "^3.0.0" + strip-bom "^4.0.0" + +jest-snapshot@30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-30.2.0.tgz#266fbbb4b95fc4665ce6f32f1f38eeb39f4e26d0" + integrity sha512-5WEtTy2jXPFypadKNpbNkZ72puZCa6UjSr/7djeecHWOu7iYhSXSnHScT8wBz3Rn8Ena5d5RYRcsyKIeqG1IyA== + dependencies: + "@babel/core" "^7.27.4" + "@babel/generator" "^7.27.5" + "@babel/plugin-syntax-jsx" "^7.27.1" + "@babel/plugin-syntax-typescript" "^7.27.1" + "@babel/types" "^7.27.3" + "@jest/expect-utils" "30.2.0" + "@jest/get-type" "30.1.0" + "@jest/snapshot-utils" "30.2.0" + "@jest/transform" "30.2.0" + "@jest/types" "30.2.0" + babel-preset-current-node-syntax "^1.2.0" + chalk "^4.1.2" + expect "30.2.0" + graceful-fs "^4.2.11" + jest-diff "30.2.0" + jest-matcher-utils "30.2.0" + jest-message-util "30.2.0" + jest-util "30.2.0" + pretty-format "30.2.0" + semver "^7.7.2" + synckit "^0.11.8" + +jest-util@30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-30.2.0.tgz#5142adbcad6f4e53c2776c067a4db3c14f913705" + integrity sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA== + dependencies: + "@jest/types" "30.2.0" + "@types/node" "*" + chalk "^4.1.2" + ci-info "^4.2.0" + graceful-fs "^4.2.11" + picomatch "^4.0.2" + +jest-validate@30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-30.2.0.tgz#273eaaed4c0963b934b5b31e96289edda6e0a2ef" + integrity sha512-FBGWi7dP2hpdi8nBoWxSsLvBFewKAg0+uSQwBaof4Y4DPgBabXgpSYC5/lR7VmnIlSpASmCi/ntRWPbv7089Pw== + dependencies: + "@jest/get-type" "30.1.0" + "@jest/types" "30.2.0" + camelcase "^6.3.0" + chalk "^4.1.2" + leven "^3.1.0" + pretty-format "30.2.0" + +jest-watcher@30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-30.2.0.tgz#f9c055de48e18c979e7756a3917e596e2d69b07b" + integrity sha512-PYxa28dxJ9g777pGm/7PrbnMeA0Jr7osHP9bS7eJy9DuAjMgdGtxgf0uKMyoIsTWAkIbUW5hSDdJ3urmgXBqxg== + dependencies: + "@jest/test-result" "30.2.0" + "@jest/types" "30.2.0" + "@types/node" "*" + ansi-escapes "^4.3.2" + chalk "^4.1.2" + emittery "^0.13.1" + jest-util "30.2.0" + string-length "^4.0.2" + +jest-worker@30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-30.2.0.tgz#fd5c2a36ff6058ec8f74366ec89538cc99539d26" + integrity sha512-0Q4Uk8WF7BUwqXHuAjc23vmopWJw5WH7w2tqBoUOZpOjW/ZnR44GXXd1r82RvnmI2GZge3ivrYXk/BE2+VtW2g== + dependencies: + "@types/node" "*" + "@ungap/structured-clone" "^1.3.0" + jest-util "30.2.0" + merge-stream "^2.0.0" + supports-color "^8.1.1" + +jest@^30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/jest/-/jest-30.2.0.tgz#9f0a71e734af968f26952b5ae4b724af82681630" + integrity sha512-F26gjC0yWN8uAA5m5Ss8ZQf5nDHWGlN/xWZIh8S5SRbsEKBovwZhxGd6LJlbZYxBgCYOtreSUyb8hpXyGC5O4A== + dependencies: + "@jest/core" "30.2.0" + "@jest/types" "30.2.0" + import-local "^3.2.0" + jest-cli "30.2.0" + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^3.13.1: + version "3.14.2" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.2.tgz#77485ce1dd7f33c061fd1b16ecea23b55fcb04b0" + integrity sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg== dependencies: - argparse "^2.0.1" + argparse "^1.0.7" + esprima "^4.0.0" + +jsesc@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.1.0.tgz#74d335a234f67ed19907fdadfac7ccf9d409825d" + integrity sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA== json-buffer@3.0.1: version "3.0.1" - resolved "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== +json-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + json-schema-traverse@^0.4.1: version "0.4.1" - resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== -kafkajs@^2.2.4: - version "2.2.4" - resolved "https://registry.npmjs.org/kafkajs/-/kafkajs-2.2.4.tgz" - integrity sha512-j/YeapB1vfPT2iOIUn/vxdyKEuhuY2PxMBvf5JWux6iSaukAccrMtXEY/Lb7OvavDhOWME589bpLrEdnVHjfjA== +json-stringify-safe@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== + +json5@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== -keyv@^4.5.3: - version "4.5.3" - resolved "https://registry.npmjs.org/keyv/-/keyv-4.5.3.tgz" - integrity sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug== +keyv@^4.5.4: + version "4.5.4" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== dependencies: json-buffer "3.0.1" +kuler@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/kuler/-/kuler-2.0.0.tgz#e2c570a3800388fb44407e851531c1d670b061b3" + integrity sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A== + +lazystream@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.1.tgz#494c831062f1f9408251ec44db1cba29242a2638" + integrity sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw== + dependencies: + readable-stream "^2.0.5" + +leven@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== + levn@^0.4.1: version "0.4.1" - resolved "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== dependencies: prelude-ls "^1.2.1" type-check "~0.4.0" -libsodium-sumo@^0.7.11: - version "0.7.11" - resolved "https://registry.npmjs.org/libsodium-sumo/-/libsodium-sumo-0.7.11.tgz" - integrity sha512-bY+7ph7xpk51Ez2GbE10lXAQ5sJma6NghcIDaSPbM/G9elfrjLa0COHl/7P6Wb/JizQzl5UQontOOP1z0VwbLA== +libsodium-sumo@^0.7.16: + version "0.7.16" + resolved "https://registry.yarnpkg.com/libsodium-sumo/-/libsodium-sumo-0.7.16.tgz#85037acdf9029296373bf2a9f078930a723eedb5" + integrity sha512-x6atrz2AdXCJg6G709x9W9TTJRI6/0NcL5dD0l5GGVqNE48UJmDsjO4RUWYTeyXXUpg+NXZ2SHECaZnFRYzwGA== libsodium-wrappers-sumo@^0.7.11: - version "0.7.11" - resolved "https://registry.npmjs.org/libsodium-wrappers-sumo/-/libsodium-wrappers-sumo-0.7.11.tgz" - integrity sha512-DGypHOmJbB1nZn89KIfGOAkDgfv5N6SBGC3Qvmy/On0P0WD1JQvNRS/e3UL3aFF+xC0m+MYz5M+MnRnK2HMrKQ== + version "0.7.16" + resolved "https://registry.yarnpkg.com/libsodium-wrappers-sumo/-/libsodium-wrappers-sumo-0.7.16.tgz#53838cabe5d99768a3c070bdb65cd0043e0d0bfd" + integrity sha512-gR0JEFPeN3831lB9+ogooQk0KH4K5LSMIO5Prd5Q5XYR2wHFtZfPg0eP7t1oJIWq+UIzlU4WVeBxZ97mt28tXw== + dependencies: + libsodium-sumo "^0.7.16" + +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== + +lint-staged@^16.3.2: + version "16.3.2" + resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-16.3.2.tgz#378b48c6c340d42eefcc8d13d198b61a562e63a9" + integrity sha512-xKqhC2AeXLwiAHXguxBjuChoTTWFC6Pees0SHPwOpwlvI3BH7ZADFPddAdN3pgo3aiKgPUx/bxE78JfUnxQnlg== + dependencies: + commander "^14.0.3" + listr2 "^9.0.5" + micromatch "^4.0.8" + string-argv "^0.3.2" + tinyexec "^1.0.2" + yaml "^2.8.2" + +listr2@^9.0.5: + version "9.0.5" + resolved "https://registry.yarnpkg.com/listr2/-/listr2-9.0.5.tgz#92df7c4416a6da630eb9ef46da469b70de97b316" + integrity sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g== + dependencies: + cli-truncate "^5.0.0" + colorette "^2.0.20" + eventemitter3 "^5.0.1" + log-update "^6.1.0" + rfdc "^1.4.1" + wrap-ansi "^9.0.0" + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== dependencies: - libsodium-sumo "^0.7.11" + p-locate "^4.1.0" locate-path@^6.0.0: version "6.0.0" - resolved "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== dependencies: p-locate "^5.0.0" -lodash.merge@^4.6.2: - version "4.6.2" - resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz" - integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== +lodash.camelcase@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" + integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA== -log-symbols@4.1.0: - version "4.1.0" - resolved "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz" - integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== - dependencies: - chalk "^4.1.0" - is-unicode-supported "^0.1.0" +lodash.memoize@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" + integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== + +lodash@^4.17.15: + version "4.17.23" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.23.tgz#f113b0378386103be4f6893388c73d0bde7f2c5a" + integrity sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w== + +log-update@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/log-update/-/log-update-6.1.0.tgz#1a04ff38166f94647ae1af562f4bd6a15b1b7cd4" + integrity sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w== + dependencies: + ansi-escapes "^7.0.0" + cli-cursor "^5.0.0" + slice-ansi "^7.1.0" + strip-ansi "^7.1.0" + wrap-ansi "^9.0.0" + +logform@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/logform/-/logform-2.7.0.tgz#cfca97528ef290f2e125a08396805002b2d060d1" + integrity sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ== + dependencies: + "@colors/colors" "1.6.0" + "@types/triple-beam" "^1.3.2" + fecha "^4.2.0" + ms "^2.1.1" + safe-stable-stringify "^2.3.1" + triple-beam "^1.3.0" long@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/long/-/long-4.0.0.tgz" + resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA== -lru-cache@^10.0.1: - version "10.0.1" - resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.1.tgz" - integrity sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g== +long@^5.0.0: + version "5.3.2" + resolved "https://registry.yarnpkg.com/long/-/long-5.3.2.tgz#1d84463095999262d7d7b7f8bfd4a8cc55167f83" + integrity sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA== -lru-cache@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz" - integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== +lru-cache@^10.2.0: + version "10.4.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" + integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== dependencies: - yallist "^4.0.0" + yallist "^3.0.2" -map-stream@~0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz" - integrity sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g== +make-dir@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e" + integrity sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw== + dependencies: + semver "^7.5.3" + +make-error@^1.1.1, make-error@^1.3.6: + version "1.3.6" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + +makeerror@1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" + integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== + dependencies: + tmpl "1.0.5" + +math-intrinsics@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9" + integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== + +media-typer@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-1.1.0.tgz#6ab74b8f2d3320f2064b2a87a38e7931ff3a5561" + integrity sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw== + +merge-descriptors@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-2.0.0.tgz#ea922f660635a2249ee565e0449f951e6b603808" + integrity sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g== merge-stream@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== -merge2@^1.3.0, merge2@^1.4.1: - version "1.4.1" - resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz" - integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== - -micromatch@^4.0.4: - version "4.0.5" - resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz" - integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== +micromatch@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== dependencies: - braces "^3.0.2" + braces "^3.0.3" picomatch "^2.3.1" mime-db@1.52.0: version "1.52.0" - resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== +mime-db@^1.54.0: + version "1.54.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.54.0.tgz#cddb3ee4f9c64530dff640236661d42cb6a314f5" + integrity sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ== + mime-types@^2.1.12: version "2.1.35" - resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== dependencies: mime-db "1.52.0" +mime-types@^3.0.0, mime-types@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-3.0.2.tgz#39002d4182575d5af036ffa118100f2524b2e2ab" + integrity sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A== + dependencies: + mime-db "^1.54.0" + mimic-fn@^2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== -mimic-fn@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz" - integrity sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw== +mimic-function@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/mimic-function/-/mimic-function-5.0.1.tgz#acbe2b3349f99b9deaca7fb70e48b83e94e67076" + integrity sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA== minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== minimalistic-crypto-utils@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== -minimatch@5.0.1: - version "5.0.1" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz" - integrity sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g== +minimatch@^10.2.2, minimatch@^10.2.4: + version "10.2.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-10.2.4.tgz#465b3accbd0218b8281f5301e27cedc697f96fde" + integrity sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg== dependencies: - brace-expansion "^2.0.1" + brace-expansion "^5.0.2" -minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: - version "3.1.2" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" - integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== +minimatch@^3.0.3, minimatch@^3.0.4, minimatch@^3.1.1: + version "3.1.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.5.tgz#580c88f8d5445f2bd6aa8f3cadefa0de79fbd69e" + integrity sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w== dependencies: brace-expansion "^1.1.7" -mocha@^10.2.0: - version "10.2.0" - resolved "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz" - integrity sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg== - dependencies: - ansi-colors "4.1.1" - browser-stdout "1.3.1" - chokidar "3.5.3" - debug "4.3.4" - diff "5.0.0" - escape-string-regexp "4.0.0" - find-up "5.0.0" - glob "7.2.0" - he "1.2.0" - js-yaml "4.1.0" - log-symbols "4.1.0" - minimatch "5.0.1" - ms "2.1.3" - nanoid "3.3.3" - serialize-javascript "6.0.0" - strip-json-comments "3.1.1" - supports-color "8.1.1" - workerpool "6.2.1" - yargs "16.2.0" - yargs-parser "20.2.4" - yargs-unparser "2.0.0" - -ms@2.1.2: - version "2.1.2" - resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== +minimatch@^5.1.0: + version "5.1.9" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.9.tgz#1293ef15db0098b394540e8f9f744f9fda8dee4b" + integrity sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw== + dependencies: + brace-expansion "^2.0.1" + +minimatch@^9.0.4: + version "9.0.9" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.9.tgz#9b0cb9fcb78087f6fd7eababe2511c4d3d60574e" + integrity sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg== + dependencies: + brace-expansion "^2.0.2" + +minimist@^1.2.5: + version "1.2.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.1.2: + version "7.1.3" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.3.tgz#79389b4eb1bb2d003a9bba87d492f2bd37bdc65b" + integrity sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A== -ms@2.1.3: +mkdirp-classic@^0.5.2: + version "0.5.3" + resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" + integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== + +mkdirp@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + +mkdirp@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-3.0.1.tgz#e44e4c5607fb279c168241713cc6e0fea9adcb50" + integrity sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg== + +ms@^2.0.0, ms@^2.1.1, ms@^2.1.3: version "2.1.3" - resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== -nanoid@3.3.3: - version "3.3.3" - resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz" - integrity sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w== +nan@^2.19.0, nan@^2.23.0: + version "2.25.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.25.0.tgz#937ed345e63d9481362a7942d49c4860d27eeabd" + integrity sha512-0M90Ag7Xn5KMLLZ7zliPWP3rT90P6PN+IzVFS0VqmnPktBk3700xUVv8Ikm9EUaUE5SDWdp/BIxdENzVznpm1g== + +napi-postinstall@^0.3.0: + version "0.3.4" + resolved "https://registry.yarnpkg.com/napi-postinstall/-/napi-postinstall-0.3.4.tgz#7af256d6588b5f8e952b9190965d6b019653bbb9" + integrity sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ== natural-compare@^1.4.0: version "1.4.0" - resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== -node-cleanup@^2.1.2: - version "2.1.2" - resolved "https://registry.npmjs.org/node-cleanup/-/node-cleanup-2.1.2.tgz" - integrity sha512-qN8v/s2PAJwGUtr1/hYTpNKlD6Y9rc4p8KSmJXyGdYGZsDGKXrGThikLFP9OCHFeLeEpQzPwiAtdIvBLqm//Hw== +negotiator@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-1.0.0.tgz#b6c91bb47172d69f93cfd7c357bbb529019b5f6a" + integrity sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg== -normalize-path@^3.0.0, normalize-path@~3.0.0: +neo-async@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" + integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== + +node-cron@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/node-cron/-/node-cron-4.2.1.tgz#6979be4aee4702f06322d21220df8de252c8e265" + integrity sha512-lgimEHPE/QDgFlywTd8yTR61ptugX3Qer29efeyWw2rv259HtGBNn1vZVmp8lB9uo9wC0t/AT4iGqXxia+CJFg== + +node-fetch@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" + integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== + dependencies: + whatwg-url "^5.0.0" + +node-gyp-build@^4.3.0: + version "4.8.4" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.8.4.tgz#8a70ee85464ae52327772a90d66c6077a900cfc8" + integrity sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ== + +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== + +node-releases@^2.0.27: + version "2.0.36" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.36.tgz#99fd6552aaeda9e17c4713b57a63964a2e325e9d" + integrity sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA== + +noms@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/noms/-/noms-0.0.0.tgz#da8ebd9f3af9d6760919b27d9cdc8092a7332859" + integrity sha512-lNDU9VJaOPxUmXcLb+HQFeUgQQPtMI24Gt6hgfuMHRJgMRHMF/qZ4HJD3GDru4sSw9IQl2jPjAYnQrdIeLbwow== + dependencies: + inherits "^2.0.1" + readable-stream "~1.0.31" + +normalize-path@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== npm-run-path@^4.0.1: version "4.0.1" - resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== dependencies: path-key "^3.0.0" -npm-run-path@^5.1.0: - version "5.1.0" - resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz" - integrity sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q== - dependencies: - path-key "^4.0.0" +object-inspect@^1.13.3: + version "1.13.4" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.4.tgz#8375265e21bc20d0fa582c22e1b13485d6e00213" + integrity sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew== object-keys@^1.1.1: version "1.1.1" - resolved "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== -on-exit-leak-free@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.0.tgz" - integrity sha512-VuCaZZAjReZ3vUwgOB8LxAosIurDiAW0s13rI1YwmaP++jvcxP77AWoQvenZebpCA2m8WC1/EosPYPMjnRAp/w== +on-finished@^2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" + integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== + dependencies: + ee-first "1.1.1" -once@^1.3.0: +once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" - resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== dependencies: wrappy "1" +one-time@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/one-time/-/one-time-1.0.0.tgz#e06bc174aed214ed58edede573b433bbf827cb45" + integrity sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g== + dependencies: + fn.name "1.x.x" + onetime@^5.1.2: version "5.1.2" - resolved "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== dependencies: mimic-fn "^2.1.0" -onetime@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz" - integrity sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ== - dependencies: - mimic-fn "^4.0.0" - -open@^9.1.0: - version "9.1.0" - resolved "https://registry.npmjs.org/open/-/open-9.1.0.tgz" - integrity sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg== +onetime@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-7.0.0.tgz#9f16c92d8c9ef5120e3acd9dd9957cceecc1ab60" + integrity sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ== dependencies: - default-browser "^4.0.0" - define-lazy-prop "^3.0.0" - is-inside-container "^1.0.0" - is-wsl "^2.2.0" + mimic-function "^5.0.0" optionator@^0.9.3: - version "0.9.3" - resolved "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz" - integrity sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg== + version "0.9.4" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" + integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== dependencies: - "@aashutoshrathi/word-wrap" "^1.2.3" deep-is "^0.1.3" fast-levenshtein "^2.0.6" levn "^0.4.1" prelude-ls "^1.2.1" type-check "^0.4.0" + word-wrap "^1.2.5" -osmojs@^16.14.0: - version "16.14.0" - resolved "https://registry.npmjs.org/osmojs/-/osmojs-16.14.0.tgz" - integrity sha512-m4A5X0ZYanQ/u4/Xlz6nU9QqZEQbAKSD8SAKaDR/mIQYB6g3JkzWLgQgLMzMxDNJZKFTJCjWxHBp7al502x2aw== +osmojs@^16.15.0: + version "16.15.0" + resolved "https://registry.yarnpkg.com/osmojs/-/osmojs-16.15.0.tgz#ca96bf2a6c56cb0a86ed089948a24b08a6d1ea73" + integrity sha512-ERIXRzSF+EkS+RNFSzhTurr/EfWnpNfV6b1onf0MXd+YA3X3t8WbkboXg9+/ol61HDEGjugEGzRtz6sFvwaC3w== dependencies: "@cosmjs/amino" "0.32.3" "@cosmjs/proto-signing" "0.32.3" @@ -1738,130 +4348,205 @@ osmojs@^16.14.0: "@cosmjs/tendermint-rpc" "0.32.3" "@cosmology/lcd" "^0.13.3" -p-limit@^3.0.2: +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-limit@^3.0.2, p-limit@^3.1.0: version "3.1.0" - resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== dependencies: yocto-queue "^0.1.0" +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + p-locate@^5.0.0: version "5.0.0" - resolved "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== dependencies: p-limit "^3.0.2" -parent-module@^1.0.0: +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +package-json-from-dist@^1.0.0: 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== + resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz#4f1471a010827a86f94cfd9b0727e36d267de505" + integrity sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw== + +parse-json@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== dependencies: - callsites "^3.0.0" + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-even-better-errors "^2.3.0" + lines-and-columns "^1.1.6" + +parseurl@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== path-exists@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== path-is-absolute@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== path-key@^3.0.0, path-key@^3.1.0: version "3.1.1" - resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== -path-key@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz" - integrity sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ== - -path-type@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz" - integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== - -pause-stream@0.0.11: - version "0.0.11" - resolved "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz" - integrity sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A== +path-scurry@^1.11.1: + version "1.11.1" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2" + integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== dependencies: - through "~2.3" + lru-cache "^10.2.0" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" -picocolors@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz" - integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== +path-to-regexp@^8.0.0: + version "8.3.0" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-8.3.0.tgz#aa818a6981f99321003a08987d3cec9c3474cd1f" + integrity sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA== + +picocolors@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== -picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: +picomatch@^2.0.4, picomatch@^2.3.1: version "2.3.1" - resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== -pino-abstract-transport@v1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-1.1.0.tgz" - integrity sha512-lsleG3/2a/JIWUtf9Q5gUNErBqwIu1tUKTT3dUzaf5DySw9ra1wcqKjJjLX1VTY64Wk1eEOYsVGSaGfCK85ekA== - dependencies: - readable-stream "^4.0.0" - split2 "^4.0.0" +picomatch@^4.0.2, picomatch@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.3.tgz#796c76136d1eead715db1e7bad785dedd695a042" + integrity sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q== + +pirates@^4.0.7: + version "4.0.7" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.7.tgz#643b4a18c4257c8a65104b73f3049ce9a0a15e22" + integrity sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA== + +piscina@^5.1.4: + version "5.1.4" + resolved "https://registry.yarnpkg.com/piscina/-/piscina-5.1.4.tgz#86ca2b8e42bcbfc258dc7b09d918ee04b2327a67" + integrity sha512-7uU4ZnKeQq22t9AsmHGD2w4OYQGonwFnTypDypaWi7Qr2EvQIFVtG8J5D/3bE7W123Wdc9+v4CZDu5hJXVCtBg== + optionalDependencies: + "@napi-rs/nice" "^1.0.4" -pino-std-serializers@^6.0.0: - version "6.2.2" - resolved "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-6.2.2.tgz" - integrity sha512-cHjPPsE+vhj/tnhCy/wiMh3M3z3h/j15zHQX+S9GkTBgqJuTuJzYJ4gUyACLhDaJ7kk9ba9iRDmbH2tJU03OiA== - -pino@^8.15.1: - version "8.15.1" - resolved "https://registry.npmjs.org/pino/-/pino-8.15.1.tgz" - integrity sha512-Cp4QzUQrvWCRJaQ8Lzv0mJzXVk4z2jlq8JNKMGaixC2Pz5L4l2p95TkuRvYbrEbe85NQsDKrAd4zalf7Ml6WiA== - dependencies: - atomic-sleep "^1.0.0" - fast-redact "^3.1.1" - on-exit-leak-free "^2.1.0" - pino-abstract-transport v1.1.0 - pino-std-serializers "^6.0.0" - process-warning "^2.0.0" - quick-format-unescaped "^4.0.3" - real-require "^0.2.0" - safe-stable-stringify "^2.3.1" - sonic-boom "^3.1.0" - thread-stream "^2.0.0" +pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" prelude-ls@^1.2.1: version "1.2.1" - resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== -prettier-linter-helpers@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz" - integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== +prettier-linter-helpers@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.1.tgz#6a31f88a4bad6c7adda253de12ba4edaea80ebcd" + integrity sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg== dependencies: fast-diff "^1.1.2" -prettier@^3.0.3: - version "3.0.3" - resolved "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz" - integrity sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg== +prettier@^3.6.2: + version "3.8.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.8.1.tgz#edf48977cf991558f4fcbd8a3ba6015ba2a3a173" + integrity sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg== -process-warning@^2.0.0: - version "2.2.0" - resolved "https://registry.npmjs.org/process-warning/-/process-warning-2.2.0.tgz" - integrity sha512-/1WZ8+VQjR6avWOgHeEPd7SDQmFQ1B5mC1eRXsCm5TarlNmx/wCsa5GEaxGm05BORRtyG/Ex/3xq3TuRvq57qg== +pretty-format@30.2.0, pretty-format@^30.0.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-30.2.0.tgz#2d44fe6134529aed18506f6d11509d8a62775ebe" + integrity sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA== + dependencies: + "@jest/schemas" "30.0.5" + ansi-styles "^5.2.0" + react-is "^18.3.1" + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== process@^0.11.10: version "0.11.10" - resolved "https://registry.npmjs.org/process/-/process-0.11.10.tgz" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== -protobufjs@^6.8.8, protobufjs@~6.11.2, protobufjs@~6.11.3: - version "6.11.4" - resolved "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.4.tgz" - integrity sha512-5kQWPaJHi1WoCpjTGszzQ32PG2F4+wRY6BmAT4Vfw56Q2FZ4YZzK20xUYQH4YkfehY1e6QSICrJquM6xXZNcrw== +prom-client@^15.1.3: + version "15.1.3" + resolved "https://registry.yarnpkg.com/prom-client/-/prom-client-15.1.3.tgz#69fa8de93a88bc9783173db5f758dc1c69fa8fc2" + integrity sha512-6ZiOBfCywsD4k1BN9IX0uZhF+tJkV8q8llP64G5Hajs4JOeVLPCwpPVcpXy3BwYiUGgyJzsJJQeOIv7+hDSq8g== + dependencies: + "@opentelemetry/api" "^1.4.0" + tdigest "^0.1.1" + +proper-lockfile@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/proper-lockfile/-/proper-lockfile-4.1.2.tgz#c8b9de2af6b2f1601067f98e01ac66baa223141f" + integrity sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA== + dependencies: + graceful-fs "^4.2.4" + retry "^0.12.0" + signal-exit "^3.0.2" + +properties-reader@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/properties-reader/-/properties-reader-3.0.1.tgz#576af69708759bb75672bfc162b80cc8a3d1bdb2" + integrity sha512-WPn+h9RGEExOKdu4bsF4HksG/uzd3cFq3MFtq8PsFeExPse5Ha/VOjQNyHhjboBFwGXGev6muJYTSPAOkROq2g== + dependencies: + "@kwsites/file-exists" "^1.1.1" + mkdirp "^3.0.1" + +protobufjs@^6.8.8: + version "6.11.4" + resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.11.4.tgz#29a412c38bf70d89e537b6d02d904a6f448173aa" + integrity sha512-5kQWPaJHi1WoCpjTGszzQ32PG2F4+wRY6BmAT4Vfw56Q2FZ4YZzK20xUYQH4YkfehY1e6QSICrJquM6xXZNcrw== + dependencies: + "@protobufjs/aspromise" "^1.1.2" + "@protobufjs/base64" "^1.1.2" + "@protobufjs/codegen" "^2.0.4" + "@protobufjs/eventemitter" "^1.1.0" + "@protobufjs/fetch" "^1.1.0" + "@protobufjs/float" "^1.0.2" + "@protobufjs/inquire" "^1.1.0" + "@protobufjs/path" "^1.1.2" + "@protobufjs/pool" "^1.1.0" + "@protobufjs/utf8" "^1.1.0" + "@types/long" "^4.0.1" + "@types/node" ">=13.7.0" + long "^4.0.0" + +protobufjs@^7.2.5, protobufjs@^7.3.2, protobufjs@^7.5.3: + version "7.5.4" + resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.5.4.tgz#885d31fe9c4b37f25d1bb600da30b1c5b37d286a" + integrity sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg== dependencies: "@protobufjs/aspromise" "^1.1.2" "@protobufjs/base64" "^1.1.2" @@ -1873,48 +4558,93 @@ protobufjs@^6.8.8, protobufjs@~6.11.2, protobufjs@~6.11.3: "@protobufjs/path" "^1.1.2" "@protobufjs/pool" "^1.1.0" "@protobufjs/utf8" "^1.1.0" - "@types/long" "^4.0.1" "@types/node" ">=13.7.0" - long "^4.0.0" + long "^5.0.0" + +proxy-addr@^2.0.7: + version "2.0.7" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" + integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== + dependencies: + forwarded "0.2.0" + ipaddr.js "1.9.1" proxy-from-env@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== -ps-tree@^1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/ps-tree/-/ps-tree-1.2.0.tgz" - integrity sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA== +pump@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.4.tgz#1f313430527fa8b905622ebd22fe1444e757ab3c" + integrity sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA== dependencies: - event-stream "=3.3.4" + end-of-stream "^1.1.0" + once "^1.3.1" punycode@^2.1.0: - version "2.3.0" - resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz" - integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== -queue-microtask@^1.2.2: - version "1.2.3" - resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz" - integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== +pure-rand@^7.0.0: + version "7.0.1" + resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-7.0.1.tgz#6f53a5a9e3e4a47445822af96821ca509ed37566" + integrity sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ== -quick-format-unescaped@^4.0.3: - version "4.0.4" - resolved "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz" - integrity sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg== +qs@^6.14.0, qs@^6.14.1: + version "6.15.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.15.0.tgz#db8fd5d1b1d2d6b5b33adaf87429805f1909e7b3" + integrity sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ== + dependencies: + side-channel "^1.1.0" -randombytes@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz" - integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== +range-parser@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-3.0.2.tgz#3e3ada5ae5568f9095d84376fd3a49b8fb000a51" + integrity sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA== + dependencies: + bytes "~3.1.2" + http-errors "~2.0.1" + iconv-lite "~0.7.0" + unpipe "~1.0.0" + +react-is@^18.3.1: + version "18.3.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" + integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== + +readable-stream@^2.0.5, readable-stream@~2.3.6: + version "2.3.8" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" + integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.5.0, readable-stream@^3.6.2: + version "3.6.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== dependencies: - safe-buffer "^5.1.0" + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" readable-stream@^4.0.0: - version "4.4.2" - resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-4.4.2.tgz" - integrity sha512-Lk/fICSyIhodxy1IDK2HazkeGjSmezAWX2egdtJnYhtzKEsBPJowlI6F6LPb5tqIQILrMbx22S5o3GuJavPusA== + version "4.7.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-4.7.0.tgz#cedbd8a1146c13dfff8dab14068028d58c15ac91" + integrity sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg== dependencies: abort-controller "^3.0.0" buffer "^6.0.3" @@ -1922,351 +4652,1032 @@ readable-stream@^4.0.0: process "^0.11.10" string_decoder "^1.3.0" -readdirp@~3.6.0: - version "3.6.0" - resolved "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz" - integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== +readable-stream@~1.0.31: + version "1.0.34" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" + integrity sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +readdir-glob@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/readdir-glob/-/readdir-glob-1.1.3.tgz#c3d831f51f5e7bfa62fa2ffbe4b508c640f09584" + integrity sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA== dependencies: - picomatch "^2.2.1" + minimatch "^5.1.0" readonly-date@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/readonly-date/-/readonly-date-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/readonly-date/-/readonly-date-1.0.0.tgz#5af785464d8c7d7c40b9d738cbde8c646f97dcd9" integrity sha512-tMKIV7hlk0h4mO3JTmmVuIlJVXjKk3Sep9Bf5OH0O+758ruuVkUy2J9SttDLm91IEX/WHlXPSpxMGjPj4beMIQ== -real-require@^0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz" - integrity sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg== +redis@^4.6.0: + version "4.7.1" + resolved "https://registry.yarnpkg.com/redis/-/redis-4.7.1.tgz#08588a30936be0e7ad9c0f3e1ac6a85ccaf73e94" + integrity sha512-S1bJDnqLftzHXHP8JsT5II/CtHWQrASX5K96REjWjlmWKrviSOLWmM7QnRLstAWsu1VBBV1ffV6DzCvxNP0UJQ== + dependencies: + "@redis/bloom" "1.2.0" + "@redis/client" "1.6.1" + "@redis/graph" "1.1.1" + "@redis/json" "1.0.7" + "@redis/search" "1.2.0" + "@redis/time-series" "1.1.0" + +reflect-metadata@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.2.2.tgz#400c845b6cba87a21f2c65c4aeb158f4fa4d9c5b" + integrity sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q== require-directory@^2.1.1: version "2.1.1" - resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== -resolve-from@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz" - integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== - -reusify@^1.0.4: - version "1.0.4" - resolved "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz" - integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== - -rimraf@^3.0.2: - version "3.0.2" - resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== +resolve-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== dependencies: - glob "^7.1.3" + resolve-from "^5.0.0" -run-applescript@^5.0.0: +resolve-from@^5.0.0: version "5.0.0" - resolved "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz" - integrity sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg== - dependencies: - execa "^5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== -run-parallel@^1.1.9: - version "1.2.0" - resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz" - integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== +restore-cursor@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-5.1.0.tgz#0766d95699efacb14150993f55baf0953ea1ebe7" + integrity sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA== dependencies: - queue-microtask "^1.2.2" + onetime "^7.0.0" + signal-exit "^4.1.0" + +retry@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" + integrity sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow== + +rfdc@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.4.1.tgz#778f76c4fb731d93414e8f925fbecf64cce7f6ca" + integrity sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA== -safe-buffer@^5.1.0, safe-buffer@~5.2.0: +router@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/router/-/router-2.2.0.tgz#019be620b711c87641167cc79b99090f00b146ef" + integrity sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ== + dependencies: + debug "^4.4.0" + depd "^2.0.0" + is-promise "^4.0.0" + parseurl "^1.3.3" + path-to-regexp "^8.0.0" + +rpc-websockets@^9.0.2: + version "9.3.5" + resolved "https://registry.yarnpkg.com/rpc-websockets/-/rpc-websockets-9.3.5.tgz#9adb87514cb219434d67b7d3f455e5c132aff956" + integrity sha512-4mAmr+AEhPYJ9TmDtxF3r3ZcbWy7W8kvZ4PoZYw/Xgp2J7WixjwTgiQZsoTDvch5nimmg3Ay6/0Kuh9oIvVs9A== + dependencies: + "@swc/helpers" "^0.5.11" + "@types/uuid" "^10.0.0" + "@types/ws" "^8.2.2" + buffer "^6.0.3" + eventemitter3 "^5.0.1" + uuid "^11.0.0" + ws "^8.5.0" + optionalDependencies: + bufferutil "^4.0.1" + utf-8-validate "^6.0.0" + +safe-buffer@^5.0.1, safe-buffer@~5.2.0: version "5.2.1" - resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== +safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + safe-stable-stringify@^2.3.1: - version "2.4.3" - resolved "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz" - integrity sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g== + version "2.5.0" + resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz#4ca2f8e385f2831c432a719b108a3bf7af42a1dd" + integrity sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA== -semver@^7.5.4: - version "7.5.4" - resolved "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz" - integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== - dependencies: - lru-cache "^6.0.0" +"safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@~2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -serialize-javascript@6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz" - integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag== +semver@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +semver@^7.5.3, semver@^7.5.4, semver@^7.7.2, semver@^7.7.3: + version "7.7.4" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.4.tgz#28464e36060e991fa7a11d0279d2d3f3b57a7e8a" + integrity sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA== + +send@^1.1.0, send@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/send/-/send-1.2.1.tgz#9eab743b874f3550f40a26867bf286ad60d3f3ed" + integrity sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ== + dependencies: + debug "^4.4.3" + encodeurl "^2.0.0" + escape-html "^1.0.3" + etag "^1.8.1" + fresh "^2.0.0" + http-errors "^2.0.1" + mime-types "^3.0.2" + ms "^2.1.3" + on-finished "^2.4.1" + range-parser "^1.2.1" + statuses "^2.0.2" + +serve-static@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-2.2.1.tgz#7f186a4a4e5f5b663ad7a4294ff1bf37cf0e98a9" + integrity sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw== dependencies: - randombytes "^2.1.0" + encodeurl "^2.0.0" + escape-html "^1.0.3" + parseurl "^1.3.3" + send "^1.2.0" + +setprototypeof@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" + integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== shebang-command@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== dependencies: shebang-regex "^3.0.0" shebang-regex@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -signal-exit@^3.0.3, signal-exit@^3.0.7: +side-channel-list@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/side-channel-list/-/side-channel-list-1.0.0.tgz#10cb5984263115d3b7a0e336591e290a830af8ad" + integrity sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA== + dependencies: + es-errors "^1.3.0" + object-inspect "^1.13.3" + +side-channel-map@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/side-channel-map/-/side-channel-map-1.0.1.tgz#d6bb6b37902c6fef5174e5f533fab4c732a26f42" + integrity sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + get-intrinsic "^1.2.5" + object-inspect "^1.13.3" + +side-channel-weakmap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz#11dda19d5368e40ce9ec2bdc1fb0ecbc0790ecea" + integrity sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + get-intrinsic "^1.2.5" + object-inspect "^1.13.3" + side-channel-map "^1.0.1" + +side-channel@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.1.0.tgz#c3fcff9c4da932784873335ec9765fa94ff66bc9" + integrity sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw== + dependencies: + es-errors "^1.3.0" + object-inspect "^1.13.3" + side-channel-list "^1.0.0" + side-channel-map "^1.0.1" + side-channel-weakmap "^1.0.2" + +signal-exit@^3.0.2, signal-exit@^3.0.3: version "3.0.7" - resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== +signal-exit@^4.0.1, signal-exit@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== + slash@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== -sonic-boom@^3.1.0: - version "3.3.0" - resolved "https://registry.npmjs.org/sonic-boom/-/sonic-boom-3.3.0.tgz" - integrity sha512-LYxp34KlZ1a2Jb8ZQgFCK3niIHzibdwtwNUWKg0qQRzsDoJ3Gfgkf8KdBTFU3SkejDEIlWwnSnpVdOZIhFMl/g== +slice-ansi@^7.1.0: + version "7.1.2" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-7.1.2.tgz#adf7be70aa6d72162d907cd0e6d5c11f507b5403" + integrity sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w== dependencies: - atomic-sleep "^1.0.0" + ansi-styles "^6.2.1" + is-fullwidth-code-point "^5.0.0" -split2@^4.0.0: - version "4.2.0" - resolved "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz" - integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg== +slice-ansi@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-8.0.0.tgz#22d0b66d18bc5c57f488bfcf36cbde3bef731537" + integrity sha512-stxByr12oeeOyY2BlviTNQlYV5xOj47GirPr4yA1hE9JCtxfQN0+tVbkxwCtYDQWhEKWFHsEK48ORg5jrouCAg== + dependencies: + ansi-styles "^6.2.3" + is-fullwidth-code-point "^5.1.0" + +source-map-support@0.5.13: + version "0.5.13" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" + integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.6.0, source-map@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +split-ca@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/split-ca/-/split-ca-1.0.1.tgz#6c83aff3692fa61256e0cd197e05e9de157691a6" + integrity sha512-Q5thBSxp5t8WPTTJQS59LrGqOZqOsrhDGDVm8azCqIBjSBd7nd9o2PM+mDulQQkh8h//4U6hFZnc/mul8t5pWQ== + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== + +ssh-remote-port-forward@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/ssh-remote-port-forward/-/ssh-remote-port-forward-1.0.4.tgz#72b0c5df8ec27ca300c75805cc6b266dee07e298" + integrity sha512-x0LV1eVDwjf1gmG7TTnfqIzf+3VPRz7vrNIjX6oYLbeCrf/PeVY6hkT68Mg+q02qXxQhrLjB0jfgvhevoCRmLQ== + dependencies: + "@types/ssh2" "^0.5.48" + ssh2 "^1.4.0" + +ssh2@^1.15.0, ssh2@^1.4.0: + version "1.17.0" + resolved "https://registry.yarnpkg.com/ssh2/-/ssh2-1.17.0.tgz#dc686e8e3abdbd4ad95d46fa139615903c12258c" + integrity sha512-wPldCk3asibAjQ/kziWQQt1Wh3PgDFpC0XpwclzKcdT1vql6KeYxf5LIt4nlFkUeR8WuphYMKqUA56X4rjbfgQ== + dependencies: + asn1 "^0.2.6" + bcrypt-pbkdf "^1.0.2" + optionalDependencies: + cpu-features "~0.0.10" + nan "^2.23.0" + +stack-trace@0.0.x: + version "0.0.10" + resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" + integrity sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg== -split@0.3: - version "0.3.3" - resolved "https://registry.npmjs.org/split/-/split-0.3.3.tgz" - integrity sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA== +stack-utils@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f" + integrity sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ== + dependencies: + escape-string-regexp "^2.0.0" + +statuses@^2.0.1, statuses@^2.0.2, statuses@~2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.2.tgz#8f75eecef765b5e1cfcdc080da59409ed424e382" + integrity sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw== + +stream-chain@^2.2.5: + version "2.2.5" + resolved "https://registry.yarnpkg.com/stream-chain/-/stream-chain-2.2.5.tgz#b30967e8f14ee033c5b9a19bbe8a2cba90ba0d09" + integrity sha512-1TJmBx6aSWqZ4tx7aTpBDXK0/e2hhcNSTV8+CbFJtDjbb+I1mZ8lHit0Grw9GRT+6JbIrrDd8esncgBi8aBXGA== + +stream-json@^1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/stream-json/-/stream-json-1.9.1.tgz#e3fec03e984a503718946c170db7d74556c2a187" + integrity sha512-uWkjJ+2Nt/LO9Z/JyKZbMusL8Dkh97uUBTv3AJQ74y07lVahLY4eEFsPsE97pxYBwr8nnjMAIch5eqI0gPShyw== dependencies: - through "2" + stream-chain "^2.2.5" -stream-combiner@~0.0.4: - version "0.0.4" - resolved "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz" - integrity sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw== +streamx@^2.12.5, streamx@^2.15.0, streamx@^2.21.0: + version "2.23.0" + resolved "https://registry.yarnpkg.com/streamx/-/streamx-2.23.0.tgz#7d0f3d00d4a6c5de5728aecd6422b4008d66fd0b" + integrity sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg== dependencies: - duplexer "~0.1.1" + events-universal "^1.0.0" + fast-fifo "^1.3.2" + text-decoder "^1.1.0" -string-argv@^0.3.1: +string-argv@^0.3.2: version "0.3.2" - resolved "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz" + resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.2.tgz#2b6d0ef24b656274d957d54e0a4bbf6153dc02b6" integrity sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q== -string-width@^4.1.0, string-width@^4.2.0: +string-length@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" + integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== + dependencies: + char-regex "^1.0.2" + strip-ansi "^6.0.0" + +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" - resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== dependencies: emoji-regex "^8.0.0" is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" -string_decoder@^1.3.0: +string-width@^5.0.1, string-width@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" + integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== + dependencies: + eastasianwidth "^0.2.0" + emoji-regex "^9.2.2" + strip-ansi "^7.0.1" + +string-width@^7.0.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-7.2.0.tgz#b5bb8e2165ce275d4d43476dd2700ad9091db6dc" + integrity sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ== + dependencies: + emoji-regex "^10.3.0" + get-east-asian-width "^1.0.0" + strip-ansi "^7.1.0" + +string-width@^8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-8.2.0.tgz#bdb6a9bd6d7800db635adae96cdb0443fec56c42" + integrity sha512-6hJPQ8N0V0P3SNmP6h2J99RLuzrWz2gvT7VnK5tKvrNqJoyS9W4/Fb8mo31UiPvy00z7DQXkP2hnKBVav76thw== + dependencies: + get-east-asian-width "^1.5.0" + strip-ansi "^7.1.2" + +string_decoder@^1.1.1, string_decoder@^1.3.0: version "1.3.0" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== dependencies: safe-buffer "~5.2.0" +string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + integrity sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ== + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== dependencies: ansi-regex "^5.0.1" +strip-ansi@^7.0.1, strip-ansi@^7.1.0, strip-ansi@^7.1.2: + version "7.2.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.2.0.tgz#d22a269522836a627af8d04b5c3fd2c7fa3e32e3" + integrity sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w== + dependencies: + ansi-regex "^6.2.2" + +strip-bom@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" + integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== + strip-final-newline@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== -strip-final-newline@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz" - integrity sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw== - -strip-json-comments@3.1.1, strip-json-comments@^3.1.1: +strip-json-comments@^3.1.1: version "3.1.1" - resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== -supports-color@8.1.1: - version "8.1.1" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz" - integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== - dependencies: - has-flag "^4.0.0" +superstruct@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-2.0.2.tgz#3f6d32fbdc11c357deff127d591a39b996300c54" + integrity sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A== supports-color@^7.1.0: version "7.2.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== dependencies: has-flag "^4.0.0" +supports-color@^8.1.1: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + symbol-observable@^2.0.3: version "2.0.3" - resolved "https://registry.npmjs.org/symbol-observable/-/symbol-observable-2.0.3.tgz" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-2.0.3.tgz#5b521d3d07a43c351055fa43b8355b62d33fd16a" integrity sha512-sQV7phh2WCYAn81oAkakC5qjq2Ml0g8ozqz03wOGnx9dDlG1de6yrF+0RAzSJD8fPUow3PTSMf2SAbOGxb93BA== -synckit@^0.8.5: - version "0.8.5" - resolved "https://registry.npmjs.org/synckit/-/synckit-0.8.5.tgz" - integrity sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q== +synckit@^0.11.12, synckit@^0.11.8: + version "0.11.12" + resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.11.12.tgz#abe74124264fbc00a48011b0d98bdc1cffb64a7b" + integrity sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ== dependencies: - "@pkgr/utils" "^2.3.1" - tslib "^2.5.0" + "@pkgr/core" "^0.2.9" -text-table@^0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz" - integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== +tar-fs@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.4.tgz#800824dbf4ef06ded9afea4acafe71c67c76b930" + integrity sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ== + dependencies: + chownr "^1.1.1" + mkdirp-classic "^0.5.2" + pump "^3.0.0" + tar-stream "^2.1.4" -thread-stream@^2.0.0: - version "2.4.0" - resolved "https://registry.npmjs.org/thread-stream/-/thread-stream-2.4.0.tgz" - integrity sha512-xZYtOtmnA63zj04Q+F9bdEay5r47bvpo1CaNqsKi7TpoJHcotUez8Fkfo2RJWpW91lnnaApdpRbVwCWsy+ifcw== +tar-fs@^3.1.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-3.1.2.tgz#114b012f54796f31e62f3e57792820a80b83ae6e" + integrity sha512-QGxxTxxyleAdyM3kpFs14ymbYmNFrfY+pHj7Z8FgtbZ7w2//VAgLMac7sT6nRpIHjppXO2AwwEOg0bPFVRcmXw== + dependencies: + pump "^3.0.0" + tar-stream "^3.1.5" + optionalDependencies: + bare-fs "^4.0.1" + bare-path "^3.0.0" + +tar-stream@^2.1.4: + version "2.2.0" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" + integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== dependencies: - real-require "^0.2.0" + bl "^4.0.3" + end-of-stream "^1.4.1" + fs-constants "^1.0.0" + inherits "^2.0.3" + readable-stream "^3.1.1" -through@2, through@~2.3, through@~2.3.1: - version "2.3.8" - resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz" - integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== +tar-stream@^3.0.0, tar-stream@^3.1.5: + version "3.1.8" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-3.1.8.tgz#a26f5b26c34dfd4936a4f8a9e694a8f5102af13d" + integrity sha512-U6QpVRyCGHva435KoNWy9PRoi2IFYCgtEhq9nmrPPpbRacPs9IH4aJ3gbrFC8dPcXvdSZ4XXfXT5Fshbp2MtlQ== + dependencies: + b4a "^1.6.4" + bare-fs "^4.5.5" + fast-fifo "^1.2.0" + streamx "^2.15.0" -titleize@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/titleize/-/titleize-3.0.0.tgz" - integrity sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ== +tdigest@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/tdigest/-/tdigest-0.1.2.tgz#96c64bac4ff10746b910b0e23b515794e12faced" + integrity sha512-+G0LLgjjo9BZX2MfdvPfH+MKLCrxlXSYec5DaPYP1fe6Iyhf0/fSmJ0bFiZ1F8BT6cGXl2LpltQptzjXKWEkKA== + dependencies: + bintrees "1.0.2" + +teex@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/teex/-/teex-1.0.1.tgz#b8fa7245ef8e8effa8078281946c85ab780a0b12" + integrity sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg== + dependencies: + streamx "^2.12.5" + +test-exclude@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" + integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== + dependencies: + "@istanbuljs/schema" "^0.1.2" + glob "^7.1.4" + minimatch "^3.0.4" + +testcontainers@^11.12.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/testcontainers/-/testcontainers-11.12.0.tgz#2a2b9f9d20955f658959a44ed5ac0f2aedf7077a" + integrity sha512-VWtH+UQejVYYvb53ohEZRbx2naxyDvwO9lQ6A0VgmVE2Oh8r9EF09I+BfmrXpd9N9ntpzhao9di2yNwibSz5KA== + dependencies: + "@balena/dockerignore" "^1.0.2" + "@types/dockerode" "^4.0.1" + archiver "^7.0.1" + async-lock "^1.4.1" + byline "^5.0.0" + debug "^4.4.3" + docker-compose "^1.3.1" + dockerode "^4.0.9" + get-port "^7.1.0" + proper-lockfile "^4.1.2" + properties-reader "^3.0.1" + ssh-remote-port-forward "^1.0.4" + tar-fs "^3.1.1" + tmp "^0.2.5" + undici "^7.22.0" + +text-decoder@^1.1.0: + version "1.2.7" + resolved "https://registry.yarnpkg.com/text-decoder/-/text-decoder-1.2.7.tgz#5d073a9a74b9c0a9d28dfadcab96b604af57d8ba" + integrity sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ== + dependencies: + b4a "^1.6.4" + +text-encoding-utf-8@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz#585b62197b0ae437e3c7b5d0af27ac1021e10d13" + integrity sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg== + +text-hex@1.0.x: + version "1.0.0" + resolved "https://registry.yarnpkg.com/text-hex/-/text-hex-1.0.0.tgz#69dc9c1b17446ee79a92bf5b884bb4b9127506f5" + integrity sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg== + +through2@^2.0.1: + version "2.0.5" + resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" + integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== + dependencies: + readable-stream "~2.3.6" + xtend "~4.0.1" + +tinyexec@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/tinyexec/-/tinyexec-1.0.2.tgz#bdd2737fe2ba40bd6f918ae26642f264b99ca251" + integrity sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg== + +tinyglobby@^0.2.15: + version "0.2.15" + resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.15.tgz#e228dd1e638cea993d2fdb4fcd2d4602a79951c2" + integrity sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ== + dependencies: + fdir "^6.5.0" + picomatch "^4.0.3" + +tmp@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.5.tgz#b06bcd23f0f3c8357b426891726d16015abfd8f8" + integrity sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow== + +tmpl@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" + integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== to-regex-range@^5.0.1: version "5.0.1" - resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== dependencies: is-number "^7.0.0" -ts-api-utils@^1.0.1: - version "1.0.3" - resolved "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz" - integrity sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg== +toidentifier@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" + integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== -tsc-watch@^6.0.4: - version "6.0.4" - resolved "https://registry.npmjs.org/tsc-watch/-/tsc-watch-6.0.4.tgz" - integrity sha512-cHvbvhjO86w2aGlaHgSCeQRl+Aqw6X6XN4sQMPZKF88GoP30O+oTuh5lRIJr5pgFWrRpF1AgXnJJ2DoFEIPHyg== - dependencies: - cross-spawn "^7.0.3" - node-cleanup "^2.1.2" - ps-tree "^1.2.0" - string-argv "^0.3.1" +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== -tslib@^2.5.0, tslib@^2.6.0: - version "2.6.2" - resolved "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz" - integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== +triple-beam@^1.3.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.4.1.tgz#6fde70271dc6e5d73ca0c3b24e2d92afb7441984" + integrity sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg== + +ts-api-utils@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-2.4.0.tgz#2690579f96d2790253bdcf1ca35d569ad78f9ad8" + integrity sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA== + +ts-jest@^29.4.6: + version "29.4.6" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.4.6.tgz#51cb7c133f227396818b71297ad7409bb77106e9" + integrity sha512-fSpWtOO/1AjSNQguk43hb/JCo16oJDnMJf3CdEGNkqsEX3t0KX96xvyX1D7PfLCpVoKu4MfVrqUkFyblYoY4lA== + dependencies: + bs-logger "^0.2.6" + fast-json-stable-stringify "^2.1.0" + handlebars "^4.7.8" + json5 "^2.2.3" + lodash.memoize "^4.1.2" + make-error "^1.3.6" + semver "^7.7.3" + type-fest "^4.41.0" + yargs-parser "^21.1.1" + +ts-node@^10.9.1: + version "10.9.2" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.2.tgz#70f021c9e185bccdca820e26dc413805c101c71f" + integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== + dependencies: + "@cspotcode/source-map-support" "^0.8.0" + "@tsconfig/node10" "^1.0.7" + "@tsconfig/node12" "^1.0.7" + "@tsconfig/node14" "^1.0.0" + "@tsconfig/node16" "^1.0.2" + acorn "^8.4.1" + acorn-walk "^8.1.1" + arg "^4.1.0" + create-require "^1.1.0" + diff "^4.0.1" + make-error "^1.1.1" + v8-compile-cache-lib "^3.0.1" + yn "3.1.1" + +tslib@2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.7.0.tgz#d9b40c5c40ab59e8738f297df3087bf1a2690c01" + integrity sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA== + +tslib@^2.4.0, tslib@^2.8.0: + version "2.8.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" + integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== + +tweetnacl@^0.14.3: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + integrity sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA== type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" - resolved "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== dependencies: prelude-ls "^1.2.1" -type-fest@^0.20.2: - 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== +type-detect@4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + +type-fest@^4.41.0: + version "4.41.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-4.41.0.tgz#6ae1c8e5731273c2bf1f58ad39cbae2c91a46c58" + integrity sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA== + +type-is@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-2.0.1.tgz#64f6cf03f92fce4015c2b224793f6bdd4b068c97" + integrity sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw== + dependencies: + content-type "^1.0.5" + media-typer "^1.1.0" + mime-types "^3.0.0" + +typescript-eslint@^8.52.0: + version "8.56.1" + resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.56.1.tgz#15a9fcc5d2150a0d981772bb36f127a816fe103f" + integrity sha512-U4lM6pjmBX7J5wk4szltF7I1cGBHXZopnAXCMXb3+fZ3B/0Z3hq3wS/CCUB2NZBNAExK92mCU2tEohWuwVMsDQ== + dependencies: + "@typescript-eslint/eslint-plugin" "8.56.1" + "@typescript-eslint/parser" "8.56.1" + "@typescript-eslint/typescript-estree" "8.56.1" + "@typescript-eslint/utils" "8.56.1" + +typescript@^5.8.3: + version "5.9.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.9.3.tgz#5b4f59e15310ab17a216f5d6cf53ee476ede670f" + integrity sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw== + +uglify-js@^3.1.4: + version "3.19.3" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.19.3.tgz#82315e9bbc6f2b25888858acd1fff8441035b77f" + integrity sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ== + +undici-types@~5.26.4: + version "5.26.5" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" + integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== + +undici-types@~6.19.2: + version "6.19.8" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" + integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== + +undici-types@~6.21.0: + version "6.21.0" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.21.0.tgz#691d00af3909be93a7faa13be61b3a5b50ef12cb" + integrity sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ== + +undici-types@~7.18.0: + version "7.18.2" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-7.18.2.tgz#29357a89e7b7ca4aef3bf0fd3fd0cd73884229e9" + integrity sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w== + +undici@^7.22.0: + version "7.22.0" + resolved "https://registry.yarnpkg.com/undici/-/undici-7.22.0.tgz#7a82590a5908e504a47d85c60b0f89ca14240e60" + integrity sha512-RqslV2Us5BrllB+JeiZnK4peryVTndy9Dnqq62S3yYRRTj0tFQCwEniUy2167skdGOy3vqRzEvl1Dm4sV2ReDg== + +unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== -typescript@^5.1.6: - version "5.1.6" - resolved "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz" - integrity sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA== +unrs-resolver@^1.7.11: + version "1.11.1" + resolved "https://registry.yarnpkg.com/unrs-resolver/-/unrs-resolver-1.11.1.tgz#be9cd8686c99ef53ecb96df2a473c64d304048a9" + integrity sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg== + dependencies: + napi-postinstall "^0.3.0" + optionalDependencies: + "@unrs/resolver-binding-android-arm-eabi" "1.11.1" + "@unrs/resolver-binding-android-arm64" "1.11.1" + "@unrs/resolver-binding-darwin-arm64" "1.11.1" + "@unrs/resolver-binding-darwin-x64" "1.11.1" + "@unrs/resolver-binding-freebsd-x64" "1.11.1" + "@unrs/resolver-binding-linux-arm-gnueabihf" "1.11.1" + "@unrs/resolver-binding-linux-arm-musleabihf" "1.11.1" + "@unrs/resolver-binding-linux-arm64-gnu" "1.11.1" + "@unrs/resolver-binding-linux-arm64-musl" "1.11.1" + "@unrs/resolver-binding-linux-ppc64-gnu" "1.11.1" + "@unrs/resolver-binding-linux-riscv64-gnu" "1.11.1" + "@unrs/resolver-binding-linux-riscv64-musl" "1.11.1" + "@unrs/resolver-binding-linux-s390x-gnu" "1.11.1" + "@unrs/resolver-binding-linux-x64-gnu" "1.11.1" + "@unrs/resolver-binding-linux-x64-musl" "1.11.1" + "@unrs/resolver-binding-wasm32-wasi" "1.11.1" + "@unrs/resolver-binding-win32-arm64-msvc" "1.11.1" + "@unrs/resolver-binding-win32-ia32-msvc" "1.11.1" + "@unrs/resolver-binding-win32-x64-msvc" "1.11.1" untildify@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz" + resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b" integrity sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw== +update-browserslist-db@^1.2.0: + version "1.2.3" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz#64d76db58713136acbeb4c49114366cc6cc2e80d" + integrity sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w== + dependencies: + escalade "^3.2.0" + picocolors "^1.1.1" + uri-js@^4.2.2: version "4.4.1" - resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== dependencies: punycode "^2.1.0" +utf-8-validate@^6.0.0: + version "6.0.6" + resolved "https://registry.yarnpkg.com/utf-8-validate/-/utf-8-validate-6.0.6.tgz#8a842c9b15af3f6323a3d5ed5eb9e61d208d8c22" + integrity sha512-q3l3P9UtEEiAHcsgsqTgf9PPjctrDWoIXW3NpOHFdRDbLvu4DLIcxHangJ4RLrWkBcKjmcs/6NkerI8T/rE4LA== + dependencies: + node-gyp-build "^4.3.0" + +util-deprecate@^1.0.1, util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +uuid@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-10.0.0.tgz#5a95aa454e6e002725c79055fd42aaba30ca6294" + integrity sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ== + +uuid@^11.0.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-11.1.0.tgz#9549028be1753bb934fc96e2bca09bb4105ae912" + integrity sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A== + +uuid@^8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + +v8-compile-cache-lib@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" + integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== + +v8-to-istanbul@^9.0.1: + version "9.3.0" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz#b9572abfa62bd556c16d75fdebc1a411d5ff3175" + integrity sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA== + dependencies: + "@jridgewell/trace-mapping" "^0.3.12" + "@types/istanbul-lib-coverage" "^2.0.1" + convert-source-map "^2.0.0" + +vary@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== + +walker@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" + integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== + dependencies: + makeerror "1.0.12" + +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== + +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + which@^2.0.1: version "2.0.2" - resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== dependencies: isexe "^2.0.0" -workerpool@6.2.1: - version "6.2.1" - resolved "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz" - integrity sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw== +winston-transport@^4.9.0: + version "4.9.0" + resolved "https://registry.yarnpkg.com/winston-transport/-/winston-transport-4.9.0.tgz#3bba345de10297654ea6f33519424560003b3bf9" + integrity sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A== + dependencies: + logform "^2.7.0" + readable-stream "^3.6.2" + triple-beam "^1.3.0" + +winston@^3.17.0: + version "3.19.0" + resolved "https://registry.yarnpkg.com/winston/-/winston-3.19.0.tgz#cc1d1262f5f45946904085cfffe73efb4b7a581d" + integrity sha512-LZNJgPzfKR+/J3cHkxcpHKpKKvGfDZVPS4hfJCc4cCG0CgYzvlD6yE/S3CIL/Yt91ak327YCpiF/0MyeZHEHKA== + dependencies: + "@colors/colors" "^1.6.0" + "@dabh/diagnostics" "^2.0.8" + async "^3.2.3" + is-stream "^2.0.0" + logform "^2.7.0" + one-time "^1.0.0" + readable-stream "^3.4.0" + safe-stable-stringify "^2.3.1" + stack-trace "0.0.x" + triple-beam "^1.3.0" + winston-transport "^4.9.0" + +word-wrap@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" + integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== + +wordwrap@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q== + +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" wrap-ansi@^7.0.0: version "7.0.0" - resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== dependencies: ansi-styles "^4.0.0" string-width "^4.1.0" strip-ansi "^6.0.0" +wrap-ansi@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" + integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== + dependencies: + ansi-styles "^6.1.0" + string-width "^5.0.1" + strip-ansi "^7.0.1" + +wrap-ansi@^9.0.0: + version "9.0.2" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-9.0.2.tgz#956832dea9494306e6d209eb871643bb873d7c98" + integrity sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww== + dependencies: + ansi-styles "^6.2.1" + string-width "^7.0.0" + strip-ansi "^7.1.0" + wrappy@1: version "1.0.2" - resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== -ws@^7: - version "7.5.9" - resolved "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz" - integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== +write-file-atomic@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-5.0.1.tgz#68df4717c55c6fa4281a7860b4c2ba0a6d2b11e7" + integrity sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw== + dependencies: + imurmurhash "^0.1.4" + signal-exit "^4.0.1" + +ws@8.17.1: + version "8.17.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.1.tgz#9293da530bb548febc95371d90f9c878727d919b" + integrity sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ== + +ws@^7, ws@^7.5.10: + version "7.5.10" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.10.tgz#58b5c20dc281633f6c19113f39b349bd8bd558d9" + integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ== + +ws@^8.5.0: + version "8.19.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.19.0.tgz#ddc2bdfa5b9ad860204f5a72a4863a8895fd8c8b" + integrity sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg== xstream@^11.14.0: version "11.14.0" - resolved "https://registry.npmjs.org/xstream/-/xstream-11.14.0.tgz" + resolved "https://registry.yarnpkg.com/xstream/-/xstream-11.14.0.tgz#2c071d26b18310523b6877e86b4e54df068a9ae5" integrity sha512-1bLb+kKKtKPbgTK6i/BaoAn03g47PpFstlbe1BA+y3pNS/LfvcaghS5BFf9+EE1J+KwSQsEpfJvFN5GqFtiNmw== dependencies: globalthis "^1.0.1" symbol-observable "^2.0.3" +xtend@~4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + y18n@^5.0.5: version "5.0.8" - resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== -yallist@^4.0.0: +yallist@4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== -yargs-parser@20.2.4: - version "20.2.4" - resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz" - integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + +yaml@^2.2.2, yaml@^2.8.2: + version "2.8.2" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.8.2.tgz#5694f25eca0ce9c3e7a9d9e00ce0ddabbd9e35c5" + integrity sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A== yargs-parser@^20.2.2: version "20.2.9" - resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== -yargs-unparser@2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz" - integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== - dependencies: - camelcase "^6.0.0" - decamelize "^4.0.0" - flat "^5.0.2" - is-plain-obj "^2.1.0" +yargs-parser@^21.1.1: + version "21.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== -yargs@16.2.0: +yargs@^16.1.0: version "16.2.0" - resolved "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== dependencies: cliui "^7.0.2" @@ -2277,12 +5688,39 @@ yargs@16.2.0: y18n "^5.0.5" yargs-parser "^20.2.2" +yargs@^17.7.2: + version "17.7.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== + dependencies: + cliui "^8.0.1" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.1.1" + +yn@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" + integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== + yocto-queue@^0.1.0: version "0.1.0" - resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== -zod@^3.21.4: - version "3.22.3" - resolved "https://registry.npmjs.org/zod/-/zod-3.22.3.tgz" - integrity sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug== +zip-stream@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-6.0.1.tgz#e141b930ed60ccaf5d7fa9c8260e0d1748a2bbfb" + integrity sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA== + dependencies: + archiver-utils "^5.0.0" + compress-commons "^6.0.2" + readable-stream "^4.0.0" + +zod@^4.0.14: + version "4.3.6" + resolved "https://registry.yarnpkg.com/zod/-/zod-4.3.6.tgz#89c56e0aa7d2b05107d894412227087885ab112a" + integrity sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg== From a8eb372bef82cc5f09ece80456da148128301a07 Mon Sep 17 00:00:00 2001 From: anupam-io Date: Tue, 10 Mar 2026 14:06:06 +0530 Subject: [PATCH 2/2] fix: set package.json to 2.0.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c616641b..1813de01 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@range-security/range-sdk", - "version": "1.1.6", + "version": "2.0.0", "description": "TypeScript framework for writing blockchain alert rules", "main": "dist/index.js", "types": "dist/index.d.ts",