From 8c42f751a5e32bb737e5bc753e279b6a5419eca8 Mon Sep 17 00:00:00 2001 From: turbocrime Date: Sun, 16 Jun 2024 20:41:30 -0700 Subject: [PATCH 1/4] use packages --- .changeset/silly-lemons-fly.md | 10 + .syncpackrc | 4 +- apps/extension/eslint.config.mjs | 2 +- apps/extension/package.json | 42 +- apps/extension/postcss.config.js | 2 +- apps/extension/src/entry/page-root.tsx | 2 +- apps/extension/src/entry/popup-root.tsx | 2 +- apps/extension/src/hooks/full-sync-height.ts | 13 +- .../src/listeners/message-prax-request.ts | 2 +- apps/extension/src/routes/page/index.tsx | 4 +- .../routes/page/onboarding/confirm-backup.tsx | 10 +- .../page/onboarding/default-frontend.tsx | 4 +- .../src/routes/page/onboarding/generate.tsx | 14 +- .../src/routes/page/onboarding/import.tsx | 10 +- .../page/onboarding/set-grpc-endpoint.tsx | 4 +- .../routes/page/onboarding/set-numeraire.tsx | 4 +- .../routes/page/onboarding/set-password.tsx | 8 +- .../src/routes/page/onboarding/start.tsx | 6 +- .../src/routes/page/onboarding/success.tsx | 4 +- .../restore-password/restore-password.tsx | 8 +- .../page/restore-password/set-password.tsx | 8 +- .../routes/popup/approval/approve-deny.tsx | 2 +- .../src/routes/popup/approval/origin.tsx | 4 +- .../popup/approval/transaction/index.tsx | 4 +- .../popup/approval/transaction/view-tabs.tsx | 4 +- .../src/routes/popup/home/block-sync.tsx | 6 +- .../src/routes/popup/home/frontend-link.tsx | 2 +- .../src/routes/popup/home/index-header.tsx | 4 +- .../extension/src/routes/popup/home/index.tsx | 2 +- .../popup/home/validate-address/index.tsx | 4 +- apps/extension/src/routes/popup/login.tsx | 6 +- .../popup/settings/settings-auto-lock.tsx | 4 +- .../popup/settings/settings-clear-cache.tsx | 2 +- .../settings-connected-sites/index.tsx | 2 +- .../settings-connected-sites/known-site.tsx | 2 +- .../settings/settings-full-viewing-key.tsx | 4 +- .../popup/settings/settings-passphrase.tsx | 4 +- .../popup/settings/settings-screen/index.tsx | 2 +- .../settings-screen/settings-header.tsx | 2 +- .../popup/settings/settings-spend-key.tsx | 4 +- apps/extension/src/rpc/rethrow-impl-errors.ts | 6 +- .../default-frontend-form/index.tsx | 4 +- .../new-frontend-input.tsx | 4 +- .../grpc-endpoint-form/chain-id-or-error.tsx | 2 +- .../confirm-changed-chain-id-dialog.tsx | 4 +- .../components/grpc-endpoint-form/index.tsx | 4 +- apps/extension/src/shared/components/link.tsx | 2 +- .../src/shared/components/numeraires-form.tsx | 4 +- .../src/shared/components/password-input.tsx | 4 +- .../src/shared/containers/import-form.tsx | 4 +- .../shared/containers/word-length-toogles.tsx | 2 +- apps/extension/src/state/tx-approval.ts | 2 +- apps/extension/src/utils/tests-setup.js | 3 - apps/extension/src/wallet-services.ts | 2 +- apps/extension/tailwind.config.js | 2 +- apps/extension/tsconfig.json | 8 +- apps/extension/vitest.config.ts | 8 +- apps/extension/webpack.config.ts | 8 + apps/prax-marketing-site/eslint.config.mjs | 2 +- apps/prax-marketing-site/package.json | 5 +- apps/prax-marketing-site/tailwind.config.js | 2 +- apps/prax-marketing-site/tsconfig.json | 2 +- package.json | 54 +- packages/bech32m/.npmignore | 3 - packages/bech32m/CHANGELOG.md | 49 - packages/bech32m/README.md | 113 - packages/bech32m/eslint.config.mjs | 13 - packages/bech32m/package.json | 42 - packages/bech32m/src/format/bytes.ts | 14 - packages/bech32m/src/format/convert.ts | 143 - packages/bech32m/src/format/index.ts | 76 - packages/bech32m/src/format/inner.test.ts | 54 - packages/bech32m/src/format/inner.ts | 14 - packages/bech32m/src/format/lengths.test.ts | 21 - packages/bech32m/src/format/prefix.ts | 14 - packages/bech32m/src/format/strings.ts | 14 - packages/bech32m/src/index.ts | 30 - packages/bech32m/src/passet.ts | 24 - packages/bech32m/src/pauctid.ts | 24 - packages/bech32m/src/penumbra.ts | 24 - packages/bech32m/src/penumbracompat1.ts | 15 - .../bech32m/src/penumbrafullviewingkey.ts | 26 - packages/bech32m/src/penumbragovern.ts | 24 - packages/bech32m/src/penumbraspendkey.ts | 24 - packages/bech32m/src/penumbravalid.ts | 24 - packages/bech32m/src/penumbrawalletid.ts | 24 - packages/bech32m/src/plpid.ts | 24 - packages/bech32m/src/test/passet.test.ts | 22 - packages/bech32m/src/test/penumbra.test.ts | 25 - .../bech32m/src/test/penumbracompat1.test.ts | 25 - .../src/test/penumbrafullviewingkey.test.ts | 24 - .../bech32m/src/test/penumbraspendkey.test.ts | 22 - .../bech32m/src/test/penumbravalid.test.ts | 22 - .../bech32m/src/test/penumbrawalletid.test.ts | 22 - packages/bech32m/src/test/plpid.test.ts | 22 - packages/bech32m/src/test/util/corrupt.ts | 36 - .../bech32m/src/test/util/generate-tests.ts | 37 - packages/bech32m/tsconfig.json | 9 - packages/client/CHANGELOG.md | 121 - packages/client/eslint.config.mjs | 13 - packages/client/package.json | 45 - packages/client/src/error.ts | 43 - packages/client/src/index.ts | 16 - packages/client/src/prax.ts | 66 - packages/client/tsconfig.json | 9 - .../CHANGELOG.md | 0 .../{getters => context}/eslint.config.mjs | 2 +- packages/context/package.json | 33 + .../src/index.ts | 0 packages/{query => context}/tsconfig.json | 2 +- packages/crypto/CHANGELOG.md | 97 - packages/crypto/eslint.config.mjs | 13 - packages/crypto/package.json | 29 - packages/crypto/src/encryption.test.ts | 173 - packages/crypto/src/encryption.ts | 162 - packages/crypto/src/mnemonic.test.ts | 189 - packages/crypto/src/mnemonic.ts | 34 - packages/crypto/src/sha256.test.ts | 26 - packages/crypto/src/sha256.ts | 12 - packages/crypto/tsconfig.json | 5 - packages/eslint-config/eslint.config.mjs | 2 +- packages/eslint-config/package.json | 2 +- packages/getters/CHANGELOG.md | 118 - packages/getters/README.md | 108 - packages/getters/package.json | 39 - packages/getters/src/address-view.ts | 10 - packages/getters/src/assets-response.ts | 6 - packages/getters/src/balances-response.ts | 31 - .../getters/src/batch-swap-output-data.ts | 14 - packages/getters/src/bonding-state.ts | 6 - .../delegations-by-address-index-response.ts | 7 - .../getters/src/dutch-auction-description.ts | 10 - packages/getters/src/dutch-auction.ts | 14 - packages/getters/src/equivalent-value.ts | 19 - packages/getters/src/fee.ts | 4 - packages/getters/src/funding-stream.ts | 6 - .../src/get-validator-info-response.ts | 6 - packages/getters/src/metadata.test.ts | 27 - packages/getters/src/metadata.ts | 26 - packages/getters/src/note-view.ts | 5 - packages/getters/src/output-view.ts | 6 - packages/getters/src/rate-data.ts | 10 - packages/getters/src/spend-view.ts | 6 - packages/getters/src/spendable-note-record.ts | 10 - packages/getters/src/swap-claim-view.ts | 24 - packages/getters/src/swap-record.ts | 8 - packages/getters/src/swap-view.ts | 102 - packages/getters/src/swap.ts | 4 - packages/getters/src/trading-pair.ts | 5 - packages/getters/src/transaction.ts | 13 - ...onding-tokens-by-address-index-response.ts | 7 - .../getters/src/unclaimed-swaps-response.ts | 6 - packages/getters/src/undelegate-claim-body.ts | 6 - packages/getters/src/undelegate-claim.ts | 20 - .../getters/src/utils/create-getter.test.ts | 88 - packages/getters/src/utils/create-getter.ts | 34 - .../src/utils/getter-missing-value-error.ts | 9 - packages/getters/src/utils/getter.ts | 56 - .../getters/src/validator-info-response.ts | 16 - packages/getters/src/validator-info.ts | 32 - packages/getters/src/validator-state.ts | 6 - packages/getters/src/validator-status.ts | 12 - packages/getters/src/validator.ts | 6 - packages/getters/src/value-view.ts | 86 - packages/getters/src/value.ts | 6 - packages/getters/tsconfig.json | 8 - packages/getters/vite.config.ts | 35 - packages/keys/CHANGELOG.md | 29 - packages/keys/README.md | 89 - packages/keys/action-keys.json | 8 - packages/keys/download-keys | 90 - packages/keys/package.json | 23 - packages/keys/shasums/v0.73.0.shasum | 7 - packages/keys/shasums/v0.76.0.shasum | 7 - packages/keys/shasums/v0.77.0.shasum | 7 - packages/perspective/CHANGELOG.md | 161 - packages/perspective/eslint.config.mjs | 13 - packages/perspective/package.json | 45 - .../perspective/plan/get-address-view.test.ts | 66 - packages/perspective/plan/get-address-view.ts | 31 - packages/perspective/plan/index.test.ts | 112 - packages/perspective/plan/index.ts | 53 - .../perspective/plan/view-action-plan.test.ts | 633 --- packages/perspective/plan/view-action-plan.ts | 338 -- .../perspective/transaction/classification.ts | 29 - .../perspective/transaction/classify.test.ts | 388 -- packages/perspective/transaction/classify.ts | 100 - packages/perspective/translators/README.md | 25 - .../translators/action-view.test.ts | 402 -- .../perspective/translators/action-view.ts | 68 - .../translators/address-view.test.ts | 67 - .../perspective/translators/address-view.ts | 15 - .../perspective/translators/memo-view.test.ts | 143 - packages/perspective/translators/memo-view.ts | 41 - .../translators/output-view.test.ts | 193 - .../perspective/translators/output-view.ts | 39 - .../translators/spend-view.test.ts | 93 - .../perspective/translators/spend-view.ts | 15 - .../translators/swap-claim-view.ts | 20 - packages/perspective/translators/swap-view.ts | 25 - .../translators/transaction-view.ts | 43 - packages/perspective/translators/types.ts | 16 - packages/perspective/tsconfig.json | 8 - packages/perspective/vite.config.ts | 24 - packages/perspective/vitest.config.ts | 6 - packages/polyfills/CHANGELOG.md | 26 - packages/polyfills/eslint.config.mjs | 13 - packages/polyfills/package.json | 18 - .../polyfills/src/Array.fromAsync.test.ts | 72 - packages/polyfills/src/Array.fromAsync.ts | 17 - .../polyfills/src/ReadableStream.from.test.ts | 114 - packages/polyfills/src/ReadableStream.from.ts | 40 - ...adableStream_Symbol.asyncIterator_.test.ts | 74 - .../ReadableStream_Symbol.asyncIterator_.ts | 26 - packages/polyfills/src/array-from-async.d.ts | 1 - .../polyfills/src/streamToPromise.test.ts | 52 - packages/polyfills/tsconfig.json | 8 - packages/protobuf/CHANGELOG.md | 53 - packages/protobuf/README.md | 44 - packages/protobuf/eslint.config.mjs | 13 - packages/protobuf/package.json | 36 - packages/protobuf/src/ibc-core.ts | 3 - packages/protobuf/src/index.ts | 8 - packages/protobuf/src/penumbra-cnidarium.ts | 1 - packages/protobuf/src/penumbra-core.ts | 12 - packages/protobuf/src/penumbra-proxy.ts | 1 - packages/protobuf/src/penumbra.ts | 2 - packages/protobuf/src/registry.ts | 66 - packages/protobuf/src/web.ts | 16 - packages/protobuf/tsconfig.json | 8 - packages/query/CHANGELOG.md | 214 - packages/query/eslint.config.mjs | 13 - packages/query/package.json | 37 - packages/query/src/block-processor.ts | 607 --- .../process-action-dutch-auction-end.test.ts | 114 - .../process-action-dutch-auction-end.ts | 45 - .../process-action-dutch-auction-schedule.ts | 23 - .../process-action-dutch-auction-withdraw.ts | 19 - packages/query/src/price-indexer.test.ts | 115 - packages/query/src/price-indexer.ts | 97 - packages/query/src/queriers/app.ts | 31 - packages/query/src/queriers/auction.ts | 31 - packages/query/src/queriers/cnidarium.ts | 24 - packages/query/src/queriers/compact-block.ts | 32 - packages/query/src/queriers/ibc-client.ts | 20 - packages/query/src/queriers/shielded-pool.ts | 26 - packages/query/src/queriers/staking.ts | 30 - packages/query/src/queriers/tendermint.ts | 43 - packages/query/src/queriers/utils.ts | 13 - packages/query/src/root-querier.ts | 33 - packages/services-context/eslint.config.mjs | 13 - packages/services-context/package.json | 33 - packages/services-context/tsconfig.json | 5 - packages/services/CHANGELOG.md | 294 -- packages/services/eslint.config.mjs | 13 - packages/services/package.json | 45 - packages/services/src/ctx/approver.ts | 11 - packages/services/src/ctx/custody-client.ts | 5 - packages/services/src/ctx/full-viewing-key.ts | 6 - packages/services/src/ctx/prax.ts | 11 - packages/services/src/ctx/spend-key.ts | 6 - packages/services/src/ctx/stake-client.ts | 5 - packages/services/src/ctx/wallet-id.ts | 6 - .../src/custody-service/authorize.test.ts | 249 - .../services/src/custody-service/authorize.ts | 24 - .../services/src/custody-service/index.ts | 15 - ...m-addresses-belong-to-current-user.test.ts | 123 - ...-claim-addresses-belong-to-current-user.ts | 19 - .../custody-service/validation/authorize.ts | 25 - packages/services/src/offscreen-client.ts | 97 - .../src/sct-service/epoch-by-height.test.ts | 52 - .../src/sct-service/epoch-by-height.ts | 14 - packages/services/src/sct-service/index.ts | 9 - .../stake-service/get-validator-info.test.ts | 71 - .../src/stake-service/get-validator-info.ts | 18 - packages/services/src/stake-service/index.ts | 14 - .../src/stake-service/validator-info.test.ts | 88 - .../src/stake-service/validator-info.ts | 22 - .../stake-service/validator-penalty.test.ts | 55 - .../src/stake-service/validator-penalty.ts | 8 - packages/services/src/test-utils.ts | 91 - .../src/view-service/address-by-index.test.ts | 49 - .../src/view-service/address-by-index.ts | 10 - .../src/view-service/app-parameters.test.ts | 110 - .../src/view-service/app-parameters.ts | 16 - .../view-service/asset-metadata-by-id.test.ts | 126 - .../src/view-service/asset-metadata-by-id.ts | 29 - .../services/src/view-service/assets.test.ts | 290 -- packages/services/src/view-service/assets.ts | 53 - .../src/view-service/auctions.test.ts | 251 - .../services/src/view-service/auctions.ts | 93 - .../src/view-service/authorize-and-build.ts | 28 - .../src/view-service/balances.test.ts | 410 -- .../services/src/view-service/balances.ts | 229 - .../broadcast-transaction.test.ts | 478 -- .../src/view-service/broadcast-transaction.ts | 52 - .../delegations-by-address-index.test.ts | 351 -- .../delegations-by-address-index.ts | 116 - .../view-service/ephemeral-address.test.ts | 72 - .../src/view-service/ephemeral-address.ts | 14 - .../src/view-service/fmd-parameters.test.ts | 56 - .../src/view-service/fmd-parameters.ts | 12 - .../src/view-service/gas-prices.test.ts | 63 - .../services/src/view-service/gas-prices.ts | 32 - .../src/view-service/index-by-address.test.ts | 65 - .../src/view-service/index-by-address.ts | 16 - packages/services/src/view-service/index.ts | 65 - .../view-service/note-by-commitment.test.ts | 143 - .../src/view-service/note-by-commitment.ts | 25 - .../src/view-service/notes-for-voting.test.ts | 73 - .../src/view-service/notes-for-voting.ts | 10 - .../services/src/view-service/notes.test.ts | 495 -- packages/services/src/view-service/notes.ts | 30 - .../src/view-service/nullifier-status.test.ts | 253 - .../src/view-service/nullifier-status.ts | 58 - .../view-service/owned-position-ids.test.ts | 82 - .../src/view-service/owned-position-ids.ts | 15 - .../src/view-service/status-stream.test.ts | 92 - .../src/view-service/status-stream.ts | 20 - .../services/src/view-service/status.test.ts | 68 - packages/services/src/view-service/status.ts | 15 - .../view-service/swap-by-commitment.test.ts | 147 - .../src/view-service/swap-by-commitment.ts | 26 - .../transaction-info-by-hash.test.ts | 257 - .../view-service/transaction-info-by-hash.ts | 29 - .../src/view-service/transaction-info.test.ts | 141 - .../src/view-service/transaction-info.ts | 36 - ...ssert-swap-assets-are-not-the-same.test.ts | 62 - .../assert-swap-assets-are-not-the-same.ts | 19 - .../transaction-planner/index.test.ts | 123 - .../view-service/transaction-planner/index.ts | 48 - .../helpers.test.ts | 95 - .../helpers.ts | 52 - .../index.test.ts | 201 - .../index.ts | 72 - .../src/view-service/unclaimed-swaps.test.ts | 86 - .../src/view-service/unclaimed-swaps.ts | 13 - .../src/view-service/util/build-tx.ts | 75 - .../view-service/util/custody-authorize.ts | 18 - .../services/src/view-service/wallet-id.ts | 7 - .../src/view-service/witness-and-build.ts | 32 - .../services/src/view-service/witness.test.ts | 173 - packages/services/src/view-service/witness.ts | 19 - packages/services/tests-setup.js | 24 - packages/services/tsconfig.json | 5 - packages/services/vitest.config.ts | 9 - packages/storage/CHANGELOG.md | 177 - packages/storage/eslint.config.mjs | 13 - packages/storage/package.json | 40 - packages/storage/src/indexed-db/index.ts | 827 ---- .../src/indexed-db/indexed-db.test-data.ts | 718 --- .../storage/src/indexed-db/indexed-db.test.ts | 799 --- packages/storage/src/indexed-db/stream.ts | 24 - packages/storage/src/indexed-db/updater.ts | 74 - packages/storage/tsconfig.json | 5 - packages/storage/vitest.config.ts | 16 - packages/tailwind-config/package.json | 4 +- .../resolved-tailwind-config.ts | 2 +- packages/transport-chrome/CHANGELOG.md | 64 - packages/transport-chrome/eslint.config.mjs | 13 - packages/transport-chrome/package.json | 34 - .../src/channel-names.test.ts | 27 - .../transport-chrome/src/channel-names.ts | 62 - packages/transport-chrome/src/message.ts | 8 - .../transport-chrome/src/session-client.ts | 107 - .../transport-chrome/src/session-manager.ts | 178 - packages/transport-chrome/src/stream.ts | 93 - packages/transport-chrome/tsconfig.json | 5 - packages/transport-dom/CHANGELOG.md | 43 - packages/transport-dom/eslint.config.mjs | 13 - packages/transport-dom/package.json | 40 - packages/transport-dom/src/adapter.ts | 210 - packages/transport-dom/src/any-impl.ts | 19 - packages/transport-dom/src/create.test.ts | 207 - packages/transport-dom/src/create.ts | 213 - packages/transport-dom/src/direct.ts | 76 - packages/transport-dom/src/messages.ts | 51 - packages/transport-dom/src/proxy.ts | 81 - packages/transport-dom/src/stream.test.ts | 174 - packages/transport-dom/src/stream.ts | 35 - packages/transport-dom/tsconfig.json | 8 - packages/transport-dom/vite.config.ts | 32 - packages/tsconfig/package.json | 2 +- packages/types/CHANGELOG.md | 144 - packages/types/eslint.config.mjs | 13 - packages/types/package.json | 43 - packages/types/src/amount.test.ts | 299 -- packages/types/src/amount.ts | 130 - packages/types/src/assets.test.ts | 177 - packages/types/src/assets.ts | 105 - packages/types/src/base64.test.ts | 86 - packages/types/src/base64.ts | 28 - packages/types/src/block-processor.ts | 7 - packages/types/src/box.ts | 26 - packages/types/src/environment.ts | 55 - packages/types/src/hex.test.ts | 89 - packages/types/src/hex.ts | 57 - packages/types/src/indexed-db.ts | 311 -- .../types/src/internal-msg/chrome-error.ts | 7 - packages/types/src/internal-msg/offscreen.ts | 49 - packages/types/src/internal-msg/shared.ts | 22 - packages/types/src/jsonified.ts | 60 - packages/types/src/lo-hi.test.ts | 207 - packages/types/src/lo-hi.ts | 90 - packages/types/src/protobuf.test.ts | 20 - packages/types/src/protobuf.ts | 10 - packages/types/src/querier.ts | 76 - packages/types/src/servers.ts | 10 - packages/types/src/services.ts | 15 - packages/types/src/staking.test.ts | 94 - packages/types/src/staking.ts | 94 - packages/types/src/state-commitment-tree.ts | 71 - packages/types/src/string.test.ts | 88 - packages/types/src/string.ts | 17 - packages/types/src/swap.test.ts | 327 -- packages/types/src/swap.ts | 106 - packages/types/src/user-choice.ts | 5 - packages/types/src/utility.ts | 8 - packages/types/src/validation.test.ts | 117 - packages/types/src/validation.ts | 45 - packages/types/src/value-view.test.ts | 77 - packages/types/src/value-view.ts | 22 - packages/types/src/wallet.ts | 55 - packages/types/tsconfig.json | 8 - packages/types/vite.config.ts | 36 - packages/ui/components.json | 2 +- .../ui/block-sync-status/condensed.tsx | 79 +- .../components/ui/block-sync-status/hooks.ts | 13 +- .../components/ui/block-sync-status/shared.ts | 10 - packages/ui/components/ui/box.tsx | 2 +- packages/ui/components/ui/navigation-menu.tsx | 114 - packages/ui/components/ui/network.tsx | 6 +- packages/ui/components/ui/progress.tsx | 4 +- packages/ui/eslint.config.mjs | 2 +- packages/ui/package.json | 20 +- packages/ui/tailwind.config.js | 2 +- packages/ui/tsconfig.json | 2 +- packages/wasm/.gitignore | 3 - packages/wasm/.npmignore | 1 - packages/wasm/CHANGELOG.md | 139 - packages/wasm/README.md | 130 - packages/wasm/crate/Cargo.lock | 4263 ----------------- packages/wasm/crate/Cargo.toml | 53 - packages/wasm/crate/src/asset.rs | 19 - packages/wasm/crate/src/auction.rs | 70 - packages/wasm/crate/src/build.rs | 37 - packages/wasm/crate/src/dex.rs | 34 - packages/wasm/crate/src/error.rs | 81 - packages/wasm/crate/src/keys.rs | 127 - packages/wasm/crate/src/lib.rs | 21 - packages/wasm/crate/src/metadata.rs | 244 - packages/wasm/crate/src/note_record.rs | 77 - packages/wasm/crate/src/planner.rs | 534 --- packages/wasm/crate/src/storage.rs | 397 -- packages/wasm/crate/src/swap_record.rs | 70 - packages/wasm/crate/src/tree.rs | 18 - packages/wasm/crate/src/tx.rs | 424 -- packages/wasm/crate/src/utils.rs | 10 - packages/wasm/crate/src/view_server.rs | 316 -- packages/wasm/crate/tests/build.rs | 571 --- packages/wasm/crate/tests/deserialize.rs | 35 - packages/wasm/crate/tests/keys.rs | 34 - packages/wasm/eslint.config.mjs | 13 - packages/wasm/package.json | 54 - packages/wasm/src/address.test.ts | 54 - packages/wasm/src/address.ts | 26 - packages/wasm/src/asset.test.ts | 52 - packages/wasm/src/asset.ts | 12 - packages/wasm/src/auction.ts | 16 - packages/wasm/src/build.ts | 68 - packages/wasm/src/dex.ts | 20 - packages/wasm/src/keys.test.ts | 64 - packages/wasm/src/keys.ts | 32 - packages/wasm/src/metadata.ts | 9 - packages/wasm/src/planner.ts | 19 - packages/wasm/src/transaction.ts | 25 - packages/wasm/src/tree.ts | 9 - packages/wasm/src/view-server.test.ts | 36 - packages/wasm/src/view-server.ts | 92 - packages/wasm/tsconfig.json | 9 - packages/wasm/vitest.config.ts | 6 - packages/wasm/wasm/.npmignore | 0 packages/zquery/CHANGELOG.md | 7 - packages/zquery/eslint.config.mjs | 13 - packages/zquery/package.json | 15 - packages/zquery/src/index.test.ts | 56 - packages/zquery/src/index.ts | 261 - packages/zquery/src/types.ts | 190 - packages/zquery/tsconfig.json | 5 - pnpm-lock.yaml | 3350 ++++++------- 490 files changed, 1889 insertions(+), 35467 deletions(-) create mode 100644 .changeset/silly-lemons-fly.md delete mode 100644 packages/bech32m/.npmignore delete mode 100644 packages/bech32m/CHANGELOG.md delete mode 100644 packages/bech32m/README.md delete mode 100644 packages/bech32m/eslint.config.mjs delete mode 100644 packages/bech32m/package.json delete mode 100644 packages/bech32m/src/format/bytes.ts delete mode 100644 packages/bech32m/src/format/convert.ts delete mode 100644 packages/bech32m/src/format/index.ts delete mode 100644 packages/bech32m/src/format/inner.test.ts delete mode 100644 packages/bech32m/src/format/inner.ts delete mode 100644 packages/bech32m/src/format/lengths.test.ts delete mode 100644 packages/bech32m/src/format/prefix.ts delete mode 100644 packages/bech32m/src/format/strings.ts delete mode 100644 packages/bech32m/src/index.ts delete mode 100644 packages/bech32m/src/passet.ts delete mode 100644 packages/bech32m/src/pauctid.ts delete mode 100644 packages/bech32m/src/penumbra.ts delete mode 100644 packages/bech32m/src/penumbracompat1.ts delete mode 100644 packages/bech32m/src/penumbrafullviewingkey.ts delete mode 100644 packages/bech32m/src/penumbragovern.ts delete mode 100644 packages/bech32m/src/penumbraspendkey.ts delete mode 100644 packages/bech32m/src/penumbravalid.ts delete mode 100644 packages/bech32m/src/penumbrawalletid.ts delete mode 100644 packages/bech32m/src/plpid.ts delete mode 100644 packages/bech32m/src/test/passet.test.ts delete mode 100644 packages/bech32m/src/test/penumbra.test.ts delete mode 100644 packages/bech32m/src/test/penumbracompat1.test.ts delete mode 100644 packages/bech32m/src/test/penumbrafullviewingkey.test.ts delete mode 100644 packages/bech32m/src/test/penumbraspendkey.test.ts delete mode 100644 packages/bech32m/src/test/penumbravalid.test.ts delete mode 100644 packages/bech32m/src/test/penumbrawalletid.test.ts delete mode 100644 packages/bech32m/src/test/plpid.test.ts delete mode 100644 packages/bech32m/src/test/util/corrupt.ts delete mode 100644 packages/bech32m/src/test/util/generate-tests.ts delete mode 100644 packages/bech32m/tsconfig.json delete mode 100644 packages/client/CHANGELOG.md delete mode 100644 packages/client/eslint.config.mjs delete mode 100644 packages/client/package.json delete mode 100644 packages/client/src/error.ts delete mode 100644 packages/client/src/index.ts delete mode 100644 packages/client/src/prax.ts delete mode 100644 packages/client/tsconfig.json rename packages/{services-context => context}/CHANGELOG.md (100%) rename packages/{getters => context}/eslint.config.mjs (77%) create mode 100644 packages/context/package.json rename packages/{services-context => context}/src/index.ts (100%) rename packages/{query => context}/tsconfig.json (56%) delete mode 100644 packages/crypto/CHANGELOG.md delete mode 100644 packages/crypto/eslint.config.mjs delete mode 100644 packages/crypto/package.json delete mode 100644 packages/crypto/src/encryption.test.ts delete mode 100644 packages/crypto/src/encryption.ts delete mode 100644 packages/crypto/src/mnemonic.test.ts delete mode 100644 packages/crypto/src/mnemonic.ts delete mode 100644 packages/crypto/src/sha256.test.ts delete mode 100644 packages/crypto/src/sha256.ts delete mode 100644 packages/crypto/tsconfig.json delete mode 100644 packages/getters/CHANGELOG.md delete mode 100644 packages/getters/README.md delete mode 100644 packages/getters/package.json delete mode 100644 packages/getters/src/address-view.ts delete mode 100644 packages/getters/src/assets-response.ts delete mode 100644 packages/getters/src/balances-response.ts delete mode 100644 packages/getters/src/batch-swap-output-data.ts delete mode 100644 packages/getters/src/bonding-state.ts delete mode 100644 packages/getters/src/delegations-by-address-index-response.ts delete mode 100644 packages/getters/src/dutch-auction-description.ts delete mode 100644 packages/getters/src/dutch-auction.ts delete mode 100644 packages/getters/src/equivalent-value.ts delete mode 100644 packages/getters/src/fee.ts delete mode 100644 packages/getters/src/funding-stream.ts delete mode 100644 packages/getters/src/get-validator-info-response.ts delete mode 100644 packages/getters/src/metadata.test.ts delete mode 100644 packages/getters/src/metadata.ts delete mode 100644 packages/getters/src/note-view.ts delete mode 100644 packages/getters/src/output-view.ts delete mode 100644 packages/getters/src/rate-data.ts delete mode 100644 packages/getters/src/spend-view.ts delete mode 100644 packages/getters/src/spendable-note-record.ts delete mode 100644 packages/getters/src/swap-claim-view.ts delete mode 100644 packages/getters/src/swap-record.ts delete mode 100644 packages/getters/src/swap-view.ts delete mode 100644 packages/getters/src/swap.ts delete mode 100644 packages/getters/src/trading-pair.ts delete mode 100644 packages/getters/src/transaction.ts delete mode 100644 packages/getters/src/unbonding-tokens-by-address-index-response.ts delete mode 100644 packages/getters/src/unclaimed-swaps-response.ts delete mode 100644 packages/getters/src/undelegate-claim-body.ts delete mode 100644 packages/getters/src/undelegate-claim.ts delete mode 100644 packages/getters/src/utils/create-getter.test.ts delete mode 100644 packages/getters/src/utils/create-getter.ts delete mode 100644 packages/getters/src/utils/getter-missing-value-error.ts delete mode 100644 packages/getters/src/utils/getter.ts delete mode 100644 packages/getters/src/validator-info-response.ts delete mode 100644 packages/getters/src/validator-info.ts delete mode 100644 packages/getters/src/validator-state.ts delete mode 100644 packages/getters/src/validator-status.ts delete mode 100644 packages/getters/src/validator.ts delete mode 100644 packages/getters/src/value-view.ts delete mode 100644 packages/getters/src/value.ts delete mode 100644 packages/getters/tsconfig.json delete mode 100644 packages/getters/vite.config.ts delete mode 100644 packages/keys/CHANGELOG.md delete mode 100644 packages/keys/README.md delete mode 100644 packages/keys/action-keys.json delete mode 100755 packages/keys/download-keys delete mode 100644 packages/keys/package.json delete mode 100644 packages/keys/shasums/v0.73.0.shasum delete mode 100644 packages/keys/shasums/v0.76.0.shasum delete mode 100644 packages/keys/shasums/v0.77.0.shasum delete mode 100644 packages/perspective/CHANGELOG.md delete mode 100644 packages/perspective/eslint.config.mjs delete mode 100644 packages/perspective/package.json delete mode 100644 packages/perspective/plan/get-address-view.test.ts delete mode 100644 packages/perspective/plan/get-address-view.ts delete mode 100644 packages/perspective/plan/index.test.ts delete mode 100644 packages/perspective/plan/index.ts delete mode 100644 packages/perspective/plan/view-action-plan.test.ts delete mode 100644 packages/perspective/plan/view-action-plan.ts delete mode 100644 packages/perspective/transaction/classification.ts delete mode 100644 packages/perspective/transaction/classify.test.ts delete mode 100644 packages/perspective/transaction/classify.ts delete mode 100644 packages/perspective/translators/README.md delete mode 100644 packages/perspective/translators/action-view.test.ts delete mode 100644 packages/perspective/translators/action-view.ts delete mode 100644 packages/perspective/translators/address-view.test.ts delete mode 100644 packages/perspective/translators/address-view.ts delete mode 100644 packages/perspective/translators/memo-view.test.ts delete mode 100644 packages/perspective/translators/memo-view.ts delete mode 100644 packages/perspective/translators/output-view.test.ts delete mode 100644 packages/perspective/translators/output-view.ts delete mode 100644 packages/perspective/translators/spend-view.test.ts delete mode 100644 packages/perspective/translators/spend-view.ts delete mode 100644 packages/perspective/translators/swap-claim-view.ts delete mode 100644 packages/perspective/translators/swap-view.ts delete mode 100644 packages/perspective/translators/transaction-view.ts delete mode 100644 packages/perspective/translators/types.ts delete mode 100644 packages/perspective/tsconfig.json delete mode 100644 packages/perspective/vite.config.ts delete mode 100644 packages/perspective/vitest.config.ts delete mode 100644 packages/polyfills/CHANGELOG.md delete mode 100644 packages/polyfills/eslint.config.mjs delete mode 100644 packages/polyfills/package.json delete mode 100644 packages/polyfills/src/Array.fromAsync.test.ts delete mode 100644 packages/polyfills/src/Array.fromAsync.ts delete mode 100644 packages/polyfills/src/ReadableStream.from.test.ts delete mode 100644 packages/polyfills/src/ReadableStream.from.ts delete mode 100644 packages/polyfills/src/ReadableStream_Symbol.asyncIterator_.test.ts delete mode 100644 packages/polyfills/src/ReadableStream_Symbol.asyncIterator_.ts delete mode 100644 packages/polyfills/src/array-from-async.d.ts delete mode 100644 packages/polyfills/src/streamToPromise.test.ts delete mode 100644 packages/polyfills/tsconfig.json delete mode 100644 packages/protobuf/CHANGELOG.md delete mode 100644 packages/protobuf/README.md delete mode 100644 packages/protobuf/eslint.config.mjs delete mode 100644 packages/protobuf/package.json delete mode 100644 packages/protobuf/src/ibc-core.ts delete mode 100644 packages/protobuf/src/index.ts delete mode 100644 packages/protobuf/src/penumbra-cnidarium.ts delete mode 100644 packages/protobuf/src/penumbra-core.ts delete mode 100644 packages/protobuf/src/penumbra-proxy.ts delete mode 100644 packages/protobuf/src/penumbra.ts delete mode 100644 packages/protobuf/src/registry.ts delete mode 100644 packages/protobuf/src/web.ts delete mode 100644 packages/protobuf/tsconfig.json delete mode 100644 packages/query/CHANGELOG.md delete mode 100644 packages/query/eslint.config.mjs delete mode 100644 packages/query/package.json delete mode 100644 packages/query/src/block-processor.ts delete mode 100644 packages/query/src/helpers/process-action-dutch-auction-end.test.ts delete mode 100644 packages/query/src/helpers/process-action-dutch-auction-end.ts delete mode 100644 packages/query/src/helpers/process-action-dutch-auction-schedule.ts delete mode 100644 packages/query/src/helpers/process-action-dutch-auction-withdraw.ts delete mode 100644 packages/query/src/price-indexer.test.ts delete mode 100644 packages/query/src/price-indexer.ts delete mode 100644 packages/query/src/queriers/app.ts delete mode 100644 packages/query/src/queriers/auction.ts delete mode 100644 packages/query/src/queriers/cnidarium.ts delete mode 100644 packages/query/src/queriers/compact-block.ts delete mode 100644 packages/query/src/queriers/ibc-client.ts delete mode 100644 packages/query/src/queriers/shielded-pool.ts delete mode 100644 packages/query/src/queriers/staking.ts delete mode 100644 packages/query/src/queriers/tendermint.ts delete mode 100644 packages/query/src/queriers/utils.ts delete mode 100644 packages/query/src/root-querier.ts delete mode 100644 packages/services-context/eslint.config.mjs delete mode 100644 packages/services-context/package.json delete mode 100644 packages/services-context/tsconfig.json delete mode 100644 packages/services/CHANGELOG.md delete mode 100644 packages/services/eslint.config.mjs delete mode 100644 packages/services/package.json delete mode 100644 packages/services/src/ctx/approver.ts delete mode 100644 packages/services/src/ctx/custody-client.ts delete mode 100644 packages/services/src/ctx/full-viewing-key.ts delete mode 100644 packages/services/src/ctx/prax.ts delete mode 100644 packages/services/src/ctx/spend-key.ts delete mode 100644 packages/services/src/ctx/stake-client.ts delete mode 100644 packages/services/src/ctx/wallet-id.ts delete mode 100644 packages/services/src/custody-service/authorize.test.ts delete mode 100644 packages/services/src/custody-service/authorize.ts delete mode 100644 packages/services/src/custody-service/index.ts delete mode 100644 packages/services/src/custody-service/validation/assert-swap-claim-addresses-belong-to-current-user.test.ts delete mode 100644 packages/services/src/custody-service/validation/assert-swap-claim-addresses-belong-to-current-user.ts delete mode 100644 packages/services/src/custody-service/validation/authorize.ts delete mode 100644 packages/services/src/offscreen-client.ts delete mode 100644 packages/services/src/sct-service/epoch-by-height.test.ts delete mode 100644 packages/services/src/sct-service/epoch-by-height.ts delete mode 100644 packages/services/src/sct-service/index.ts delete mode 100644 packages/services/src/stake-service/get-validator-info.test.ts delete mode 100644 packages/services/src/stake-service/get-validator-info.ts delete mode 100644 packages/services/src/stake-service/index.ts delete mode 100644 packages/services/src/stake-service/validator-info.test.ts delete mode 100644 packages/services/src/stake-service/validator-info.ts delete mode 100644 packages/services/src/stake-service/validator-penalty.test.ts delete mode 100644 packages/services/src/stake-service/validator-penalty.ts delete mode 100644 packages/services/src/test-utils.ts delete mode 100644 packages/services/src/view-service/address-by-index.test.ts delete mode 100644 packages/services/src/view-service/address-by-index.ts delete mode 100644 packages/services/src/view-service/app-parameters.test.ts delete mode 100644 packages/services/src/view-service/app-parameters.ts delete mode 100644 packages/services/src/view-service/asset-metadata-by-id.test.ts delete mode 100644 packages/services/src/view-service/asset-metadata-by-id.ts delete mode 100644 packages/services/src/view-service/assets.test.ts delete mode 100644 packages/services/src/view-service/assets.ts delete mode 100644 packages/services/src/view-service/auctions.test.ts delete mode 100644 packages/services/src/view-service/auctions.ts delete mode 100644 packages/services/src/view-service/authorize-and-build.ts delete mode 100644 packages/services/src/view-service/balances.test.ts delete mode 100644 packages/services/src/view-service/balances.ts delete mode 100644 packages/services/src/view-service/broadcast-transaction.test.ts delete mode 100644 packages/services/src/view-service/broadcast-transaction.ts delete mode 100644 packages/services/src/view-service/delegations-by-address-index.test.ts delete mode 100644 packages/services/src/view-service/delegations-by-address-index.ts delete mode 100644 packages/services/src/view-service/ephemeral-address.test.ts delete mode 100644 packages/services/src/view-service/ephemeral-address.ts delete mode 100644 packages/services/src/view-service/fmd-parameters.test.ts delete mode 100644 packages/services/src/view-service/fmd-parameters.ts delete mode 100644 packages/services/src/view-service/gas-prices.test.ts delete mode 100644 packages/services/src/view-service/gas-prices.ts delete mode 100644 packages/services/src/view-service/index-by-address.test.ts delete mode 100644 packages/services/src/view-service/index-by-address.ts delete mode 100644 packages/services/src/view-service/index.ts delete mode 100644 packages/services/src/view-service/note-by-commitment.test.ts delete mode 100644 packages/services/src/view-service/note-by-commitment.ts delete mode 100644 packages/services/src/view-service/notes-for-voting.test.ts delete mode 100644 packages/services/src/view-service/notes-for-voting.ts delete mode 100644 packages/services/src/view-service/notes.test.ts delete mode 100644 packages/services/src/view-service/notes.ts delete mode 100644 packages/services/src/view-service/nullifier-status.test.ts delete mode 100644 packages/services/src/view-service/nullifier-status.ts delete mode 100644 packages/services/src/view-service/owned-position-ids.test.ts delete mode 100644 packages/services/src/view-service/owned-position-ids.ts delete mode 100644 packages/services/src/view-service/status-stream.test.ts delete mode 100644 packages/services/src/view-service/status-stream.ts delete mode 100644 packages/services/src/view-service/status.test.ts delete mode 100644 packages/services/src/view-service/status.ts delete mode 100644 packages/services/src/view-service/swap-by-commitment.test.ts delete mode 100644 packages/services/src/view-service/swap-by-commitment.ts delete mode 100644 packages/services/src/view-service/transaction-info-by-hash.test.ts delete mode 100644 packages/services/src/view-service/transaction-info-by-hash.ts delete mode 100644 packages/services/src/view-service/transaction-info.test.ts delete mode 100644 packages/services/src/view-service/transaction-info.ts delete mode 100644 packages/services/src/view-service/transaction-planner/assert-swap-assets-are-not-the-same.test.ts delete mode 100644 packages/services/src/view-service/transaction-planner/assert-swap-assets-are-not-the-same.ts delete mode 100644 packages/services/src/view-service/transaction-planner/index.test.ts delete mode 100644 packages/services/src/view-service/transaction-planner/index.ts delete mode 100644 packages/services/src/view-service/unbonding-tokens-by-address-index/helpers.test.ts delete mode 100644 packages/services/src/view-service/unbonding-tokens-by-address-index/helpers.ts delete mode 100644 packages/services/src/view-service/unbonding-tokens-by-address-index/index.test.ts delete mode 100644 packages/services/src/view-service/unbonding-tokens-by-address-index/index.ts delete mode 100644 packages/services/src/view-service/unclaimed-swaps.test.ts delete mode 100644 packages/services/src/view-service/unclaimed-swaps.ts delete mode 100644 packages/services/src/view-service/util/build-tx.ts delete mode 100644 packages/services/src/view-service/util/custody-authorize.ts delete mode 100644 packages/services/src/view-service/wallet-id.ts delete mode 100644 packages/services/src/view-service/witness-and-build.ts delete mode 100644 packages/services/src/view-service/witness.test.ts delete mode 100644 packages/services/src/view-service/witness.ts delete mode 100644 packages/services/tests-setup.js delete mode 100644 packages/services/tsconfig.json delete mode 100644 packages/services/vitest.config.ts delete mode 100644 packages/storage/CHANGELOG.md delete mode 100644 packages/storage/eslint.config.mjs delete mode 100644 packages/storage/package.json delete mode 100644 packages/storage/src/indexed-db/index.ts delete mode 100644 packages/storage/src/indexed-db/indexed-db.test-data.ts delete mode 100644 packages/storage/src/indexed-db/indexed-db.test.ts delete mode 100644 packages/storage/src/indexed-db/stream.ts delete mode 100644 packages/storage/src/indexed-db/updater.ts delete mode 100644 packages/storage/tsconfig.json delete mode 100644 packages/storage/vitest.config.ts delete mode 100644 packages/transport-chrome/CHANGELOG.md delete mode 100644 packages/transport-chrome/eslint.config.mjs delete mode 100644 packages/transport-chrome/package.json delete mode 100644 packages/transport-chrome/src/channel-names.test.ts delete mode 100644 packages/transport-chrome/src/channel-names.ts delete mode 100644 packages/transport-chrome/src/message.ts delete mode 100644 packages/transport-chrome/src/session-client.ts delete mode 100644 packages/transport-chrome/src/session-manager.ts delete mode 100644 packages/transport-chrome/src/stream.ts delete mode 100644 packages/transport-chrome/tsconfig.json delete mode 100644 packages/transport-dom/CHANGELOG.md delete mode 100644 packages/transport-dom/eslint.config.mjs delete mode 100644 packages/transport-dom/package.json delete mode 100644 packages/transport-dom/src/adapter.ts delete mode 100644 packages/transport-dom/src/any-impl.ts delete mode 100644 packages/transport-dom/src/create.test.ts delete mode 100644 packages/transport-dom/src/create.ts delete mode 100644 packages/transport-dom/src/direct.ts delete mode 100644 packages/transport-dom/src/messages.ts delete mode 100644 packages/transport-dom/src/proxy.ts delete mode 100644 packages/transport-dom/src/stream.test.ts delete mode 100644 packages/transport-dom/src/stream.ts delete mode 100644 packages/transport-dom/tsconfig.json delete mode 100644 packages/transport-dom/vite.config.ts delete mode 100644 packages/types/CHANGELOG.md delete mode 100644 packages/types/eslint.config.mjs delete mode 100644 packages/types/package.json delete mode 100644 packages/types/src/amount.test.ts delete mode 100644 packages/types/src/amount.ts delete mode 100644 packages/types/src/assets.test.ts delete mode 100644 packages/types/src/assets.ts delete mode 100644 packages/types/src/base64.test.ts delete mode 100644 packages/types/src/base64.ts delete mode 100644 packages/types/src/block-processor.ts delete mode 100644 packages/types/src/box.ts delete mode 100644 packages/types/src/environment.ts delete mode 100644 packages/types/src/hex.test.ts delete mode 100644 packages/types/src/hex.ts delete mode 100644 packages/types/src/indexed-db.ts delete mode 100644 packages/types/src/internal-msg/chrome-error.ts delete mode 100644 packages/types/src/internal-msg/offscreen.ts delete mode 100644 packages/types/src/internal-msg/shared.ts delete mode 100644 packages/types/src/jsonified.ts delete mode 100644 packages/types/src/lo-hi.test.ts delete mode 100644 packages/types/src/lo-hi.ts delete mode 100644 packages/types/src/protobuf.test.ts delete mode 100644 packages/types/src/protobuf.ts delete mode 100644 packages/types/src/querier.ts delete mode 100644 packages/types/src/servers.ts delete mode 100644 packages/types/src/services.ts delete mode 100644 packages/types/src/staking.test.ts delete mode 100644 packages/types/src/staking.ts delete mode 100644 packages/types/src/state-commitment-tree.ts delete mode 100644 packages/types/src/string.test.ts delete mode 100644 packages/types/src/string.ts delete mode 100644 packages/types/src/swap.test.ts delete mode 100644 packages/types/src/swap.ts delete mode 100644 packages/types/src/user-choice.ts delete mode 100644 packages/types/src/utility.ts delete mode 100644 packages/types/src/validation.test.ts delete mode 100644 packages/types/src/validation.ts delete mode 100644 packages/types/src/value-view.test.ts delete mode 100644 packages/types/src/value-view.ts delete mode 100644 packages/types/src/wallet.ts delete mode 100644 packages/types/tsconfig.json delete mode 100644 packages/types/vite.config.ts delete mode 100644 packages/ui/components/ui/block-sync-status/shared.ts delete mode 100644 packages/ui/components/ui/navigation-menu.tsx delete mode 100644 packages/wasm/.gitignore delete mode 100644 packages/wasm/.npmignore delete mode 100644 packages/wasm/CHANGELOG.md delete mode 100644 packages/wasm/README.md delete mode 100644 packages/wasm/crate/Cargo.lock delete mode 100644 packages/wasm/crate/Cargo.toml delete mode 100644 packages/wasm/crate/src/asset.rs delete mode 100644 packages/wasm/crate/src/auction.rs delete mode 100644 packages/wasm/crate/src/build.rs delete mode 100644 packages/wasm/crate/src/dex.rs delete mode 100644 packages/wasm/crate/src/error.rs delete mode 100644 packages/wasm/crate/src/keys.rs delete mode 100644 packages/wasm/crate/src/lib.rs delete mode 100644 packages/wasm/crate/src/metadata.rs delete mode 100644 packages/wasm/crate/src/note_record.rs delete mode 100644 packages/wasm/crate/src/planner.rs delete mode 100644 packages/wasm/crate/src/storage.rs delete mode 100644 packages/wasm/crate/src/swap_record.rs delete mode 100644 packages/wasm/crate/src/tree.rs delete mode 100644 packages/wasm/crate/src/tx.rs delete mode 100644 packages/wasm/crate/src/utils.rs delete mode 100644 packages/wasm/crate/src/view_server.rs delete mode 100644 packages/wasm/crate/tests/build.rs delete mode 100644 packages/wasm/crate/tests/deserialize.rs delete mode 100644 packages/wasm/crate/tests/keys.rs delete mode 100644 packages/wasm/eslint.config.mjs delete mode 100644 packages/wasm/package.json delete mode 100644 packages/wasm/src/address.test.ts delete mode 100644 packages/wasm/src/address.ts delete mode 100644 packages/wasm/src/asset.test.ts delete mode 100644 packages/wasm/src/asset.ts delete mode 100644 packages/wasm/src/auction.ts delete mode 100644 packages/wasm/src/build.ts delete mode 100644 packages/wasm/src/dex.ts delete mode 100644 packages/wasm/src/keys.test.ts delete mode 100644 packages/wasm/src/keys.ts delete mode 100644 packages/wasm/src/metadata.ts delete mode 100644 packages/wasm/src/planner.ts delete mode 100644 packages/wasm/src/transaction.ts delete mode 100644 packages/wasm/src/tree.ts delete mode 100644 packages/wasm/src/view-server.test.ts delete mode 100644 packages/wasm/src/view-server.ts delete mode 100644 packages/wasm/tsconfig.json delete mode 100644 packages/wasm/vitest.config.ts delete mode 100644 packages/wasm/wasm/.npmignore delete mode 100644 packages/zquery/CHANGELOG.md delete mode 100644 packages/zquery/eslint.config.mjs delete mode 100644 packages/zquery/package.json delete mode 100644 packages/zquery/src/index.test.ts delete mode 100644 packages/zquery/src/index.ts delete mode 100644 packages/zquery/src/types.ts delete mode 100644 packages/zquery/tsconfig.json diff --git a/.changeset/silly-lemons-fly.md b/.changeset/silly-lemons-fly.md new file mode 100644 index 00000000..10448984 --- /dev/null +++ b/.changeset/silly-lemons-fly.md @@ -0,0 +1,10 @@ +--- +'context': major +'prax-marketing-website': major +'tailwind-config': major +'@repo/eslint-config': major +'chrome-extension': major +'ui': major +--- + +use imported packages diff --git a/.syncpackrc b/.syncpackrc index 4b267e28..d2261984 100644 --- a/.syncpackrc +++ b/.syncpackrc @@ -45,8 +45,8 @@ "@buf/*" ], "snapTo": [ - "penumbra-web" + "prax-wallet" ] } ] -} +} \ No newline at end of file diff --git a/apps/extension/eslint.config.mjs b/apps/extension/eslint.config.mjs index a53ed8e5..11c6ce91 100644 --- a/apps/extension/eslint.config.mjs +++ b/apps/extension/eslint.config.mjs @@ -1,4 +1,4 @@ -import { penumbraEslintConfig } from '@penumbra-zone/eslint-config'; +import { penumbraEslintConfig } from '@repo/eslint-config'; import { config, parser } from 'typescript-eslint'; export default config({ diff --git a/apps/extension/package.json b/apps/extension/package.json index 8a6d9ff0..e17e64bf 100644 --- a/apps/extension/package.json +++ b/apps/extension/package.json @@ -6,7 +6,7 @@ "description": "chrome-extension", "type": "module", "scripts": { - "build": "NODE_ENV=mainnet pnpm bundle", + "build": "pnpm bundle", "bundle": "NODE_OPTIONS=\"--import=./src/utils/webpack-register.js\" webpack", "clean": "rm -rfv dist bin", "dev": "NODE_ENV=testnet pnpm bundle --watch --mode=development -d inline-source-map", @@ -14,26 +14,28 @@ "test": "vitest run" }, "dependencies": { - "@buf/penumbra-zone_penumbra.bufbuild_es": "1.9.0-20240528180215-8fe1c79485f8.1", + "@buf/cosmos_ibc.bufbuild_es": "1.10.0-20240606104028-442292b00c16.1", + "@buf/penumbra-zone_penumbra.bufbuild_es": "1.10.0-20240616005217-ca45ca80333e.1", "@bufbuild/protobuf": "^1.10.0", "@connectrpc/connect": "^1.4.0", "@connectrpc/connect-web": "^1.4.0", "@penumbra-labs/registry": "8.0.1", - "@penumbra-zone/bech32m": "workspace:*", - "@penumbra-zone/client": "workspace:*", - "@penumbra-zone/crypto-web": "workspace:*", - "@penumbra-zone/getters": "workspace:*", - "@penumbra-zone/perspective": "workspace:*", - "@penumbra-zone/protobuf": "workspace:*", - "@penumbra-zone/query": "workspace:*", - "@penumbra-zone/services": "workspace:*", - "@penumbra-zone/services-context": "workspace:*", - "@penumbra-zone/storage": "workspace:*", - "@penumbra-zone/transport-chrome": "workspace:*", - "@penumbra-zone/transport-dom": "workspace:*", - "@penumbra-zone/types": "workspace:*", - "@penumbra-zone/ui": "workspace:*", - "@penumbra-zone/wasm": "workspace:*", + "@penumbra-zone/bech32m": "^6.1.0", + "@penumbra-zone/client": "^8.0.0", + "@penumbra-zone/crypto-web": "^5.0.0", + "@penumbra-zone/getters": "^8.0.0", + "@penumbra-zone/keys": "^4.1.0", + "@penumbra-zone/perspective": "^6.0.0", + "@penumbra-zone/protobuf": "^5.1.0", + "@penumbra-zone/query": "^6.0.0", + "@penumbra-zone/services": "^6.0.0", + "@penumbra-zone/storage": "^6.0.0", + "@penumbra-zone/transport-chrome": "^4.0.0", + "@penumbra-zone/transport-dom": "^7.1.0", + "@penumbra-zone/types": "^9.0.0", + "@penumbra-zone/wasm": "^9.0.0", + "@repo/context": "workspace:*", + "@repo/ui": "workspace:*", "@tanstack/react-query": "4.36.1", "buffer": "^6.0.3", "exponential-backoff": "^3.1.1", @@ -51,8 +53,8 @@ "zustand": "^4.5.2" }, "devDependencies": { - "@penumbra-zone/keys": "workspace:*", "@radix-ui/react-icons": "^1.3.0", + "@types/chrome": "0.0.268", "@types/firefox-webext-browser": "^120.0.3", "@types/lodash": "^4.17.4", "@types/react": "^18.3.2", @@ -67,11 +69,9 @@ "postcss-loader": "^8.1.1", "promise.withresolvers": "^1.0.3", "style-loader": "^4.0.0", - "tailwindcss": "^3.4.3", + "tailwindcss": "^3.4.4", "ts-loader": "^9.5.1", "ts-node": "^10.9.2", - "vite-plugin-top-level-await": "^1.4.1", - "vite-plugin-wasm": "^3.3.0", "webpack": "^5.91.0", "webpack-cli": "^5.1.4", "webpack-merge": "^5.10.0" diff --git a/apps/extension/postcss.config.js b/apps/extension/postcss.config.js index 8e18cdcb..a2051ffd 100644 --- a/apps/extension/postcss.config.js +++ b/apps/extension/postcss.config.js @@ -1 +1 @@ -export { default } from '@penumbra-zone/ui/postcss.config.js'; +export { default } from '@repo/ui/postcss.config.js'; diff --git a/apps/extension/src/entry/page-root.tsx b/apps/extension/src/entry/page-root.tsx index fe0f7e64..19e7f121 100644 --- a/apps/extension/src/entry/page-root.tsx +++ b/apps/extension/src/entry/page-root.tsx @@ -4,7 +4,7 @@ import { pageRouter } from '../routes/page/router'; import { StrictMode, useState } from 'react'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; -import '@penumbra-zone/ui/styles/globals.css'; +import '@repo/ui/styles/globals.css'; const MainPage = () => { const [queryClient] = useState(() => new QueryClient()); diff --git a/apps/extension/src/entry/popup-root.tsx b/apps/extension/src/entry/popup-root.tsx index 2e24aa64..4f42f0d1 100644 --- a/apps/extension/src/entry/popup-root.tsx +++ b/apps/extension/src/entry/popup-root.tsx @@ -12,7 +12,7 @@ import { txApprovalSelector } from '../state/tx-approval'; import { errorToJson } from '@connectrpc/connect/protocol-connect'; import { ConnectError } from '@connectrpc/connect'; -import '@penumbra-zone/ui/styles/globals.css'; +import '@repo/ui/styles/globals.css'; chrome.runtime.onMessage.addListener( (req: unknown, _: chrome.runtime.MessageSender, responder: (x: unknown) => void) => { diff --git a/apps/extension/src/hooks/full-sync-height.ts b/apps/extension/src/hooks/full-sync-height.ts index 6d5fab47..fccb15d8 100644 --- a/apps/extension/src/hooks/full-sync-height.ts +++ b/apps/extension/src/hooks/full-sync-height.ts @@ -1,9 +1,11 @@ import { useQuery } from '@tanstack/react-query'; -import { TendermintQuerier } from '@penumbra-zone/query/queriers/tendermint'; import { PopupLoaderData } from '../routes/popup/home'; import { useStore } from '../state'; import { networkSelector } from '../state/network'; import { useLoaderData } from 'react-router-dom'; +import { TendermintProxyService } from '@penumbra-zone/protobuf'; +import { createGrpcWebTransport } from '@connectrpc/connect-web'; +import { createPromiseClient } from '@connectrpc/connect'; const tryGetMax = (a?: number, b?: number): number | undefined => { // Height can be 0n which is falsy, so should compare to undefined state @@ -29,8 +31,13 @@ export const useSyncProgress = () => { const { data: queriedLatest, error } = useQuery({ queryKey: ['latestBlockHeight'], queryFn: async () => { - const querier = new TendermintQuerier({ grpcEndpoint: grpcEndpoint! }); - const blockHeight = await querier.latestBlockHeight(); + if (!grpcEndpoint) return; + const tendermintClient = createPromiseClient( + TendermintProxyService, + createGrpcWebTransport({ baseUrl: grpcEndpoint }), + ); + const blockHeight = (await tendermintClient.getStatus({}).catch(() => undefined))?.syncInfo + ?.latestBlockHeight; return Number(blockHeight); }, enabled: Boolean(grpcEndpoint), diff --git a/apps/extension/src/listeners/message-prax-request.ts b/apps/extension/src/listeners/message-prax-request.ts index 8b030d4c..19d23e1d 100644 --- a/apps/extension/src/listeners/message-prax-request.ts +++ b/apps/extension/src/listeners/message-prax-request.ts @@ -21,7 +21,7 @@ chrome.runtime.onMessage.addListener( } }, e => { - if (process.env['NODE_ENV'] === 'development') { + if (globalThis.__DEV__) { console.warn('Connection request listener failed:', e); } if (e instanceof ConnectError && e.code === Code.Unauthenticated) { diff --git a/apps/extension/src/routes/page/index.tsx b/apps/extension/src/routes/page/index.tsx index a29a144a..7a5fc931 100644 --- a/apps/extension/src/routes/page/index.tsx +++ b/apps/extension/src/routes/page/index.tsx @@ -1,7 +1,7 @@ import { redirect } from 'react-router-dom'; import { PagePath } from './paths'; -import { SplashPage } from '@penumbra-zone/ui/components/ui/splash-page'; -import { Button } from '@penumbra-zone/ui/components/ui/button'; +import { SplashPage } from '@repo/ui/components/ui/splash-page'; +import { Button } from '@repo/ui/components/ui/button'; import { localExtStorage } from '../../storage/local'; import { useStore } from '../../state'; import { getDefaultFrontend } from '../../state/default-frontend'; diff --git a/apps/extension/src/routes/page/onboarding/confirm-backup.tsx b/apps/extension/src/routes/page/onboarding/confirm-backup.tsx index 091fbb5f..841fecca 100644 --- a/apps/extension/src/routes/page/onboarding/confirm-backup.tsx +++ b/apps/extension/src/routes/page/onboarding/confirm-backup.tsx @@ -1,15 +1,15 @@ import { useState } from 'react'; -import { Button } from '@penumbra-zone/ui/components/ui/button'; -import { BackIcon } from '@penumbra-zone/ui/components/ui/back-icon'; +import { Button } from '@repo/ui/components/ui/button'; +import { BackIcon } from '@repo/ui/components/ui/back-icon'; import { Card, CardContent, CardDescription, CardHeader, CardTitle, -} from '@penumbra-zone/ui/components/ui/card'; -import { FadeTransition } from '@penumbra-zone/ui/components/ui/fade-transition'; -import { Input } from '@penumbra-zone/ui/components/ui/input'; +} from '@repo/ui/components/ui/card'; +import { FadeTransition } from '@repo/ui/components/ui/fade-transition'; +import { Input } from '@repo/ui/components/ui/input'; import { useStore } from '../../../state'; import { generateSelector } from '../../../state/seed-phrase/generate'; import { usePageNav } from '../../../utils/navigate'; diff --git a/apps/extension/src/routes/page/onboarding/default-frontend.tsx b/apps/extension/src/routes/page/onboarding/default-frontend.tsx index 349a3825..bc256b2f 100644 --- a/apps/extension/src/routes/page/onboarding/default-frontend.tsx +++ b/apps/extension/src/routes/page/onboarding/default-frontend.tsx @@ -1,5 +1,5 @@ -import { Card, CardDescription, CardHeader, CardTitle } from '@penumbra-zone/ui/components/ui/card'; -import { FadeTransition } from '@penumbra-zone/ui/components/ui/fade-transition'; +import { Card, CardDescription, CardHeader, CardTitle } from '@repo/ui/components/ui/card'; +import { FadeTransition } from '@repo/ui/components/ui/fade-transition'; import { usePageNav } from '../../../utils/navigate'; import { PagePath } from '../paths'; import { DefaultFrontendForm } from '../../../shared/components/default-frontend-form'; diff --git a/apps/extension/src/routes/page/onboarding/generate.tsx b/apps/extension/src/routes/page/onboarding/generate.tsx index 4f6d7f35..d4cb21e5 100644 --- a/apps/extension/src/routes/page/onboarding/generate.tsx +++ b/apps/extension/src/routes/page/onboarding/generate.tsx @@ -1,13 +1,13 @@ import { ExclamationTriangleIcon, LockClosedIcon } from '@radix-ui/react-icons'; import { SeedPhraseLength } from '@penumbra-zone/crypto-web/mnemonic'; import { useEffect, useState } from 'react'; -import { Button } from '@penumbra-zone/ui/components/ui/button'; -import { BackIcon } from '@penumbra-zone/ui/components/ui/back-icon'; -import { Card, CardContent, CardHeader, CardTitle } from '@penumbra-zone/ui/components/ui/card'; -import { CopyToClipboard } from '@penumbra-zone/ui/components/ui/copy-to-clipboard'; -import { FadeTransition } from '@penumbra-zone/ui/components/ui/fade-transition'; -import { Input } from '@penumbra-zone/ui/components/ui/input'; -import { cn } from '@penumbra-zone/ui/lib/utils'; +import { Button } from '@repo/ui/components/ui/button'; +import { BackIcon } from '@repo/ui/components/ui/back-icon'; +import { Card, CardContent, CardHeader, CardTitle } from '@repo/ui/components/ui/card'; +import { CopyToClipboard } from '@repo/ui/components/ui/copy-to-clipboard'; +import { FadeTransition } from '@repo/ui/components/ui/fade-transition'; +import { Input } from '@repo/ui/components/ui/input'; +import { cn } from '@repo/ui/lib/utils'; import { useCountdown } from 'usehooks-ts'; import { useStore } from '../../../state'; import { generateSelector } from '../../../state/seed-phrase/generate'; diff --git a/apps/extension/src/routes/page/onboarding/import.tsx b/apps/extension/src/routes/page/onboarding/import.tsx index 5a52d3dd..0ecc9bd9 100644 --- a/apps/extension/src/routes/page/onboarding/import.tsx +++ b/apps/extension/src/routes/page/onboarding/import.tsx @@ -1,14 +1,14 @@ -import { BackIcon } from '@penumbra-zone/ui/components/ui/back-icon'; -import { Button } from '@penumbra-zone/ui/components/ui/button'; +import { BackIcon } from '@repo/ui/components/ui/back-icon'; +import { Button } from '@repo/ui/components/ui/button'; import { Card, CardContent, CardDescription, CardHeader, CardTitle, -} from '@penumbra-zone/ui/components/ui/card'; -import { FadeTransition } from '@penumbra-zone/ui/components/ui/fade-transition'; -import { cn } from '@penumbra-zone/ui/lib/utils'; +} from '@repo/ui/components/ui/card'; +import { FadeTransition } from '@repo/ui/components/ui/fade-transition'; +import { cn } from '@repo/ui/lib/utils'; import { useStore } from '../../../state'; import { importSelector } from '../../../state/seed-phrase/import'; import { usePageNav } from '../../../utils/navigate'; diff --git a/apps/extension/src/routes/page/onboarding/set-grpc-endpoint.tsx b/apps/extension/src/routes/page/onboarding/set-grpc-endpoint.tsx index 46c1f854..55a67d9b 100644 --- a/apps/extension/src/routes/page/onboarding/set-grpc-endpoint.tsx +++ b/apps/extension/src/routes/page/onboarding/set-grpc-endpoint.tsx @@ -1,5 +1,5 @@ -import { Card, CardDescription, CardHeader, CardTitle } from '@penumbra-zone/ui/components/ui/card'; -import { FadeTransition } from '@penumbra-zone/ui/components/ui/fade-transition'; +import { Card, CardDescription, CardHeader, CardTitle } from '@repo/ui/components/ui/card'; +import { FadeTransition } from '@repo/ui/components/ui/fade-transition'; import { usePageNav } from '../../../utils/navigate'; import { PagePath } from '../paths'; import { GrpcEndpointForm } from '../../../shared/components/grpc-endpoint-form'; diff --git a/apps/extension/src/routes/page/onboarding/set-numeraire.tsx b/apps/extension/src/routes/page/onboarding/set-numeraire.tsx index eb347b14..f80852ab 100644 --- a/apps/extension/src/routes/page/onboarding/set-numeraire.tsx +++ b/apps/extension/src/routes/page/onboarding/set-numeraire.tsx @@ -1,5 +1,5 @@ -import { Card, CardDescription, CardHeader, CardTitle } from '@penumbra-zone/ui/components/ui/card'; -import { FadeTransition } from '@penumbra-zone/ui/components/ui/fade-transition'; +import { Card, CardDescription, CardHeader, CardTitle } from '@repo/ui/components/ui/card'; +import { FadeTransition } from '@repo/ui/components/ui/fade-transition'; import { usePageNav } from '../../../utils/navigate'; import { PagePath } from '../paths'; import { NumeraireForm } from '../../../shared/components/numeraires-form'; diff --git a/apps/extension/src/routes/page/onboarding/set-password.tsx b/apps/extension/src/routes/page/onboarding/set-password.tsx index 6f82a6f2..6bcd1e5c 100644 --- a/apps/extension/src/routes/page/onboarding/set-password.tsx +++ b/apps/extension/src/routes/page/onboarding/set-password.tsx @@ -1,14 +1,14 @@ import { FormEvent, MouseEvent, useState } from 'react'; -import { BackIcon } from '@penumbra-zone/ui/components/ui/back-icon'; -import { Button } from '@penumbra-zone/ui/components/ui/button'; +import { BackIcon } from '@repo/ui/components/ui/back-icon'; +import { Button } from '@repo/ui/components/ui/button'; import { Card, CardContent, CardDescription, CardHeader, CardTitle, -} from '@penumbra-zone/ui/components/ui/card'; -import { FadeTransition } from '@penumbra-zone/ui/components/ui/fade-transition'; +} from '@repo/ui/components/ui/card'; +import { FadeTransition } from '@repo/ui/components/ui/fade-transition'; import { useOnboardingSave } from '../../../hooks/onboarding'; import { usePageNav } from '../../../utils/navigate'; import { PagePath } from '../paths'; diff --git a/apps/extension/src/routes/page/onboarding/start.tsx b/apps/extension/src/routes/page/onboarding/start.tsx index 0dd0a06f..7ef621d0 100644 --- a/apps/extension/src/routes/page/onboarding/start.tsx +++ b/apps/extension/src/routes/page/onboarding/start.tsx @@ -1,12 +1,12 @@ -import { Button } from '@penumbra-zone/ui/components/ui/button'; +import { Button } from '@repo/ui/components/ui/button'; import { Card, CardContent, CardDescription, CardHeader, CardTitle, -} from '@penumbra-zone/ui/components/ui/card'; -import { FadeTransition } from '@penumbra-zone/ui/components/ui/fade-transition'; +} from '@repo/ui/components/ui/card'; +import { FadeTransition } from '@repo/ui/components/ui/fade-transition'; import { usePageNav } from '../../../utils/navigate'; import { PagePath } from '../paths'; diff --git a/apps/extension/src/routes/page/onboarding/success.tsx b/apps/extension/src/routes/page/onboarding/success.tsx index aaca1df1..2b088ef4 100644 --- a/apps/extension/src/routes/page/onboarding/success.tsx +++ b/apps/extension/src/routes/page/onboarding/success.tsx @@ -1,5 +1,5 @@ -import { Button } from '@penumbra-zone/ui/components/ui/button'; -import { SplashPage } from '@penumbra-zone/ui/components/ui/splash-page'; +import { Button } from '@repo/ui/components/ui/button'; +import { SplashPage } from '@repo/ui/components/ui/splash-page'; import { useStore } from '../../../state'; import { getDefaultFrontend } from '../../../state/default-frontend'; diff --git a/apps/extension/src/routes/page/restore-password/restore-password.tsx b/apps/extension/src/routes/page/restore-password/restore-password.tsx index 9114730e..6649745e 100644 --- a/apps/extension/src/routes/page/restore-password/restore-password.tsx +++ b/apps/extension/src/routes/page/restore-password/restore-password.tsx @@ -1,13 +1,13 @@ -import { Button } from '@penumbra-zone/ui/components/ui/button'; +import { Button } from '@repo/ui/components/ui/button'; import { Card, CardContent, CardDescription, CardHeader, CardTitle, -} from '@penumbra-zone/ui/components/ui/card'; -import { FadeTransition } from '@penumbra-zone/ui/components/ui/fade-transition'; -import { cn } from '@penumbra-zone/ui/lib/utils'; +} from '@repo/ui/components/ui/card'; +import { FadeTransition } from '@repo/ui/components/ui/fade-transition'; +import { cn } from '@repo/ui/lib/utils'; import { useStore } from '../../../state'; import { importSelector } from '../../../state/seed-phrase/import'; import { usePageNav } from '../../../utils/navigate'; diff --git a/apps/extension/src/routes/page/restore-password/set-password.tsx b/apps/extension/src/routes/page/restore-password/set-password.tsx index 02ad0686..2afcfb4f 100644 --- a/apps/extension/src/routes/page/restore-password/set-password.tsx +++ b/apps/extension/src/routes/page/restore-password/set-password.tsx @@ -1,14 +1,14 @@ import { useState } from 'react'; -import { Button } from '@penumbra-zone/ui/components/ui/button'; -import { BackIcon } from '@penumbra-zone/ui/components/ui/back-icon'; +import { Button } from '@repo/ui/components/ui/button'; +import { BackIcon } from '@repo/ui/components/ui/back-icon'; import { Card, CardContent, CardDescription, CardHeader, CardTitle, -} from '@penumbra-zone/ui/components/ui/card'; -import { FadeTransition } from '@penumbra-zone/ui/components/ui/fade-transition'; +} from '@repo/ui/components/ui/card'; +import { FadeTransition } from '@repo/ui/components/ui/fade-transition'; import { useOnboardingSave } from '../../../hooks/onboarding'; import { usePageNav } from '../../../utils/navigate'; import { PagePath } from '../paths'; diff --git a/apps/extension/src/routes/popup/approval/approve-deny.tsx b/apps/extension/src/routes/popup/approval/approve-deny.tsx index 617c7bf2..88aa94bf 100644 --- a/apps/extension/src/routes/popup/approval/approve-deny.tsx +++ b/apps/extension/src/routes/popup/approval/approve-deny.tsx @@ -1,4 +1,4 @@ -import { Button } from '@penumbra-zone/ui/components/ui/button'; +import { Button } from '@repo/ui/components/ui/button'; import { useWindowCountdown } from './use-window-countdown'; export const ApproveDeny = ({ diff --git a/apps/extension/src/routes/popup/approval/origin.tsx b/apps/extension/src/routes/popup/approval/origin.tsx index 50d6ce6a..1e81220e 100644 --- a/apps/extension/src/routes/popup/approval/origin.tsx +++ b/apps/extension/src/routes/popup/approval/origin.tsx @@ -1,10 +1,10 @@ -import { FadeTransition } from '@penumbra-zone/ui/components/ui/fade-transition'; +import { FadeTransition } from '@repo/ui/components/ui/fade-transition'; import { useStore } from '../../../state'; import { originApprovalSelector } from '../../../state/origin-approval'; import { ApproveDeny } from './approve-deny'; import { LinkGradientIcon } from '../../../icons/link-gradient'; import { DisplayOriginURL } from '../../../shared/components/display-origin-url'; -import { cn } from '@penumbra-zone/ui/lib/utils'; +import { cn } from '@repo/ui/lib/utils'; import { UserChoice } from '@penumbra-zone/types/user-choice'; import { ExclamationTriangleIcon } from '@radix-ui/react-icons'; diff --git a/apps/extension/src/routes/popup/approval/transaction/index.tsx b/apps/extension/src/routes/popup/approval/transaction/index.tsx index ecf878f0..7b7f9807 100644 --- a/apps/extension/src/routes/popup/approval/transaction/index.tsx +++ b/apps/extension/src/routes/popup/approval/transaction/index.tsx @@ -1,7 +1,7 @@ -import { TransactionViewComponent } from '@penumbra-zone/ui/components/ui/tx/view/transaction'; +import { TransactionViewComponent } from '@repo/ui/components/ui/tx/view/transaction'; import { useStore } from '../../../../state'; import { txApprovalSelector } from '../../../../state/tx-approval'; -import { JsonViewer } from '@penumbra-zone/ui/components/ui/json-viewer'; +import { JsonViewer } from '@repo/ui/components/ui/json-viewer'; import { AuthorizeRequest } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/custody/v1/custody_pb'; import { useTransactionViewSwitcher } from './use-transaction-view-switcher'; import { ViewTabs } from './view-tabs'; diff --git a/apps/extension/src/routes/popup/approval/transaction/view-tabs.tsx b/apps/extension/src/routes/popup/approval/transaction/view-tabs.tsx index ad797228..b0bdfbac 100644 --- a/apps/extension/src/routes/popup/approval/transaction/view-tabs.tsx +++ b/apps/extension/src/routes/popup/approval/transaction/view-tabs.tsx @@ -1,5 +1,5 @@ -import { Tabs, TabsList, TabsTrigger } from '@penumbra-zone/ui/components/ui/tabs'; -import { cn } from '@penumbra-zone/ui/lib/utils'; +import { Tabs, TabsList, TabsTrigger } from '@repo/ui/components/ui/tabs'; +import { cn } from '@repo/ui/lib/utils'; import { TransactionViewTab } from './types'; import { useStore } from '../../../../state'; import { txApprovalSelector } from '../../../../state/tx-approval'; diff --git a/apps/extension/src/routes/popup/home/block-sync.tsx b/apps/extension/src/routes/popup/home/block-sync.tsx index 426e78b3..99ad8e15 100644 --- a/apps/extension/src/routes/popup/home/block-sync.tsx +++ b/apps/extension/src/routes/popup/home/block-sync.tsx @@ -1,4 +1,4 @@ -import { CondensedBlockSyncStatus } from '@penumbra-zone/ui/components/ui/block-sync-status/condensed'; +import { CondensedBlockSyncStatus } from '@repo/ui/components/ui/block-sync-status/condensed'; import { useSyncProgress } from '../../../hooks/full-sync-height'; export const BlockSync = () => { @@ -6,8 +6,8 @@ export const BlockSync = () => { return ( ); diff --git a/apps/extension/src/routes/popup/home/frontend-link.tsx b/apps/extension/src/routes/popup/home/frontend-link.tsx index 726812e7..d8689edf 100644 --- a/apps/extension/src/routes/popup/home/frontend-link.tsx +++ b/apps/extension/src/routes/popup/home/frontend-link.tsx @@ -1,6 +1,6 @@ import { useStore } from '../../../state'; import { getDefaultFrontend } from '../../../state/default-frontend'; -import { Button } from '@penumbra-zone/ui/components/ui/button'; +import { Button } from '@repo/ui/components/ui/button'; import { ExternalLink } from 'lucide-react'; import { MouseEventHandler } from 'react'; import { usePopupNav } from '../../../utils/navigate'; diff --git a/apps/extension/src/routes/popup/home/index-header.tsx b/apps/extension/src/routes/popup/home/index-header.tsx index 05b5dbfb..ad0a06b3 100644 --- a/apps/extension/src/routes/popup/home/index-header.tsx +++ b/apps/extension/src/routes/popup/home/index-header.tsx @@ -1,7 +1,7 @@ import { HamburgerMenuIcon } from '@radix-ui/react-icons'; import { usePopupNav } from '../../../utils/navigate'; import { PopupPath } from '../paths'; -import { Network } from '@penumbra-zone/ui/components/ui/network'; +import { Network } from '@repo/ui/components/ui/network'; import { useChainIdQuery } from '../../../hooks/chain-id'; import { motion } from 'framer-motion'; import { useStore } from '../../../state'; @@ -24,7 +24,7 @@ export const IndexHeader = () => { animate={{ opacity: 1, transition: { duration: 0.5, ease: 'easeOut' } }} className='overflow-hidden' > - + ) : (
diff --git a/apps/extension/src/routes/popup/home/index.tsx b/apps/extension/src/routes/popup/home/index.tsx index cf6a7a54..50e941f1 100644 --- a/apps/extension/src/routes/popup/home/index.tsx +++ b/apps/extension/src/routes/popup/home/index.tsx @@ -1,4 +1,4 @@ -import { SelectAccount } from '@penumbra-zone/ui/components/ui/select-account'; +import { SelectAccount } from '@repo/ui/components/ui/select-account'; import { IndexHeader } from './index-header'; import { useStore } from '../../../state'; import { BlockSync } from './block-sync'; diff --git a/apps/extension/src/routes/popup/home/validate-address/index.tsx b/apps/extension/src/routes/popup/home/validate-address/index.tsx index 55863782..df8d0395 100644 --- a/apps/extension/src/routes/popup/home/validate-address/index.tsx +++ b/apps/extension/src/routes/popup/home/validate-address/index.tsx @@ -1,5 +1,5 @@ -import { Box } from '@penumbra-zone/ui/components/ui/box'; -import { IconInput } from '@penumbra-zone/ui/components/ui/icon-input'; +import { Box } from '@repo/ui/components/ui/box'; +import { IconInput } from '@repo/ui/components/ui/icon-input'; import { useEffect, useState } from 'react'; import { MagnifyingGlassIcon } from '@radix-ui/react-icons'; import { AddressOwnershipInfo } from './types'; diff --git a/apps/extension/src/routes/popup/login.tsx b/apps/extension/src/routes/popup/login.tsx index f277e964..c7d833e1 100644 --- a/apps/extension/src/routes/popup/login.tsx +++ b/apps/extension/src/routes/popup/login.tsx @@ -1,6 +1,6 @@ -import { Button } from '@penumbra-zone/ui/components/ui/button'; -import { FadeTransition } from '@penumbra-zone/ui/components/ui/fade-transition'; -import { InputProps } from '@penumbra-zone/ui/components/ui/input'; +import { Button } from '@repo/ui/components/ui/button'; +import { FadeTransition } from '@repo/ui/components/ui/fade-transition'; +import { InputProps } from '@repo/ui/components/ui/input'; import { PagePath } from '../page/paths'; import { PasswordInput } from '../../shared/components/password-input'; import { usePopupNav } from '../../utils/navigate'; diff --git a/apps/extension/src/routes/popup/settings/settings-auto-lock.tsx b/apps/extension/src/routes/popup/settings/settings-auto-lock.tsx index 12f51018..f1ebedcf 100644 --- a/apps/extension/src/routes/popup/settings/settings-auto-lock.tsx +++ b/apps/extension/src/routes/popup/settings/settings-auto-lock.tsx @@ -1,5 +1,5 @@ -import { Button } from '@penumbra-zone/ui/components/ui/button'; -import { Input } from '@penumbra-zone/ui/components/ui/input'; +import { Button } from '@repo/ui/components/ui/button'; +import { Input } from '@repo/ui/components/ui/input'; import { TimerGradientIcon } from '../../../icons/time-gradient'; import { SettingsScreen } from './settings-screen'; diff --git a/apps/extension/src/routes/popup/settings/settings-clear-cache.tsx b/apps/extension/src/routes/popup/settings/settings-clear-cache.tsx index bf1721a9..c9cd1fd1 100644 --- a/apps/extension/src/routes/popup/settings/settings-clear-cache.tsx +++ b/apps/extension/src/routes/popup/settings/settings-clear-cache.tsx @@ -1,5 +1,5 @@ import { ExclamationTriangleIcon } from '@radix-ui/react-icons'; -import { Button } from '@penumbra-zone/ui/components/ui/button'; +import { Button } from '@repo/ui/components/ui/button'; import { TrashGradientIcon } from '../../../icons/trash-gradient'; import { ServicesMessage } from '../../../message/services'; import { usePopupNav } from '../../../utils/navigate'; diff --git a/apps/extension/src/routes/popup/settings/settings-connected-sites/index.tsx b/apps/extension/src/routes/popup/settings/settings-connected-sites/index.tsx index 7849544f..f43ce386 100644 --- a/apps/extension/src/routes/popup/settings/settings-connected-sites/index.tsx +++ b/apps/extension/src/routes/popup/settings/settings-connected-sites/index.tsx @@ -1,5 +1,5 @@ import { MagnifyingGlassIcon } from '@radix-ui/react-icons'; -import { Input } from '@penumbra-zone/ui/components/ui/input'; +import { Input } from '@repo/ui/components/ui/input'; import { LinkGradientIcon } from '../../../../icons/link-gradient'; import { OriginRecord } from '../../../../storage/types'; import { AllSlices, useStore } from '../../../../state'; diff --git a/apps/extension/src/routes/popup/settings/settings-connected-sites/known-site.tsx b/apps/extension/src/routes/popup/settings/settings-connected-sites/known-site.tsx index 89e63e48..dbec1699 100644 --- a/apps/extension/src/routes/popup/settings/settings-connected-sites/known-site.tsx +++ b/apps/extension/src/routes/popup/settings/settings-connected-sites/known-site.tsx @@ -1,6 +1,6 @@ import { OriginRecord } from '../../../../storage/types'; import { UserChoice } from '@penumbra-zone/types/user-choice'; -import { Button } from '@penumbra-zone/ui/components/ui/button'; +import { Button } from '@repo/ui/components/ui/button'; import { TrashIcon } from 'lucide-react'; import { DisplayOriginURL } from '../../../../shared/components/display-origin-url'; diff --git a/apps/extension/src/routes/popup/settings/settings-full-viewing-key.tsx b/apps/extension/src/routes/popup/settings/settings-full-viewing-key.tsx index 2a8ba424..ee383107 100644 --- a/apps/extension/src/routes/popup/settings/settings-full-viewing-key.tsx +++ b/apps/extension/src/routes/popup/settings/settings-full-viewing-key.tsx @@ -1,7 +1,7 @@ import { ExclamationTriangleIcon } from '@radix-ui/react-icons'; import { useState } from 'react'; -import { Button } from '@penumbra-zone/ui/components/ui/button'; -import { CopyToClipboard } from '@penumbra-zone/ui/components/ui/copy-to-clipboard'; +import { Button } from '@repo/ui/components/ui/button'; +import { CopyToClipboard } from '@repo/ui/components/ui/copy-to-clipboard'; import { PasswordInput } from '../../../shared/components/password-input'; import { useStore } from '../../../state'; import { passwordSelector } from '../../../state/password'; diff --git a/apps/extension/src/routes/popup/settings/settings-passphrase.tsx b/apps/extension/src/routes/popup/settings/settings-passphrase.tsx index 3abefaf1..1ec91663 100644 --- a/apps/extension/src/routes/popup/settings/settings-passphrase.tsx +++ b/apps/extension/src/routes/popup/settings/settings-passphrase.tsx @@ -1,7 +1,7 @@ import { ExclamationTriangleIcon } from '@radix-ui/react-icons'; import { useState } from 'react'; -import { Button } from '@penumbra-zone/ui/components/ui/button'; -import { CopyToClipboard } from '@penumbra-zone/ui/components/ui/copy-to-clipboard'; +import { Button } from '@repo/ui/components/ui/button'; +import { CopyToClipboard } from '@repo/ui/components/ui/copy-to-clipboard'; import { FileTextGradientIcon } from '../../../icons/file-text-gradient'; import { PasswordInput } from '../../../shared/components/password-input'; import { useStore } from '../../../state'; diff --git a/apps/extension/src/routes/popup/settings/settings-screen/index.tsx b/apps/extension/src/routes/popup/settings/settings-screen/index.tsx index 285486ec..9d4df79d 100644 --- a/apps/extension/src/routes/popup/settings/settings-screen/index.tsx +++ b/apps/extension/src/routes/popup/settings/settings-screen/index.tsx @@ -1,4 +1,4 @@ -import { FadeTransition } from '@penumbra-zone/ui/components/ui/fade-transition'; +import { FadeTransition } from '@repo/ui/components/ui/fade-transition'; import { SettingsHeader } from './settings-header'; import { ReactNode } from 'react'; diff --git a/apps/extension/src/routes/popup/settings/settings-screen/settings-header.tsx b/apps/extension/src/routes/popup/settings/settings-screen/settings-header.tsx index f0657750..a893bef2 100644 --- a/apps/extension/src/routes/popup/settings/settings-screen/settings-header.tsx +++ b/apps/extension/src/routes/popup/settings/settings-screen/settings-header.tsx @@ -1,4 +1,4 @@ -import { BackIcon } from '@penumbra-zone/ui/components/ui/back-icon'; +import { BackIcon } from '@repo/ui/components/ui/back-icon'; import { usePopupNav } from '../../../../utils/navigate'; export const SettingsHeader = ({ title }: { title: string }) => { diff --git a/apps/extension/src/routes/popup/settings/settings-spend-key.tsx b/apps/extension/src/routes/popup/settings/settings-spend-key.tsx index 37e5ff41..7330a977 100644 --- a/apps/extension/src/routes/popup/settings/settings-spend-key.tsx +++ b/apps/extension/src/routes/popup/settings/settings-spend-key.tsx @@ -1,7 +1,7 @@ import { ExclamationTriangleIcon } from '@radix-ui/react-icons'; import { useState } from 'react'; -import { Button } from '@penumbra-zone/ui/components/ui/button'; -import { CopyToClipboard } from '@penumbra-zone/ui/components/ui/copy-to-clipboard'; +import { Button } from '@repo/ui/components/ui/button'; +import { CopyToClipboard } from '@repo/ui/components/ui/copy-to-clipboard'; import { PasswordInput } from '../../../shared/components/password-input'; import { useStore } from '../../../state'; import { passwordSelector } from '../../../state/password'; diff --git a/apps/extension/src/rpc/rethrow-impl-errors.ts b/apps/extension/src/rpc/rethrow-impl-errors.ts index 4156c3f7..f171a44a 100644 --- a/apps/extension/src/rpc/rethrow-impl-errors.ts +++ b/apps/extension/src/rpc/rethrow-impl-errors.ts @@ -12,12 +12,12 @@ const wrapUnaryImpl = const result = methodImplementation(req, ctx); if (result instanceof Promise) return result.catch((e: unknown) => { - if (process.env['NODE_ENV'] === 'development') console.debug(ctx.method.name, req, e); + if (globalThis.__DEV__) console.debug(ctx.method.name, req, e); throw ConnectError.from(e); }); return result; } catch (e) { - if (process.env['NODE_ENV'] === 'development') console.debug(ctx.method.name, req, e); + if (globalThis.__DEV__) console.debug(ctx.method.name, req, e); throw ConnectError.from(e); } }; @@ -31,7 +31,7 @@ const wrapServerStreamingImpl = ( yield result; } } catch (e) { - if (process.env['NODE_ENV'] === 'development') console.debug(ctx.method.name, req, e); + if (globalThis.__DEV__) console.debug(ctx.method.name, req, e); throw ConnectError.from(e); } }; diff --git a/apps/extension/src/shared/components/default-frontend-form/index.tsx b/apps/extension/src/shared/components/default-frontend-form/index.tsx index 15784b41..c338c516 100644 --- a/apps/extension/src/shared/components/default-frontend-form/index.tsx +++ b/apps/extension/src/shared/components/default-frontend-form/index.tsx @@ -1,9 +1,9 @@ -import { SelectList } from '@penumbra-zone/ui/components/ui/select-list'; +import { SelectList } from '@repo/ui/components/ui/select-list'; import { ChainRegistryClient } from '@penumbra-labs/registry'; import { AllSlices } from '../../../state'; import { useStoreShallow } from '../../../utils/use-store-shallow'; import { useMemo, useRef } from 'react'; -import { Button } from '@penumbra-zone/ui/components/ui/button'; +import { Button } from '@repo/ui/components/ui/button'; import { NewFrontendInput } from './new-frontend-input'; import { useIsFocus } from './use-is-focus'; import { extractDomain } from './extract-domain'; diff --git a/apps/extension/src/shared/components/default-frontend-form/new-frontend-input.tsx b/apps/extension/src/shared/components/default-frontend-form/new-frontend-input.tsx index bf488988..d390760e 100644 --- a/apps/extension/src/shared/components/default-frontend-form/new-frontend-input.tsx +++ b/apps/extension/src/shared/components/default-frontend-form/new-frontend-input.tsx @@ -7,8 +7,8 @@ import { useRef, useState, } from 'react'; -import { SelectList } from '@penumbra-zone/ui/components/ui/select-list'; -import { cn } from '@penumbra-zone/ui/lib/utils'; +import { SelectList } from '@repo/ui/components/ui/select-list'; +import { cn } from '@repo/ui/lib/utils'; import { isValidUrl } from '../../utils/is-valid-url'; const isValidAndNotInitial = (url: string, initialUrl?: string): boolean => { diff --git a/apps/extension/src/shared/components/grpc-endpoint-form/chain-id-or-error.tsx b/apps/extension/src/shared/components/grpc-endpoint-form/chain-id-or-error.tsx index 4c9bf61d..3e710ed3 100644 --- a/apps/extension/src/shared/components/grpc-endpoint-form/chain-id-or-error.tsx +++ b/apps/extension/src/shared/components/grpc-endpoint-form/chain-id-or-error.tsx @@ -1,4 +1,4 @@ -import { cn } from '@penumbra-zone/ui/lib/utils'; +import { cn } from '@repo/ui/lib/utils'; export const ChainIdOrError = ({ error, diff --git a/apps/extension/src/shared/components/grpc-endpoint-form/confirm-changed-chain-id-dialog.tsx b/apps/extension/src/shared/components/grpc-endpoint-form/confirm-changed-chain-id-dialog.tsx index fdf6446e..c61fb494 100644 --- a/apps/extension/src/shared/components/grpc-endpoint-form/confirm-changed-chain-id-dialog.tsx +++ b/apps/extension/src/shared/components/grpc-endpoint-form/confirm-changed-chain-id-dialog.tsx @@ -1,10 +1,10 @@ -import { Button } from '@penumbra-zone/ui/components/ui/button'; +import { Button } from '@repo/ui/components/ui/button'; import { Dialog, DialogContent, DialogDescription, DialogHeader, -} from '@penumbra-zone/ui/components/ui/dialog'; +} from '@repo/ui/components/ui/dialog'; export const ConfirmChangedChainIdDialog = ({ chainId, diff --git a/apps/extension/src/shared/components/grpc-endpoint-form/index.tsx b/apps/extension/src/shared/components/grpc-endpoint-form/index.tsx index 191b08e8..ba8b0c77 100644 --- a/apps/extension/src/shared/components/grpc-endpoint-form/index.tsx +++ b/apps/extension/src/shared/components/grpc-endpoint-form/index.tsx @@ -1,6 +1,6 @@ import { FormEvent, useRef } from 'react'; -import { SelectList } from '@penumbra-zone/ui/components/ui/select-list'; -import { Button } from '@penumbra-zone/ui/components/ui/button'; +import { SelectList } from '@repo/ui/components/ui/select-list'; +import { Button } from '@repo/ui/components/ui/button'; import { Network } from 'lucide-react'; import { useGrpcEndpointForm } from './use-grpc-endpoint-form'; import { ConfirmChangedChainIdDialog } from './confirm-changed-chain-id-dialog'; diff --git a/apps/extension/src/shared/components/link.tsx b/apps/extension/src/shared/components/link.tsx index e3239539..13073d56 100644 --- a/apps/extension/src/shared/components/link.tsx +++ b/apps/extension/src/shared/components/link.tsx @@ -1,5 +1,5 @@ import { ReactElement } from 'react'; -import { Button } from '@penumbra-zone/ui/components/ui/button'; +import { Button } from '@repo/ui/components/ui/button'; interface LinkProps { icon: ReactElement; diff --git a/apps/extension/src/shared/components/numeraires-form.tsx b/apps/extension/src/shared/components/numeraires-form.tsx index 71b1e906..7342b5c3 100644 --- a/apps/extension/src/shared/components/numeraires-form.tsx +++ b/apps/extension/src/shared/components/numeraires-form.tsx @@ -3,10 +3,10 @@ import { AllSlices, useStore } from '../../state'; import { useChainIdQuery } from '../../hooks/chain-id'; import { useMemo, useState } from 'react'; import { ServicesMessage } from '../../message/services'; -import { SelectList } from '@penumbra-zone/ui/components/ui/select-list'; +import { SelectList } from '@repo/ui/components/ui/select-list'; import { bech32mAssetId } from '@penumbra-zone/bech32m/passet'; import { getAssetId } from '@penumbra-zone/getters/metadata'; -import { Button } from '@penumbra-zone/ui/components/ui/button'; +import { Button } from '@repo/ui/components/ui/button'; import { Metadata } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; const getNumeraireFromRegistry = (chainId?: string): Metadata[] => { diff --git a/apps/extension/src/shared/components/password-input.tsx b/apps/extension/src/shared/components/password-input.tsx index ad7a8ac3..d5b80bee 100644 --- a/apps/extension/src/shared/components/password-input.tsx +++ b/apps/extension/src/shared/components/password-input.tsx @@ -1,7 +1,7 @@ import { EyeClosedIcon, EyeOpenIcon } from '@radix-ui/react-icons'; import { ReactElement, useState } from 'react'; -import { Input, InputProps } from '@penumbra-zone/ui/components/ui/input'; -import { cn } from '@penumbra-zone/ui/lib/utils'; +import { Input, InputProps } from '@repo/ui/components/ui/input'; +import { cn } from '@repo/ui/lib/utils'; import { Validation } from '../../types/utility'; import { useValidationResult } from '../../hooks/validation-result'; diff --git a/apps/extension/src/shared/containers/import-form.tsx b/apps/extension/src/shared/containers/import-form.tsx index b5fa3965..54ef37e6 100644 --- a/apps/extension/src/shared/containers/import-form.tsx +++ b/apps/extension/src/shared/containers/import-form.tsx @@ -1,7 +1,7 @@ import { SeedPhraseLength } from '@penumbra-zone/crypto-web/mnemonic'; import { useEffect } from 'react'; -import { Input } from '@penumbra-zone/ui/components/ui/input'; -import { cn } from '@penumbra-zone/ui/lib/utils'; +import { Input } from '@repo/ui/components/ui/input'; +import { cn } from '@repo/ui/lib/utils'; import { useStore } from '../../state'; import { generateSelector } from '../../state/seed-phrase/generate'; import { importSelector } from '../../state/seed-phrase/import'; diff --git a/apps/extension/src/shared/containers/word-length-toogles.tsx b/apps/extension/src/shared/containers/word-length-toogles.tsx index 00bfd18d..b1276b10 100644 --- a/apps/extension/src/shared/containers/word-length-toogles.tsx +++ b/apps/extension/src/shared/containers/word-length-toogles.tsx @@ -1,5 +1,5 @@ import { SeedPhraseLength } from '@penumbra-zone/crypto-web/mnemonic'; -import { Toggle } from '@penumbra-zone/ui/components/ui/toggle'; +import { Toggle } from '@repo/ui/components/ui/toggle'; interface WordLengthTooglesProsp { toogleClick: (length: SeedPhraseLength) => void; diff --git a/apps/extension/src/state/tx-approval.ts b/apps/extension/src/state/tx-approval.ts index e5bc681f..e40b0bb8 100644 --- a/apps/extension/src/state/tx-approval.ts +++ b/apps/extension/src/state/tx-approval.ts @@ -22,7 +22,7 @@ import { AssetId, Metadata, } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; -import { viewTransactionPlan } from '@penumbra-zone/perspective/plan/index'; +import { viewTransactionPlan } from '@penumbra-zone/perspective/plan/view-transaction-plan'; import { FullViewingKey } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb'; export interface TxApprovalSlice { diff --git a/apps/extension/src/utils/tests-setup.js b/apps/extension/src/utils/tests-setup.js index e2cbc267..7ce3bbfb 100644 --- a/apps/extension/src/utils/tests-setup.js +++ b/apps/extension/src/utils/tests-setup.js @@ -1,7 +1,4 @@ import { vi } from 'vitest'; -import withResolvers from 'promise.withresolvers'; - -withResolvers.shim(); // chrome.storage persistence middleware is run upon importing from `state/index.ts`. // For tests, this is problematic as it uses globals. This mocks those out. diff --git a/apps/extension/src/wallet-services.ts b/apps/extension/src/wallet-services.ts index 606ea7df..b2e8b7bc 100644 --- a/apps/extension/src/wallet-services.ts +++ b/apps/extension/src/wallet-services.ts @@ -8,7 +8,7 @@ import { } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb'; import { localExtStorage } from './storage/local'; import { onboardGrpcEndpoint, onboardWallet } from './storage/onboard'; -import { Services } from '@penumbra-zone/services-context'; +import { Services } from '@repo/context'; import { ServicesMessage } from './message/services'; import { WalletServices } from '@penumbra-zone/types/services'; import { AssetId } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; diff --git a/apps/extension/tailwind.config.js b/apps/extension/tailwind.config.js index c97ca2ed..2a13f7dd 100644 --- a/apps/extension/tailwind.config.js +++ b/apps/extension/tailwind.config.js @@ -1 +1 @@ -export { default } from '@penumbra-zone/tailwind-config'; +export * from '@repo/tailwind-config'; diff --git a/apps/extension/tsconfig.json b/apps/extension/tsconfig.json index 5fe576ac..5a528d05 100644 --- a/apps/extension/tsconfig.json +++ b/apps/extension/tsconfig.json @@ -1,9 +1,13 @@ { - "extends": "tsconfig/extension.json", + "extends": "@repo/tsconfig/base.json", "include": ["src/**/*.ts", "src/**/*.tsx", "*.ts"], "compilerOptions": { "outDir": "./dist", "declaration": false, - "declarationMap": false + "declarationMap": false, + "jsx": "react-jsx", + "lib": ["ESNext", "DOM", "DOM.Iterable"], + "types": ["chrome"], + "moduleResolution": "bundler" } } diff --git a/apps/extension/vitest.config.ts b/apps/extension/vitest.config.ts index 68a8604e..fd072f1f 100644 --- a/apps/extension/vitest.config.ts +++ b/apps/extension/vitest.config.ts @@ -1,10 +1,12 @@ import { defineConfig } from 'vitest/config'; -import wasm from 'vite-plugin-wasm'; -import topLevelAwait from 'vite-plugin-top-level-await'; export default defineConfig({ - plugins: [wasm(), topLevelAwait()], test: { + poolOptions: { + threads: { + execArgv: ['--experimental-wasm-modules'], + }, + }, setupFiles: ['./src/utils/tests-setup.js'], }, }); diff --git a/apps/extension/webpack.config.ts b/apps/extension/webpack.config.ts index 2a323fe2..a5062534 100644 --- a/apps/extension/webpack.config.ts +++ b/apps/extension/webpack.config.ts @@ -22,6 +22,8 @@ const definitions = { PRAX: JSON.stringify(process.env['PRAX']), PRAX_ORIGIN: JSON.stringify(`chrome-extension://${process.env['PRAX']}`), IDB_VERSION: JSON.stringify(Number(process.env['IDB_VERSION'])), + 'globalThis.__DEV__': JSON.stringify(true), + 'globalThis.__ASSERT_ROOT__': JSON.stringify(false), }; const __dirname = new URL('.', import.meta.url).pathname; @@ -66,6 +68,12 @@ const config: webpack.Configuration = { use: 'ts-loader', exclude: /node_modules/, }, + { + test: /\.m?js/, + resolve: { + fullySpecified: false, + }, + }, { test: /\.css$/i, use: [ diff --git a/apps/prax-marketing-site/eslint.config.mjs b/apps/prax-marketing-site/eslint.config.mjs index a53ed8e5..11c6ce91 100644 --- a/apps/prax-marketing-site/eslint.config.mjs +++ b/apps/prax-marketing-site/eslint.config.mjs @@ -1,4 +1,4 @@ -import { penumbraEslintConfig } from '@penumbra-zone/eslint-config'; +import { penumbraEslintConfig } from '@repo/eslint-config'; import { config, parser } from 'typescript-eslint'; export default config({ diff --git a/apps/prax-marketing-site/package.json b/apps/prax-marketing-site/package.json index 53b596c1..840a2943 100644 --- a/apps/prax-marketing-site/package.json +++ b/apps/prax-marketing-site/package.json @@ -10,15 +10,12 @@ "lint": "eslint ." }, "dependencies": { - "@vitejs/plugin-react-swc": "^3.6.0", "react": "^18.3.1", "react-dom": "^18.3.1", "react-router-dom": "^6.23.1", - "tailwindcss": "^3.4.3" + "tailwindcss": "^3.4.4" }, "devDependencies": { - "@penumbra-zone/eslint-config": "workspace:*", - "@penumbra-zone/tailwind-config": "workspace:*", "@types/react": "^18.3.2", "@types/react-dom": "^18.3.0", "autoprefixer": "^10.4.19", diff --git a/apps/prax-marketing-site/tailwind.config.js b/apps/prax-marketing-site/tailwind.config.js index c97ca2ed..2a13f7dd 100644 --- a/apps/prax-marketing-site/tailwind.config.js +++ b/apps/prax-marketing-site/tailwind.config.js @@ -1 +1 @@ -export { default } from '@penumbra-zone/tailwind-config'; +export * from '@repo/tailwind-config'; diff --git a/apps/prax-marketing-site/tsconfig.json b/apps/prax-marketing-site/tsconfig.json index 4f38a350..aca2837c 100644 --- a/apps/prax-marketing-site/tsconfig.json +++ b/apps/prax-marketing-site/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "tsconfig/vite.json", + "extends": "@repo/tsconfig/vite.json", "include": ["src", "*.ts", "__mocks__", "eslint.config.mjs"], "exclude": ["node_modules"] } diff --git a/package.json b/package.json index 79048acb..0ab57151 100644 --- a/package.json +++ b/package.json @@ -1,15 +1,14 @@ { - "name": "penumbra-web", + "name": "prax-wallet", "private": true, "license": "(MIT OR Apache-2.0)", - "repository": "penumbra-zone/web.git", "packageManager": "pnpm@9.1.2", "scripts": { "all-check": "pnpm clean && pnpm install && pnpm compile && pnpm lint && pnpm lint:rust && pnpm build && pnpm test && pnpm test:rust", "buf-update": "pnpm update --latest \"@buf/*\" \"@bufbuild/*\" \"@connectrpc/*\" && pnpm syncpack fix-mismatches && pnpm install", "build": "turbo build", "clean": "turbo clean", - "clean-modules": "rm -rf node_modules apps/*/node_modules packages/*/node_modules pnpm-lock.yaml", + "clean:modules": "rm -rf node_modules apps/*/node_modules packages/*/node_modules pnpm-lock.yaml", "clean:vitest-mjs": "find . -type f -name 'vite*.config.ts.timestamp-*-*.mjs' -ls -delete", "compile": "turbo compile", "dev": "turbo dev", @@ -27,43 +26,36 @@ "test:rust": "turbo test:rust" }, "dependencies": { - "@buf/cosmos_ibc.bufbuild_es": "1.9.0-20240530142100-ad4444393387.1", - "@buf/cosmos_ibc.connectrpc_es": "1.4.0-20240530142100-ad4444393387.2", - "@buf/penumbra-zone_penumbra.bufbuild_es": "1.9.0-20240528180215-8fe1c79485f8.1", - "@buf/penumbra-zone_penumbra.connectrpc_es": "1.4.0-20240528180215-8fe1c79485f8.2", - "@buf/tendermint_tendermint.bufbuild_es": "1.9.0-20231117195010-33ed361a9051.1", + "@buf/cosmos_ibc.bufbuild_es": "1.10.0-20240606104028-442292b00c16.1", + "@buf/cosmos_ibc.connectrpc_es": "1.4.0-20240606104028-442292b00c16.3", + "@buf/penumbra-zone_penumbra.bufbuild_es": "1.10.0-20240616005217-ca45ca80333e.1", + "@buf/penumbra-zone_penumbra.connectrpc_es": "1.4.0-20240616005217-ca45ca80333e.3", + "@buf/tendermint_tendermint.bufbuild_es": "1.10.0-20231117195010-33ed361a9051.1", "@bufbuild/protobuf": "^1.10.0", "@connectrpc/connect": "^1.4.0", - "@connectrpc/connect-web": "^1.4.0", - "@penumbra-zone/keys": "workspace:*" + "@connectrpc/connect-web": "^1.4.0" }, "devDependencies": { - "@buf/connectrpc_eliza.bufbuild_es": "1.9.0-20230913231627-233fca715f49.1", - "@buf/connectrpc_eliza.connectrpc_es": "1.4.0-20230913231627-233fca715f49.2", - "@changesets/cli": "^2.27.3", - "@penumbra-zone/eslint-config": "workspace:*", - "@penumbra-zone/tailwind-config": "workspace:*", - "@penumbra-zone/wasm": "workspace:*", + "@buf/connectrpc_eliza.bufbuild_es": "1.10.0-20230913231627-233fca715f49.1", + "@buf/connectrpc_eliza.connectrpc_es": "1.4.0-20230913231627-233fca715f49.3", + "@changesets/cli": "^2.27.5", + "@repo/eslint-config": "workspace:*", + "@repo/tailwind-config": "workspace:*", + "@repo/tsconfig": "workspace:*", "@storybook/react-vite": "8.1.1", - "@turbo/gen": "^1.13.3", + "@turbo/gen": "^1.13.4", "@types/chrome": "0.0.268", - "@types/node": "^20.12.12", - "@vitejs/plugin-basic-ssl": "^1.1.0", - "@vitejs/plugin-react": "^4.2.1", - "@vitejs/plugin-react-swc": "^3.6.0", + "@types/node": "^20.14.5", + "@vitejs/plugin-react-swc": "^3.7.0", "@vitest/browser": "^1.6.0", - "jsdom": "^24.0.0", - "playwright": "^1.44.0", - "prettier": "^3.2.5", - "react": "^18.3.1", + "jsdom": "^24.1.0", + "playwright": "^1.44.1", + "prettier": "^3.3.2", "syncpack": "^12.3.2", - "tailwindcss": "^3.4.3", - "tsconfig": "workspace:*", - "turbo": "^1.13.3", + "tailwindcss": "^3.4.4", + "turbo": "^1.13.4", "typescript": "^5.4.5", - "vite": "^5.2.11", - "vite-plugin-dts": "^3.9.1", - "vite-plugin-externalize-deps": "^0.8.0", + "vite": "^5.3.1", "vite-plugin-top-level-await": "^1.4.1", "vite-plugin-wasm": "^3.3.0", "vitest": "^1.6.0" diff --git a/packages/bech32m/.npmignore b/packages/bech32m/.npmignore deleted file mode 100644 index f1bfb1e1..00000000 --- a/packages/bech32m/.npmignore +++ /dev/null @@ -1,3 +0,0 @@ -.turbo -src -.eslintrc.cjs diff --git a/packages/bech32m/CHANGELOG.md b/packages/bech32m/CHANGELOG.md deleted file mode 100644 index 9c77a7aa..00000000 --- a/packages/bech32m/CHANGELOG.md +++ /dev/null @@ -1,49 +0,0 @@ -# @penumbra-zone/bech32 - -## 5.0.0 - -### Major Changes - -- 8fe4de6: correct ordering of default export - -## 4.0.0 - -### Major Changes - -- 8b121ec: change package exports to use 'default' field - -## 3.2.0 - -### Minor Changes - -- 3ea1e6c: update buf types dependencies - -## 3.1.1 - -### Patch Changes - -- e35c6f7: Deps bumped to latest - -## 3.1.0 - -### Minor Changes - -- v8.0.0 versioning and manifest - -## 3.0.1 - -### Patch Changes - -- 8410d2f: dependency version bump - -## 3.0.0 - -### Major Changes - -- fdd4303: new package to replace `@penumbra-zone/bech32`. validation is much more complete and correct - -## 2.0.0 - -### Major Changes - -- 929d278: barrel imports to facilitate better tree shaking diff --git a/packages/bech32m/README.md b/packages/bech32m/README.md deleted file mode 100644 index 710475ad..00000000 --- a/packages/bech32m/README.md +++ /dev/null @@ -1,113 +0,0 @@ -# `@penumbra-zone/bech32m` - -This package is for validating and manipulating bech32m strings relevant to the -Penumbra blockchain. - -- validate bech32m strings, including checksums -- enforce expected lengths of input and output -- convert back and forth between string and binary representations - -## Simple use - -It is recommended to use the typed functions provided in the submodules, each -named after the relevant prefix. - -```ts -import { fullViewingKeyFromBech32m } from '@penumbra-zone/bech32m/penumbrafullviewingkey'; -import { bech32mIdentityKey } from '@penumbra-zone/bech32m/penumbravalid'; - -// typical use -const fvk: { inner: Uint8Array } = fullViewingKeyFromBech32m( - 'penumbrafullviewingkey1vzfytwlvq067g2kz095vn7sgcft47hga40atrg5zu2crskm6tyyjysm28qg5nth2fqmdf5n0q530jreumjlsrcxjwtfv6zdmfpe5kqsa5lg09i', -); - -// will throw -const badFvk: { inner: Uint8Array } = fullViewingKeyFromBech32m('penumbrafullviewingkey1badinput'); - -// will succeed, but this all-zero key identifies nothing -const validator: string = bech32mIdentityKey({ ik: new Uint8Array(32) }); -``` - -## Typical use - -If you're working with Penumbra bech32m strings, there's a good chance you also -want to use our protobuf message types. The buf registry package -`@buf/penumbra-zone_penumbra.bufbuild_es` is a peer dependency. - -Exported functions do not explicitly refer to those types, in order to permit -production use without bundling the definitions, but all input/output will -satisfy the relevant structures. - -```ts -import { assetIdFromBech32m } from '@penumbra-zone/bech32m/passet'; -import { plpidFromBech32m } from '@penumbra-zone/bech32m/plpid'; -import { spendKeyFromBech32m } from '@penumbra-zone/bech32m/penumbraspendkey'; - -import type { PlainMessage, PartialMessage } from '@bufbuild/protobuf'; -import type { AssetId } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; -import type { PositionId } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/dex/v1/dex_pb'; -import { SpendKey } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb'; - -const plainAssetId: PlainMessage = assetIdFromBech32m( - 'passet1vhga2czmpk76hsu3t7usjj2a2qga0u29vqlcp3hky8lwkfz30qrqy6gaae', -); - -const partialPositionId: PartialMessage = plpidFromBech32( - 'plpid1fkf3tlv500vgzwc6dkc7g9wnuv6rzezhefefdywq5tt4lyl97rgsd6j689', -); - -// you must explicitly construct the object if you want to use functions -// available on the @bufbuild/protobuf Message class - -const realSpendKey: SpendKey = new SpendKey( - spendKeyFromBech32m( - 'penumbraspendkey1qul0huewkcmemljd5m3vz3awqt7442tjg2dudahvzu6eyj9qf0eszrnguh', - ), -); - -// marshal to protojson -realSpendKey.toJson(); -// { "inner": "Bz778y62N53+TabiwUeuAv1aqXJCm8b27Bc1kkigS/M=" } - -// true -realSpendKey.equals({ - inner: new Uint8Array([ - 0x07, 0x3e, 0xfb, 0xf3, 0x2e, 0xb6, 0x37, 0x9d, 0xfe, 0x4d, 0xa6, 0xe2, 0xc1, 0x47, 0xae, 0x02, - 0xfd, 0x5a, 0xa9, 0x72, 0x42, 0x9b, 0xc6, 0xf6, 0xec, 0x17, 0x35, 0x92, 0x48, 0xa0, 0x4b, 0xf3, - ]), -}); -``` - -## Constants only - -If you already have a validation solution and just need the parameters, you can -import simple constants from the main module. This technique should bundle very -small. - -```js -import { - PENUMBRA_BECH32M_ADDRESS_LENGTH as pnLength, - PENUMBRA_BECH32M_ADDRESS_PREFIX as pnPrefix, -} from '@penumbra-zone/bech32m'; - -// matches prefix, length, and valid charset. no checksum validation. -export const addressRegex = new RegEx( - `^${pnPrefix}1[02-9ac-hj-np-z]{${pnLength - (pnPrefix.length + 1)}}$`, -); -``` - -## penumbracompat1 is bech32, not bech32m - -For IBC compatibility, we provide a `penumbracompat1` address format that is -bech32 instead of bech32m. You can use `penumbracompat1` when interacting with -any chain that does not support a bech32m destination. - -```ts -import { bech32Address } from '@penumbra-zone/bech32m/penumbra'; -import { bech32CompatAddress } from '@penumbra-zone/bech32m/penumbracompat1'; - -const bech32Chains = ['noble', 'nobletestnet']; -const getCompatibleAddress = (chainName: string, address: { inner: Uint8Array }): string => { - return bech32Chains.includes(chainName) ? bech32CompatAddress(address) : bech32mAddress(address); -}; -``` diff --git a/packages/bech32m/eslint.config.mjs b/packages/bech32m/eslint.config.mjs deleted file mode 100644 index a53ed8e5..00000000 --- a/packages/bech32m/eslint.config.mjs +++ /dev/null @@ -1,13 +0,0 @@ -import { penumbraEslintConfig } from '@penumbra-zone/eslint-config'; -import { config, parser } from 'typescript-eslint'; - -export default config({ - ...penumbraEslintConfig, - languageOptions: { - parser, - parserOptions: { - project: true, - tsconfigRootDir: import.meta.dirname, - }, - }, -}); diff --git a/packages/bech32m/package.json b/packages/bech32m/package.json deleted file mode 100644 index a83433df..00000000 --- a/packages/bech32m/package.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "name": "@penumbra-zone/bech32m", - "version": "5.0.0", - "private": true, - "license": "(MIT OR Apache-2.0)", - "description": "Tools for manipulating Penumbra bech32m strings", - "type": "module", - "scripts": { - "build": "tsc --build", - "clean": "rm -rfv dist", - "lint": "eslint src", - "test": "vitest run" - }, - "files": [ - "./dist" - ], - "exports": { - ".": "./src/index.ts", - "./*": "./src/*.ts" - }, - "publishConfig": { - "exports": { - ".": { - "types": "./dist/index.d.ts", - "default": "./dist/index.js" - }, - "./*": { - "types": "./dist/*.d.ts", - "default": "./dist/*.js" - } - } - }, - "dependencies": { - "bech32": "^2.0.0" - }, - "devDependencies": { - "@buf/penumbra-zone_penumbra.bufbuild_es": "1.9.0-20240528180215-8fe1c79485f8.1" - }, - "peerDependencies": { - "@buf/penumbra-zone_penumbra.bufbuild_es": "1.9.0-20240528180215-8fe1c79485f8.1" - } -} diff --git a/packages/bech32m/src/format/bytes.ts b/packages/bech32m/src/format/bytes.ts deleted file mode 100644 index 524dd50e..00000000 --- a/packages/bech32m/src/format/bytes.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { Prefix } from './prefix'; - -export const ByteLength = { - passet: 32, - pauctid: 32, - penumbra: 80, - penumbracompat1: 80, - penumbrafullviewingkey: 64, - penumbragovern: 32, - penumbraspendkey: 32, - penumbravalid: 32, - penumbrawalletid: 32, - plpid: 32, -} as const satisfies Required>; diff --git a/packages/bech32m/src/format/convert.ts b/packages/bech32m/src/format/convert.ts deleted file mode 100644 index 6112b169..00000000 --- a/packages/bech32m/src/format/convert.ts +++ /dev/null @@ -1,143 +0,0 @@ -import { bech32, bech32m, BechLib } from 'bech32'; -import { StringLength } from './strings'; -import { ByteLength } from './bytes'; -import { Prefix } from './prefix'; - -/** - * Internal use. Converts a valid bech32m string of spec format to a byte array, - * throwing on invalid input. - * - * @param b32mStr input string - * @param prefix verified or detected input prefix - * @returns byte array of spec length - */ -export const fromBech32m =

( - b32mStr: `${P}1${string}`, - prefix: Prefix = b32mStr.slice(0, b32mStr.lastIndexOf('1')) as P, -): Uint8Array => { - return fromBechWithLib(b32mStr, prefix, bech32m); -}; - -/** - * Similar to above, but used to convert from Bech32 for compatibility reasons. - * - * @param b32mStr input string - * @param prefix verified or detected input prefix - * @returns byte array of spec length - */ -export const fromBech32 =

( - b32mStr: `${P}1${string}`, - prefix: Prefix = b32mStr.slice(0, b32mStr.lastIndexOf('1')) as P, -): Uint8Array => { - return fromBechWithLib(b32mStr, prefix, bech32); -}; - -const fromBechWithLib =

( - b32mStr: `${P}1${string}`, - prefix: Prefix, - bechLib: BechLib, -): Uint8Array => { - const p = b32mStr.slice(0, b32mStr.lastIndexOf('1')); - if (p !== prefix) throw new TypeError(`Unexpected prefix: expected ${prefix}, got ${p}`); - return from({ - bechLib: bechLib, - b32mStr, - expectPrefix: p, - expectLength: StringLength[p], - expectBytes: ByteLength[p], - }); -}; - -/** - * Internal use. Converts a byte array to a valid bech32m string of spec format, - * throwing on invalid input. - * - * @param bData input bytes - * @param prefix known prefix in spec - * @returns bech32m string of spec format - */ -export const toBech32m =

(bData: Uint8Array, prefix: P): `${P}1${string}` => - to({ - bechLib: bech32m, - bData, - prefix, - expectLength: StringLength[prefix], - expectBytes: ByteLength[prefix], - }); - -/** - * Similar to above, but used to convert to Bech32 for compatibility reasons. - * - * @param bData input bytes - * @param prefix known prefix in spec - * @returns bech32 string of spec format - */ -export const toBech32 =

(bData: Uint8Array, prefix: P): `${P}1${string}` => - to({ - bechLib: bech32, - bData, - prefix, - expectLength: StringLength[prefix], - expectBytes: ByteLength[prefix], - }); - -interface FromParams { - bechLib: BechLib; // Lib doing decoding - b32mStr: string; // input string - expectPrefix: string; // verify input prefix - expectLength: number; // verify input length - expectBytes: number; // expected output length -} - -/** - * Internal use. Converts a bech32m string to a byte array. Verifies the prefix, - * input string length, and output byte length. - * - * @returns byte array of length `expectBytes` - */ -const from = ({ - bechLib, - b32mStr, - expectPrefix, - expectLength, - expectBytes, -}: FromParams): Uint8Array => { - if (b32mStr.length !== expectLength) { - throw new TypeError(`Invalid string length: expected ${expectLength}, got ${b32mStr.length}`); - } - - const { prefix, words } = bechLib.decode(b32mStr, expectLength); - if (prefix !== expectPrefix) throw new TypeError('Wrong prefix'); - const bytes = new Uint8Array(bechLib.fromWords(words)); - if (bytes.length !== expectBytes) throw new TypeError('Unexpected data length'); - return bytes; -}; - -interface ToParams

{ - bechLib: BechLib; // Lib doing encoding - bData: Uint8Array; // input bytes - prefix: P; // string to use as prefix - expectLength: number; // expected output length, including prefix - expectBytes: number; // verify input byte length -} - -/** - * Internal use. Converts a byte array to a bech32m string with specified - * prefix. Verifies input byte length and output string length. - * - * @returns bech32m with prefix and length `expectLength` - */ -const to =

({ - bechLib, - bData, - prefix, - expectLength, - expectBytes, -}: ToParams

): `${P}1${string}` => { - if (bData.length !== expectBytes) { - throw new TypeError(`Invalid data length: expected ${expectBytes}, got ${bData.length}`); - } - const bStr = bechLib.encode(prefix, bechLib.toWords(bData), expectLength); - if (bStr.length !== expectLength) throw new TypeError('Unexpected string length'); - return bStr as `${P}1${string}`; -}; diff --git a/packages/bech32m/src/format/index.ts b/packages/bech32m/src/format/index.ts deleted file mode 100644 index d40e0a69..00000000 --- a/packages/bech32m/src/format/index.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { Inner } from './inner'; -import { StringLength } from './strings'; -import { ByteLength } from './bytes'; -import { Prefix, Prefixes } from './prefix'; - -type PenumbraBech32mSpec = Required<{ - readonly [p in Prefix]: { - readonly prefix: (typeof Prefixes)[p]; - readonly stringLength: (typeof StringLength)[p]; - readonly byteLength: (typeof ByteLength)[p]; - readonly innerName: (typeof Inner)[p]; - }; -}>; - -export default { - passet: { - prefix: Prefixes.passet, - stringLength: StringLength.passet, - byteLength: ByteLength.passet, - innerName: Inner.passet, - }, - pauctid: { - prefix: Prefixes.pauctid, - stringLength: StringLength.pauctid, - byteLength: ByteLength.pauctid, - innerName: Inner.pauctid, - }, - penumbra: { - prefix: Prefixes.penumbra, - stringLength: StringLength.penumbra, - byteLength: ByteLength.penumbra, - innerName: Inner.penumbra, - }, - penumbracompat1: { - prefix: Prefixes.penumbracompat1, - stringLength: StringLength.penumbracompat1, - byteLength: ByteLength.penumbracompat1, - innerName: Inner.penumbracompat1, - }, - penumbrafullviewingkey: { - prefix: Prefixes.penumbrafullviewingkey, - stringLength: StringLength.penumbrafullviewingkey, - byteLength: ByteLength.penumbrafullviewingkey, - innerName: Inner.penumbrafullviewingkey, - }, - penumbragovern: { - prefix: Prefixes.penumbragovern, - stringLength: StringLength.penumbragovern, - byteLength: ByteLength.penumbragovern, - innerName: Inner.penumbragovern, - }, - penumbraspendkey: { - prefix: Prefixes.penumbraspendkey, - stringLength: StringLength.penumbraspendkey, - byteLength: ByteLength.penumbraspendkey, - innerName: Inner.penumbraspendkey, - }, - penumbravalid: { - prefix: Prefixes.penumbravalid, - stringLength: StringLength.penumbravalid, - byteLength: ByteLength.penumbravalid, - innerName: Inner.penumbravalid, - }, - penumbrawalletid: { - prefix: Prefixes.penumbrawalletid, - stringLength: StringLength.penumbrawalletid, - byteLength: ByteLength.penumbrawalletid, - innerName: Inner.penumbrawalletid, - }, - plpid: { - prefix: Prefixes.plpid, - stringLength: StringLength.plpid, - byteLength: ByteLength.plpid, - innerName: Inner.plpid, - }, -} as const satisfies PenumbraBech32mSpec; diff --git a/packages/bech32m/src/format/inner.test.ts b/packages/bech32m/src/format/inner.test.ts deleted file mode 100644 index 36ba0e6d..00000000 --- a/packages/bech32m/src/format/inner.test.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { AssetId } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; -import { PositionId } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/dex/v1/dex_pb'; -import { - Address, - FullViewingKey, - GovernanceKey, - IdentityKey, - SpendKey, - WalletId, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb'; -import { describe, expect, test } from 'vitest'; -import { Inner } from './inner'; - -describe('The expected inner field exists on the actual types', () => { - test('passet inner', () => { - const passet = new AssetId(); - expect(passet[Inner.passet]).toBeDefined(); - }); - - test('address inner', () => { - const address = new Address(); - expect(address[Inner.penumbra]).toBeDefined(); - }); - - test('full viewing key inner', () => { - const fullViewingKey = new FullViewingKey(); - expect(fullViewingKey[Inner.penumbrafullviewingkey]).toBeDefined(); - }); - - test('spend key inner', () => { - const spendKey = new SpendKey(); - expect(spendKey[Inner.penumbraspendkey]).toBeDefined(); - }); - - test('governance key gk', () => { - const governanceKey = new GovernanceKey(); - expect(governanceKey[Inner.penumbragovern]).toBeDefined(); - }); - - test('validatorid key ik', () => { - const validatorId = new IdentityKey(); - expect(validatorId[Inner.penumbravalid]).toBeDefined(); - }); - - test('lp id inner', () => { - const positionId = new PositionId(); - expect(positionId[Inner.plpid]).toBeDefined(); - }); - - test('wallet id inner', () => { - const walletId = new WalletId(); - expect(walletId[Inner.penumbrawalletid]).toBeDefined(); - }); -}); diff --git a/packages/bech32m/src/format/inner.ts b/packages/bech32m/src/format/inner.ts deleted file mode 100644 index 340a91d5..00000000 --- a/packages/bech32m/src/format/inner.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { Prefix } from './prefix'; - -export const Inner = { - passet: 'inner', - pauctid: 'inner', - penumbra: 'inner', - penumbracompat1: 'inner', - penumbrafullviewingkey: 'inner', - penumbragovern: 'gk', - penumbraspendkey: 'inner', - penumbravalid: 'ik', - penumbrawalletid: 'inner', - plpid: 'inner', -} as const satisfies Required>; diff --git a/packages/bech32m/src/format/lengths.test.ts b/packages/bech32m/src/format/lengths.test.ts deleted file mode 100644 index 72757e20..00000000 --- a/packages/bech32m/src/format/lengths.test.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { describe, expect, test } from 'vitest'; -import { Prefix } from './prefix'; -import { StringLength } from './strings'; -import { ByteLength } from './bytes'; - -const bech32Length = (prefix: string, byteSize: number) => - prefix.length + - 1 + // separator is '1' - Math.ceil( - (8 / 5) * byteSize, - // ratio of 8bits/byte to 5bits/char - // ceil to whole number of chars - ) + - 6; // checksum is 6 chars - -describe('length', () => { - test('recorded byte sizes are correctly calculated from the recorded string sizes', () => - Object.entries(ByteLength).map(([prefix, byteLength]) => - expect(bech32Length(prefix, byteLength)).toBe(StringLength[prefix as Prefix]), - )); -}); diff --git a/packages/bech32m/src/format/prefix.ts b/packages/bech32m/src/format/prefix.ts deleted file mode 100644 index bc89718f..00000000 --- a/packages/bech32m/src/format/prefix.ts +++ /dev/null @@ -1,14 +0,0 @@ -export const Prefixes = { - passet: 'passet', - pauctid: 'pauctid', - penumbra: 'penumbra', - penumbracompat1: 'penumbracompat1', - penumbrafullviewingkey: 'penumbrafullviewingkey', - penumbragovern: 'penumbragovern', - penumbraspendkey: 'penumbraspendkey', - penumbravalid: 'penumbravalid', - penumbrawalletid: 'penumbrawalletid', - plpid: 'plpid', -} as const; - -export type Prefix = keyof typeof Prefixes; diff --git a/packages/bech32m/src/format/strings.ts b/packages/bech32m/src/format/strings.ts deleted file mode 100644 index cd1ed0c9..00000000 --- a/packages/bech32m/src/format/strings.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { Prefix } from './prefix'; - -export const StringLength = { - passet: 65, - pauctid: 66, - penumbra: 143, - penumbracompat1: 150, - penumbrafullviewingkey: 132, - penumbragovern: 73, - penumbraspendkey: 75, - penumbravalid: 72, - penumbrawalletid: 75, - plpid: 64, -} as const satisfies Required>; diff --git a/packages/bech32m/src/index.ts b/packages/bech32m/src/index.ts deleted file mode 100644 index 4091e148..00000000 --- a/packages/bech32m/src/index.ts +++ /dev/null @@ -1,30 +0,0 @@ -import SPEC from './format'; - -export default SPEC; - -export const PENUMBRA_BECH32M_ADDRESS_LENGTH = SPEC.penumbra.stringLength; -export const PENUMBRA_BECH32M_ADDRESS_PREFIX = SPEC.penumbra.prefix; - -export const PENUMBRA_BECH32M_ASSETID_LENGTH = SPEC.passet.stringLength; -export const PENUMBRA_BECH32M_ASSETID_PREFIX = SPEC.passet.prefix; - -export const PENUMBRA_BECH32M_AUCTION_LENGTH = SPEC.pauctid.stringLength; -export const PENUMBRA_BECH32M_AUCTION_PREFIX = SPEC.pauctid.prefix; - -export const PENUMBRA_BECH32M_FULLVIEWINGKEY_LENGTH = SPEC.penumbrafullviewingkey.stringLength; -export const PENUMBRA_BECH32M_FULLVIEWINGKEY_PREFIX = SPEC.penumbrafullviewingkey.prefix; - -export const PENUMBRA_BECH32M_GOVERNANCEID_LENGTH = SPEC.penumbragovern.stringLength; -export const PENUMBRA_BECH32M_GOVERNANCEID_PREFIX = SPEC.penumbragovern.prefix; - -export const PENUMBRA_BECH32M_SPENDKEY_LENGTH = SPEC.penumbraspendkey.stringLength; -export const PENUMBRA_BECH32M_SPENDKEY_PREFIX = SPEC.penumbraspendkey.prefix; - -export const PENUMBRA_BECH32M_IDENTITYKEY_LENGTH = SPEC.penumbravalid.stringLength; -export const PENUMBRA_BECH32M_IDENTITYKEY_PREFIX = SPEC.penumbravalid.prefix; - -export const PENUMBRA_BECH32M_WALLETID_LENGTH = SPEC.penumbrawalletid.stringLength; -export const PENUMBRA_BECH32M_WALLETID_PREFIX = SPEC.penumbrawalletid.prefix; - -export const PENUMBRA_BECH32M_POSITIONID_LENGTH = SPEC.plpid.stringLength; -export const PENUMBRA_BECH32M_POSITIONID_PREFIX = SPEC.plpid.prefix; diff --git a/packages/bech32m/src/passet.ts b/packages/bech32m/src/passet.ts deleted file mode 100644 index b777b421..00000000 --- a/packages/bech32m/src/passet.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { fromBech32m, toBech32m } from './format/convert'; -import { Inner } from './format/inner'; -import { Prefixes } from './format/prefix'; - -const innerName = Inner.passet; -const prefix = Prefixes.passet; - -export const bech32mAssetId = ({ [innerName]: bytes }: { [innerName]: Uint8Array }) => - toBech32m(bytes, prefix); - -export const assetIdFromBech32m = (passet1: string): { [innerName]: Uint8Array } => ({ - [innerName]: fromBech32m(passet1 as `${typeof prefix}1${string}`, prefix), -}); - -export const isAssetId = (check: string): check is `${typeof prefix}1${string}` => { - try { - assetIdFromBech32m(check); - return true; - } catch { - return false; - } -}; - -export { PENUMBRA_BECH32M_ASSETID_LENGTH, PENUMBRA_BECH32M_ASSETID_PREFIX } from '.'; diff --git a/packages/bech32m/src/pauctid.ts b/packages/bech32m/src/pauctid.ts deleted file mode 100644 index d45faf52..00000000 --- a/packages/bech32m/src/pauctid.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { fromBech32m, toBech32m } from './format/convert'; -import { Inner } from './format/inner'; -import { Prefixes } from './format/prefix'; - -const innerName = Inner.pauctid; -const prefix = Prefixes.pauctid; - -export const bech32mAuctionId = ({ [innerName]: bytes }: { [innerName]: Uint8Array }) => - toBech32m(bytes, prefix); - -export const auctionIdFromBech32 = (pauctid1: string): { [innerName]: Uint8Array } => ({ - [innerName]: fromBech32m(pauctid1 as `${typeof prefix}1${string}`, prefix), -}); - -export const isAuctionId = (check: string): check is `${typeof prefix}1${string}` => { - try { - auctionIdFromBech32(check); - return true; - } catch { - return false; - } -}; - -export { PENUMBRA_BECH32M_AUCTION_LENGTH, PENUMBRA_BECH32M_AUCTION_PREFIX } from '.'; diff --git a/packages/bech32m/src/penumbra.ts b/packages/bech32m/src/penumbra.ts deleted file mode 100644 index ce6d45c3..00000000 --- a/packages/bech32m/src/penumbra.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { fromBech32m, toBech32m } from './format/convert'; -import { Inner } from './format/inner'; -import { Prefixes } from './format/prefix'; - -const innerName = Inner.penumbra; -const prefix = Prefixes.penumbra; - -export const bech32mAddress = ({ [innerName]: bytes }: { [innerName]: Uint8Array }) => - toBech32m(bytes, prefix); - -export const addressFromBech32m = (penumbra1: string): { [innerName]: Uint8Array } => ({ - [innerName]: fromBech32m(penumbra1 as `${typeof prefix}1${string}`, prefix), -}); - -export const isAddress = (check: string): check is `${typeof prefix}1${string}` => { - try { - addressFromBech32m(check); - return true; - } catch { - return false; - } -}; - -export { PENUMBRA_BECH32M_ADDRESS_LENGTH, PENUMBRA_BECH32M_ADDRESS_PREFIX } from '.'; diff --git a/packages/bech32m/src/penumbracompat1.ts b/packages/bech32m/src/penumbracompat1.ts deleted file mode 100644 index 8a36ccb5..00000000 --- a/packages/bech32m/src/penumbracompat1.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { fromBech32, toBech32 } from './format/convert'; -import { Inner } from './format/inner'; -import { Prefixes } from './format/prefix'; - -const innerName = Inner.penumbracompat1; -const prefix = Prefixes.penumbracompat1; - -export const bech32CompatAddress = ({ [innerName]: bytes }: { [innerName]: Uint8Array }) => - toBech32(bytes, prefix); - -export const compatAddressFromBech32 = (penumbracompat1: string): { [innerName]: Uint8Array } => ({ - [innerName]: fromBech32(penumbracompat1 as `${typeof prefix}1${string}`, prefix), -}); - -export { PENUMBRA_BECH32M_ADDRESS_LENGTH, PENUMBRA_BECH32M_ADDRESS_PREFIX } from '.'; diff --git a/packages/bech32m/src/penumbrafullviewingkey.ts b/packages/bech32m/src/penumbrafullviewingkey.ts deleted file mode 100644 index cd589333..00000000 --- a/packages/bech32m/src/penumbrafullviewingkey.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { fromBech32m, toBech32m } from './format/convert'; -import { Inner } from './format/inner'; -import { Prefixes } from './format/prefix'; - -const innerName = Inner.penumbrafullviewingkey; -const prefix = Prefixes.penumbrafullviewingkey; - -export const bech32mFullViewingKey = ({ [innerName]: bytes }: { [innerName]: Uint8Array }) => - toBech32m(bytes, prefix); - -export const fullViewingKeyFromBech32m = ( - penumbrafullviewingkey1: string, -): { [innerName]: Uint8Array } => ({ - [innerName]: fromBech32m(penumbrafullviewingkey1 as `${typeof prefix}1${string}`, prefix), -}); - -export const isFullViewingKey = (check: string): check is `${typeof prefix}1${string}` => { - try { - fullViewingKeyFromBech32m(check); - return true; - } catch { - return false; - } -}; - -export { PENUMBRA_BECH32M_FULLVIEWINGKEY_LENGTH, PENUMBRA_BECH32M_FULLVIEWINGKEY_PREFIX } from '.'; diff --git a/packages/bech32m/src/penumbragovern.ts b/packages/bech32m/src/penumbragovern.ts deleted file mode 100644 index b8608205..00000000 --- a/packages/bech32m/src/penumbragovern.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { fromBech32m, toBech32m } from './format/convert'; -import { Inner } from './format/inner'; -import { Prefixes } from './format/prefix'; - -const innerName = Inner.penumbragovern; -const prefix = Prefixes.penumbragovern; - -export const bech32mGovernanceId = ({ [innerName]: bytes }: { [innerName]: Uint8Array }) => - toBech32m(bytes, prefix); - -export const governanceIdFromBech32 = (penumbragovern1: string): { [innerName]: Uint8Array } => ({ - [innerName]: fromBech32m(penumbragovern1 as `${typeof prefix}1${string}`, prefix), -}); - -export const isGovernanceId = (check: string): check is `${typeof prefix}1${string}` => { - try { - governanceIdFromBech32(check); - return true; - } catch { - return false; - } -}; - -export { PENUMBRA_BECH32M_GOVERNANCEID_LENGTH, PENUMBRA_BECH32M_GOVERNANCEID_PREFIX } from '.'; diff --git a/packages/bech32m/src/penumbraspendkey.ts b/packages/bech32m/src/penumbraspendkey.ts deleted file mode 100644 index 5360e7a4..00000000 --- a/packages/bech32m/src/penumbraspendkey.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { fromBech32m, toBech32m } from './format/convert'; -import { Inner } from './format/inner'; -import { Prefixes } from './format/prefix'; - -const innerName = Inner.penumbraspendkey; -const prefix = Prefixes.penumbraspendkey; - -export const bech32mSpendKey = ({ [innerName]: bytes }: { [innerName]: Uint8Array }) => - toBech32m(bytes, prefix); - -export const spendKeyFromBech32m = (penumbraspendkey1: string): { [innerName]: Uint8Array } => ({ - [innerName]: fromBech32m(penumbraspendkey1 as `${typeof prefix}1${string}`, prefix), -}); - -export const isSpendKey = (check: string): check is `${typeof prefix}1${string}` => { - try { - spendKeyFromBech32m(check); - return true; - } catch { - return false; - } -}; - -export { PENUMBRA_BECH32M_SPENDKEY_LENGTH, PENUMBRA_BECH32M_SPENDKEY_PREFIX } from '.'; diff --git a/packages/bech32m/src/penumbravalid.ts b/packages/bech32m/src/penumbravalid.ts deleted file mode 100644 index 694abe9a..00000000 --- a/packages/bech32m/src/penumbravalid.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { fromBech32m, toBech32m } from './format/convert'; -import { Inner } from './format/inner'; -import { Prefixes } from './format/prefix'; - -const innerName = Inner.penumbravalid; -const prefix = Prefixes.penumbravalid; - -export const bech32mIdentityKey = ({ [innerName]: bytes }: { [innerName]: Uint8Array }) => - toBech32m(bytes, prefix); - -export const identityKeyFromBech32m = (penumbravalid1: string): { [innerName]: Uint8Array } => ({ - [innerName]: fromBech32m(penumbravalid1 as `${typeof prefix}1${string}`, prefix), -}); - -export const isIdentityKey = (check: string): check is `${typeof prefix}1${string}` => { - try { - identityKeyFromBech32m(check); - return true; - } catch { - return false; - } -}; - -export { PENUMBRA_BECH32M_IDENTITYKEY_LENGTH, PENUMBRA_BECH32M_IDENTITYKEY_PREFIX } from '.'; diff --git a/packages/bech32m/src/penumbrawalletid.ts b/packages/bech32m/src/penumbrawalletid.ts deleted file mode 100644 index 3468a7fe..00000000 --- a/packages/bech32m/src/penumbrawalletid.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { fromBech32m, toBech32m } from './format/convert'; -import { Inner } from './format/inner'; -import { Prefixes } from './format/prefix'; - -const innerName = Inner.penumbrawalletid; -const prefix = Prefixes.penumbrawalletid; - -export const bech32mWalletId = ({ [innerName]: bytes }: { [innerName]: Uint8Array }) => - toBech32m(bytes, prefix); - -export const walletIdFromBech32m = (penumbrawalletid1: string): { [innerName]: Uint8Array } => ({ - [innerName]: fromBech32m(penumbrawalletid1 as `${typeof prefix}1${string}`, prefix), -}); - -export const isWalletId = (check: string): check is `${typeof prefix}1${string}` => { - try { - walletIdFromBech32m(check); - return true; - } catch { - return false; - } -}; - -export { PENUMBRA_BECH32M_WALLETID_LENGTH, PENUMBRA_BECH32M_WALLETID_PREFIX } from '.'; diff --git a/packages/bech32m/src/plpid.ts b/packages/bech32m/src/plpid.ts deleted file mode 100644 index 6d74232b..00000000 --- a/packages/bech32m/src/plpid.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { fromBech32m, toBech32m } from './format/convert'; -import { Inner } from './format/inner'; -import { Prefixes } from './format/prefix'; - -const innerName = Inner.plpid; -const prefix = Prefixes.plpid; - -export const bech32mPositionId = ({ [innerName]: bytes }: { [innerName]: Uint8Array }) => - toBech32m(bytes, prefix); - -export const positionIdFromBech32 = (plpid1: string): { [innerName]: Uint8Array } => ({ - [innerName]: fromBech32m(plpid1 as `${typeof prefix}1${string}`, prefix), -}); - -export const isPositionId = (check: string): check is `${typeof prefix}1${string}` => { - try { - positionIdFromBech32(check); - return true; - } catch { - return false; - } -}; - -export { PENUMBRA_BECH32M_POSITIONID_LENGTH, PENUMBRA_BECH32M_POSITIONID_PREFIX } from '.'; diff --git a/packages/bech32m/src/test/passet.test.ts b/packages/bech32m/src/test/passet.test.ts deleted file mode 100644 index 94107a28..00000000 --- a/packages/bech32m/src/test/passet.test.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { describe } from 'vitest'; -import { generateTests } from './util/generate-tests'; -import { assetIdFromBech32m, bech32mAssetId } from '../passet'; -import { Prefixes } from '../format/prefix'; -import { Inner } from '../format/inner'; - -describe('asset id conversion', () => { - const okBech32 = 'passet1vhga2czmpk76hsu3t7usjj2a2qga0u29vqlcp3hky8lwkfz30qrqy6gaae'; - const okInner = new Uint8Array([ - 101, 209, 213, 96, 91, 13, 189, 171, 195, 145, 95, 185, 9, 73, 93, 80, 17, 215, 241, 69, 96, 63, - 128, 198, 246, 33, 254, 235, 36, 81, 120, 6, - ]); - - generateTests( - Prefixes.passet, - Inner.passet, - okInner, - okBech32, - bech32mAssetId, - assetIdFromBech32m, - ); -}); diff --git a/packages/bech32m/src/test/penumbra.test.ts b/packages/bech32m/src/test/penumbra.test.ts deleted file mode 100644 index 1ae9b0ca..00000000 --- a/packages/bech32m/src/test/penumbra.test.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { describe } from 'vitest'; -import { addressFromBech32m, bech32mAddress } from '../penumbra'; -import { generateTests } from './util/generate-tests'; -import { Prefixes } from '../format/prefix'; -import { Inner } from '../format/inner'; - -describe('address conversion', () => { - const okInner = new Uint8Array([ - 175, 182, 158, 255, 239, 16, 245, 221, 208, 117, 160, 44, 235, 175, 198, 0, 6, 216, 6, 143, 192, - 155, 159, 103, 97, 103, 136, 5, 78, 209, 17, 200, 68, 220, 182, 45, 20, 246, 181, 16, 117, 182, - 46, 141, 74, 101, 196, 86, 185, 124, 206, 253, 195, 57, 224, 34, 210, 22, 123, 246, 136, 10, - 208, 159, 24, 235, 148, 153, 211, 7, 137, 198, 158, 226, 221, 22, 208, 152, 246, 247, - ]); - const okBech32 = - 'penumbra147mfall0zr6am5r45qkwht7xqqrdsp50czde7empv7yq2nk3z8yyfh9k9520ddgswkmzar22vhz9dwtuem7uxw0qytfpv7lk3q9dp8ccaw2fn5c838rfackazmgf3ahh09cxmz'; - - generateTests( - Prefixes.penumbra, - Inner.penumbra, - okInner, - okBech32, - bech32mAddress, - addressFromBech32m, - ); -}); diff --git a/packages/bech32m/src/test/penumbracompat1.test.ts b/packages/bech32m/src/test/penumbracompat1.test.ts deleted file mode 100644 index 706b1523..00000000 --- a/packages/bech32m/src/test/penumbracompat1.test.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { describe } from 'vitest'; -import { generateTests } from './util/generate-tests'; -import { bech32CompatAddress, compatAddressFromBech32 } from '../penumbracompat1'; -import { Prefixes } from '../format/prefix'; -import { Inner } from '../format/inner'; - -describe('compat address conversion', () => { - const okInner = new Uint8Array([ - 175, 182, 158, 255, 239, 16, 245, 221, 208, 117, 160, 44, 235, 175, 198, 0, 6, 216, 6, 143, 192, - 155, 159, 103, 97, 103, 136, 5, 78, 209, 17, 200, 68, 220, 182, 45, 20, 246, 181, 16, 117, 182, - 46, 141, 74, 101, 196, 86, 185, 124, 206, 253, 195, 57, 224, 34, 210, 22, 123, 246, 136, 10, - 208, 159, 24, 235, 148, 153, 211, 7, 137, 198, 158, 226, 221, 22, 208, 152, 246, 247, - ]); - const okBech32 = - 'penumbracompat1147mfall0zr6am5r45qkwht7xqqrdsp50czde7empv7yq2nk3z8yyfh9k9520ddgswkmzar22vhz9dwtuem7uxw0qytfpv7lk3q9dp8ccaw2fn5c838rfackazmgf3ahhwqq0da'; - - generateTests( - Prefixes.penumbracompat1, - Inner.penumbracompat1, - okInner, - okBech32, - bech32CompatAddress, - compatAddressFromBech32, - ); -}); diff --git a/packages/bech32m/src/test/penumbrafullviewingkey.test.ts b/packages/bech32m/src/test/penumbrafullviewingkey.test.ts deleted file mode 100644 index a19bf3cc..00000000 --- a/packages/bech32m/src/test/penumbrafullviewingkey.test.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { describe } from 'vitest'; -import { bech32mFullViewingKey, fullViewingKeyFromBech32m } from '../penumbrafullviewingkey'; -import { generateTests } from './util/generate-tests'; -import { Prefixes } from '../format/prefix'; -import { Inner } from '../format/inner'; - -describe('fvk conversion', () => { - const okInner = new Uint8Array([ - 96, 146, 69, 187, 236, 3, 245, 228, 42, 194, 121, 104, 201, 250, 8, 194, 87, 95, 93, 29, 171, - 250, 177, 162, 130, 226, 176, 56, 91, 122, 89, 9, 34, 67, 106, 56, 17, 73, 174, 234, 72, 54, - 212, 210, 111, 5, 34, 249, 15, 60, 220, 191, 1, 224, 210, 114, 210, 205, 9, 187, 72, 115, 75, 2, - ]); - const okBech32 = - 'penumbrafullviewingkey1vzfytwlvq067g2kz095vn7sgcft47hga40atrg5zu2crskm6tyyjysm28qg5nth2fqmdf5n0q530jreumjlsrcxjwtfv6zdmfpe5kqsa5lg09'; - - generateTests( - Prefixes.penumbrafullviewingkey, - Inner.penumbrafullviewingkey, - okInner, - okBech32, - bech32mFullViewingKey, - fullViewingKeyFromBech32m, - ); -}); diff --git a/packages/bech32m/src/test/penumbraspendkey.test.ts b/packages/bech32m/src/test/penumbraspendkey.test.ts deleted file mode 100644 index 3d01344e..00000000 --- a/packages/bech32m/src/test/penumbraspendkey.test.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { describe } from 'vitest'; -import { spendKeyFromBech32m, bech32mSpendKey } from '../penumbraspendkey'; -import { generateTests } from './util/generate-tests'; -import { Prefixes } from '../format/prefix'; -import { Inner } from '../format/inner'; - -describe('spend key conversion', () => { - const okBech32 = 'penumbraspendkey1esjxkxnflw9ucrhhvgshxxpqkkjsf2ak40h2hwsanzvn6x542wnqe8stud'; - const okInner = new Uint8Array([ - 204, 36, 107, 26, 105, 251, 139, 204, 14, 247, 98, 33, 115, 24, 32, 181, 165, 4, 171, 182, 171, - 238, 171, 186, 29, 152, 153, 61, 26, 149, 83, 166, - ]); - - generateTests( - Prefixes.penumbraspendkey, - Inner.penumbraspendkey, - okInner, - okBech32, - bech32mSpendKey, - spendKeyFromBech32m, - ); -}); diff --git a/packages/bech32m/src/test/penumbravalid.test.ts b/packages/bech32m/src/test/penumbravalid.test.ts deleted file mode 100644 index 19cfc402..00000000 --- a/packages/bech32m/src/test/penumbravalid.test.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { describe } from 'vitest'; -import { generateTests } from './util/generate-tests'; -import { bech32mIdentityKey, identityKeyFromBech32m } from '../penumbravalid'; -import { Prefixes } from '../format/prefix'; -import { Inner } from '../format/inner'; - -describe('validator id conversion', () => { - const okInner = new Uint8Array([ - 46, 58, 148, 196, 175, 59, 251, 179, 127, 129, 196, 184, 185, 223, 27, 243, 46, 113, 201, 57, - 96, 186, 251, 132, 209, 136, 103, 239, 205, 105, 211, 8, - ]); - const okBech32 = 'penumbravalid19caff39080amxlupcjutnhcm7vh8rjfevza0hpx33pn7lntf6vyqvuekzh'; - - generateTests( - Prefixes.penumbravalid, - Inner.penumbravalid, - okInner, - okBech32, - bech32mIdentityKey, - identityKeyFromBech32m, - ); -}); diff --git a/packages/bech32m/src/test/penumbrawalletid.test.ts b/packages/bech32m/src/test/penumbrawalletid.test.ts deleted file mode 100644 index 35bbdec5..00000000 --- a/packages/bech32m/src/test/penumbrawalletid.test.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { describe } from 'vitest'; -import { generateTests } from './util/generate-tests'; -import { bech32mWalletId, walletIdFromBech32m } from '../penumbrawalletid'; -import { Prefixes } from '../format/prefix'; -import { Inner } from '../format/inner'; - -describe('asset id conversion', () => { - const okBech32 = 'penumbrawalletid15r7q7qsf3hhsgj0g530n7ng9acdacmmx9ajknjz38dyt90u9gcgsmjre75'; - const okInner = new Uint8Array([ - 160, 252, 15, 2, 9, 141, 239, 4, 73, 232, 164, 95, 63, 77, 5, 238, 27, 220, 111, 102, 47, 101, - 105, 200, 81, 59, 72, 178, 191, 133, 70, 17, - ]); - - generateTests( - Prefixes.penumbrawalletid, - Inner.penumbrawalletid, - okInner, - okBech32, - bech32mWalletId, - walletIdFromBech32m, - ); -}); diff --git a/packages/bech32m/src/test/plpid.test.ts b/packages/bech32m/src/test/plpid.test.ts deleted file mode 100644 index 4235aca3..00000000 --- a/packages/bech32m/src/test/plpid.test.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { describe } from 'vitest'; -import { bech32mPositionId, positionIdFromBech32 } from '../plpid'; -import { generateTests } from './util/generate-tests'; -import { Inner } from '../format/inner'; -import { Prefixes } from '../format/prefix'; - -describe('liquidity provider id conversion', () => { - const okBech32 = 'plpid1fkf3tlv500vgzwc6dkc7g9wnuv6rzezhefefdywq5tt4lyl97rgsd6j689'; - const okInner = new Uint8Array([ - 77, 147, 21, 253, 148, 123, 216, 129, 59, 26, 109, 177, 228, 21, 211, 227, 52, 49, 100, 87, 202, - 114, 150, 145, 192, 162, 215, 95, 147, 229, 240, 209, - ]); - - generateTests( - Prefixes.plpid, - Inner.plpid, - okInner, - okBech32, - bech32mPositionId, - positionIdFromBech32, - ); -}); diff --git a/packages/bech32m/src/test/util/corrupt.ts b/packages/bech32m/src/test/util/corrupt.ts deleted file mode 100644 index d2de0087..00000000 --- a/packages/bech32m/src/test/util/corrupt.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { bech32m } from 'bech32'; - -/** - * @param goodBech32 a valid bech32/bech32m string - * @param change an optional object with a string index *i* and a character *c* to replace - * @returns the same string, with one character changed - */ -export const corruptBech32 = (goodBech32: string, change?: { i: number; c: string }) => { - const separator = goodBech32.lastIndexOf('1'); - const [hrp, data] = [goodBech32.slice(0, separator), goodBech32.slice(separator + 1)]; - - const alphabet = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l'; - - const index = change?.i ?? Math.floor(Math.random() * data.length); - const dontUse = data[index]; - const wrongChar = (change ? [change.c] : Array.from(alphabet)) - .filter(c => c !== dontUse) - .sort(Math.random) - .pop(); - const bad = `${data.slice(0, index)}${wrongChar}${data.slice(index + 1)}`; - - return `${hrp}1${bad}`; -}; - -export const generateInvalid = (okBytes: Uint8Array, okString: string, innerName = 'inner') => { - const prefix = okString.slice(0, okString.lastIndexOf('1')); - return { - longBytes: { [innerName]: new Uint8Array([...okBytes, okBytes[0]!]) }, - shortBytes: { [innerName]: okBytes.slice(1) }, - longString: bech32m.encode(prefix, bech32m.toWords([...okBytes, okBytes[0]!]), Infinity), - shortString: bech32m.encode(prefix, bech32m.toWords(okBytes.slice(1)), Infinity), - corruptString: corruptBech32(okString), - wrongPrefix: Array.from(prefix).reverse().join('') + okString.slice(okString.lastIndexOf('1')), - truncatedString: okString.slice(0, -1), - }; -}; diff --git a/packages/bech32m/src/test/util/generate-tests.ts b/packages/bech32m/src/test/util/generate-tests.ts deleted file mode 100644 index bb148d12..00000000 --- a/packages/bech32m/src/test/util/generate-tests.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { describe, expect, test } from 'vitest'; -import { generateInvalid } from './corrupt'; - -export const generateTests = ( - prefix: string, - innerName: N, - okBytes: Uint8Array, - okString: string, - testToBech32: (x: { [k in N]: Uint8Array }) => string, - testFromBech32: (x: string) => { [k in N]: Uint8Array }, -) => { - type NamedInner = { [key in N]: Uint8Array }; - describe(`tests for ${prefix}`, () => { - test('Converts to bech32m', () => - expect(testToBech32({ [innerName]: okBytes } as NamedInner)).toBe(okString)); - - test('Converts from bech32m', () => - expect(testFromBech32(okString)).toMatchObject({ [innerName]: okBytes })); - - const { longBytes, shortBytes, wrongPrefix, longString, shortString, corruptString } = - generateInvalid(okBytes, okString, innerName); - - test('Throws if data too long', () => - expect(() => testToBech32({ [innerName]: longBytes } as unknown as NamedInner)).toThrow()); - - test('Throws if data too short', () => - expect(() => testToBech32({ [innerName]: shortBytes } as unknown as NamedInner)).toThrow()); - - test('Throws if prefix wrong', () => expect(() => testFromBech32(wrongPrefix)).toThrow()); - - test('Throws if string too long', () => expect(() => testFromBech32(longString)).toThrow()); - - test('Throws if string too short', () => expect(() => testFromBech32(shortString)).toThrow()); - - test('Throws if string corrupted', () => expect(() => testFromBech32(corruptString)).toThrow()); - }); -}; diff --git a/packages/bech32m/tsconfig.json b/packages/bech32m/tsconfig.json deleted file mode 100644 index eaf384a1..00000000 --- a/packages/bech32m/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "tsconfig/base.json", - "exclude": ["node_modules", "dist"], - "compilerOptions": { - "outDir": "dist", - "noEmit": false, - "declarationMap": false - } -} diff --git a/packages/client/CHANGELOG.md b/packages/client/CHANGELOG.md deleted file mode 100644 index 34f7fa68..00000000 --- a/packages/client/CHANGELOG.md +++ /dev/null @@ -1,121 +0,0 @@ -# @penumbra-zone/client - -## 6.0.1 - -### Patch Changes - -- 3be0580: change some package exports -- Updated dependencies [81b9536] - - @penumbra-zone/protobuf@4.1.0 - -## 6.0.0 - -### Major Changes - -- 8fe4de6: correct ordering of default export - -### Patch Changes - -- Updated dependencies [8fe4de6] - - @penumbra-zone/transport-dom@6.0.0 - - @penumbra-zone/protobuf@4.0.0 - -## 5.0.0 - -### Major Changes - -- 8b121ec: change package exports to use 'default' field - -### Patch Changes - -- Updated dependencies [8b121ec] - - @penumbra-zone/transport-dom@5.0.0 - - @penumbra-zone/protobuf@3.0.0 - -## 4.2.0 - -### Minor Changes - -- 3ea1e6c: update buf types dependencies - -### Patch Changes - -- Updated dependencies [4f8c150] -- Updated dependencies [029eebb] -- Updated dependencies [3ea1e6c] - - @penumbra-zone/protobuf@2.1.0 - - @penumbra-zone/transport-dom@4.1.0 - -## 4.1.2 - -### Patch Changes - -- Updated dependencies [8ccaf30] -- Updated dependencies [e35c6f7] -- Updated dependencies [8ccaf30] - - @penumbra-zone/protobuf@2.0.0 - -## 4.1.1 - -### Patch Changes - -- Updated dependencies - - @penumbra-zone/protobuf@1.1.0 - -## 4.1.0 - -### Minor Changes - -- 8410d2f: add createPraxTransport export, change interface name - -## 4.0.1 - -### Patch Changes - -- Updated dependencies [fc500af] -- Updated dependencies [6fb898a] - - @penumbra-zone/transport-dom@4.0.0 - - @penumbra-zone/protobuf@1.0.0 - -## 4.0.0 - -### Major Changes - -- 3148375: remove `/src/` path segment from exports - -### Patch Changes - -- Updated dependencies [3148375] - - @penumbra-zone/transport-dom@3.0.0 - - @penumbra-zone/types@3.0.0 - -## 3.0.1 - -### Patch Changes - -- @penumbra-zone/types@2.0.1 - -## 3.0.0 - -### Major Changes - -- 7a1efed: isPraxInstalled -> isPraxAvailable renaming -- 929d278: barrel imports to facilitate better tree shaking - -### Patch Changes - -- Updated dependencies [929d278] - - @penumbra-zone/types@2.0.0 - - @penumbra-zone/transport-dom@2.0.0 - -## 2.0.0 - -### Major Changes - -- Initial changest. Git tag v5.0.0 updates. - -### Patch Changes - -- Updated dependencies - - @penumbra-zone/transport-dom@1.1.0 - - @penumbra-zone/types@1.1.0 diff --git a/packages/client/eslint.config.mjs b/packages/client/eslint.config.mjs deleted file mode 100644 index a53ed8e5..00000000 --- a/packages/client/eslint.config.mjs +++ /dev/null @@ -1,13 +0,0 @@ -import { penumbraEslintConfig } from '@penumbra-zone/eslint-config'; -import { config, parser } from 'typescript-eslint'; - -export default config({ - ...penumbraEslintConfig, - languageOptions: { - parser, - parserOptions: { - project: true, - tsconfigRootDir: import.meta.dirname, - }, - }, -}); diff --git a/packages/client/package.json b/packages/client/package.json deleted file mode 100644 index 8e242737..00000000 --- a/packages/client/package.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "name": "@penumbra-zone/client", - "version": "6.0.1", - "private": true, - "license": "(MIT OR Apache-2.0)", - "description": "Package for connecting to any Penumbra extension, including Prax.", - "type": "module", - "scripts": { - "build": "tsc", - "clean": "rm -rfv dist package penumbra-zone-client-*.tgz", - "lint": "eslint src", - "prebuild": "$npm_execpath run clean", - "prepack": "$npm_execpath run build" - }, - "files": [ - "dist" - ], - "exports": { - ".": "./src/index.ts", - "./prax": "./src/prax.ts" - }, - "publishConfig": { - "exports": { - ".": { - "types": "./dist/index.d.ts", - "default": "./dist/index.js" - }, - "./prax": { - "types": "./dist/prax.d.ts", - "default": "./dist/prax.js" - } - } - }, - "dependencies": { - "@penumbra-zone/protobuf": "workspace:*", - "@penumbra-zone/transport-dom": "workspace:*" - }, - "devDependencies": { - "@connectrpc/connect": "^1.4.0" - }, - "peerDependencies": { - "@bufbuild/protobuf": "^1.10.0", - "@connectrpc/connect": "^1.4.0" - } -} diff --git a/packages/client/src/error.ts b/packages/client/src/error.ts deleted file mode 100644 index ff250d2a..00000000 --- a/packages/client/src/error.ts +++ /dev/null @@ -1,43 +0,0 @@ -export enum PenumbraRequestFailure { - Denied = 'Denied', - NeedsLogin = 'NeedsLogin', -} - -export class PenumbraNotAvailableError extends Error { - constructor( - message = "Penumbra global `window[Symbol.for('penumbra')]` is not available", - public opts?: ErrorOptions, - ) { - super(message, opts); - this.name = 'PenumbraNotAvailableError'; - } -} - -export class PenumbraNotConnectedError extends Error { - constructor( - message = 'Penumbra extension not connected', - public opts?: ErrorOptions, - ) { - super(message, opts); - this.name = 'PenumbraNotConnectedError'; - } -} - -export class PenumbraRequestError extends Error { - constructor( - message = 'Penumbra request failed', - public opts?: ErrorOptions & { cause: PenumbraRequestFailure }, - ) { - super(message, opts); - this.name = 'PenumbraRequestError'; - } -} -export class PenumbraNotInstalledError extends Error { - constructor( - message = 'Penumbra not installed', - public opts?: ErrorOptions, - ) { - super(message, opts); - this.name = 'PenumbraNotInstalledError'; - } -} diff --git a/packages/client/src/index.ts b/packages/client/src/index.ts deleted file mode 100644 index 7a24f9b8..00000000 --- a/packages/client/src/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -export * from './error'; - -export const PenumbraSymbol = Symbol.for('penumbra'); - -export interface PenumbraInjection { - readonly connect: () => Promise; - readonly request: () => Promise; - readonly isConnected: () => boolean | undefined; - readonly manifest: string; -} - -declare global { - interface Window { - readonly [PenumbraSymbol]?: undefined | Readonly>; - } -} diff --git a/packages/client/src/prax.ts b/packages/client/src/prax.ts deleted file mode 100644 index 31537963..00000000 --- a/packages/client/src/prax.ts +++ /dev/null @@ -1,66 +0,0 @@ -/** - * Prax is the reference implementation of browser-local Penumbra services. This - * module provides tools for connecting to Prax specifically, and a few - * additional conveniences. - */ - -import type { PromiseClient, Transport } from '@connectrpc/connect'; -import type { PenumbraService } from '@penumbra-zone/protobuf'; - -import { createPromiseClient } from '@connectrpc/connect'; -import { jsonOptions } from '@penumbra-zone/protobuf'; -import { createChannelTransport } from '@penumbra-zone/transport-dom/create'; -import { PenumbraSymbol } from '.'; -import { PenumbraNotConnectedError } from './error'; -import { PenumbraNotInstalledError } from './error'; - -const prax_id = 'lkpmkhpnhknhmibgnmmhdhgdilepfghe'; -const prax_origin = `chrome-extension://${prax_id}`; -const prax_manifest = `chrome-extension://${prax_id}/manifest.json`; - -export const getPraxManifest = async () => { - const res = await fetch(prax_manifest); - return (await res.json()) as unknown; -}; - -export const isPraxConnected = () => Boolean(window[PenumbraSymbol]?.[prax_origin]?.isConnected()); - -export const isPraxInstalled = async () => { - try { - await getPraxManifest(); - return true; - } catch { - return false; - } -}; - -export const throwIfPraxNotConnected = () => { - if (!isPraxConnected()) - throw new PenumbraNotConnectedError('Prax not connected', { cause: prax_origin }); -}; - -export const throwIfPraxNotInstalled = async () => { - if (!(await isPraxInstalled())) - throw new PenumbraNotInstalledError('Prax not installed', { cause: prax_origin }); -}; - -export const getPraxPort = async () => { - await throwIfPraxNotInstalled(); - return window[PenumbraSymbol]![prax_origin]!.connect(); -}; - -export const requestPraxAccess = async () => { - await throwIfPraxNotInstalled(); - await window[PenumbraSymbol]?.[prax_origin]?.request(); -}; - -export const praxTransportOptions = { - jsonOptions, - getPort: getPraxPort, -}; - -export const createPraxTransport = () => createChannelTransport(praxTransportOptions); - -let praxTransport: Transport | undefined; -export const createPraxClient = (service: T): PromiseClient => - createPromiseClient(service, (praxTransport ??= createPraxTransport())); diff --git a/packages/client/tsconfig.json b/packages/client/tsconfig.json deleted file mode 100644 index 1f72113e..00000000 --- a/packages/client/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "tsconfig/base.json", - "include": ["src"], - "exclude": ["node_modules", "dist"], - "compilerOptions": { - "outDir": "dist", - "noEmit": false - } -} diff --git a/packages/services-context/CHANGELOG.md b/packages/context/CHANGELOG.md similarity index 100% rename from packages/services-context/CHANGELOG.md rename to packages/context/CHANGELOG.md diff --git a/packages/getters/eslint.config.mjs b/packages/context/eslint.config.mjs similarity index 77% rename from packages/getters/eslint.config.mjs rename to packages/context/eslint.config.mjs index a53ed8e5..11c6ce91 100644 --- a/packages/getters/eslint.config.mjs +++ b/packages/context/eslint.config.mjs @@ -1,4 +1,4 @@ -import { penumbraEslintConfig } from '@penumbra-zone/eslint-config'; +import { penumbraEslintConfig } from '@repo/eslint-config'; import { config, parser } from 'typescript-eslint'; export default config({ diff --git a/packages/context/package.json b/packages/context/package.json new file mode 100644 index 00000000..11deb703 --- /dev/null +++ b/packages/context/package.json @@ -0,0 +1,33 @@ +{ + "name": "@repo/context", + "version": "3.3.0", + "private": true, + "license": "(MIT OR Apache-2.0)", + "type": "module", + "scripts": { + "lint": "eslint \"**/*.ts*\"" + }, + "files": [ + "src/", + "*.md" + ], + "exports": { + ".": "./src/index.ts" + }, + "dependencies": { + "@penumbra-zone/bech32m": "^6.1.0", + "@penumbra-zone/protobuf": "^5.1.0" + }, + "peerDependencies": { + "@buf/cosmos_ibc.bufbuild_es": "1.10.0-20240606104028-442292b00c16.1", + "@buf/penumbra-zone_penumbra.bufbuild_es": "1.10.0-20240616005217-ca45ca80333e.1", + "@bufbuild/protobuf": "^1.10.0", + "@penumbra-labs/registry": "8.0.1", + "@penumbra-zone/crypto-web": "^5.0.0", + "@penumbra-zone/query": "^6.0.0", + "@penumbra-zone/storage": "^6.0.0", + "@penumbra-zone/types": "^9.0.0", + "@penumbra-zone/wasm": "^9.0.0", + "exponential-backoff": "^3.1.1" + } +} diff --git a/packages/services-context/src/index.ts b/packages/context/src/index.ts similarity index 100% rename from packages/services-context/src/index.ts rename to packages/context/src/index.ts diff --git a/packages/query/tsconfig.json b/packages/context/tsconfig.json similarity index 56% rename from packages/query/tsconfig.json rename to packages/context/tsconfig.json index 61a00fa2..334d91f9 100644 --- a/packages/query/tsconfig.json +++ b/packages/context/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "tsconfig/base.json", + "extends": "@repo/tsconfig/base.json", "include": ["."], "exclude": ["node_modules"] } diff --git a/packages/crypto/CHANGELOG.md b/packages/crypto/CHANGELOG.md deleted file mode 100644 index 13858548..00000000 --- a/packages/crypto/CHANGELOG.md +++ /dev/null @@ -1,97 +0,0 @@ -# @penumbra-zone/crypto-web - -## 3.0.10 - -### Patch Changes - -- Updated dependencies [ab9d743] -- Updated dependencies [282eabf] -- Updated dependencies [c8e8d15] - - @penumbra-zone/types@7.1.0 - -## 3.0.9 - -### Patch Changes - -- @penumbra-zone/types@7.0.1 - -## 3.0.8 - -### Patch Changes - -- Updated dependencies [bb5f621] - - @penumbra-zone/types@7.0.0 - -## 3.0.7 - -### Patch Changes - -- Updated dependencies [029eebb] -- Updated dependencies [3ea1e6c] - - @penumbra-zone/types@6.0.0 - -## 3.0.6 - -### Patch Changes - -- Updated dependencies [146b48d] -- Updated dependencies [e35c6f7] -- Updated dependencies [8ccaf30] - - @penumbra-zone/types@5.0.0 - -## 3.0.5 - -### Patch Changes - -- Updated dependencies - - @penumbra-zone/types@4.1.0 - -## 3.0.4 - -### Patch Changes - -- @penumbra-zone/types@4.0.1 - -## 3.0.3 - -### Patch Changes - -- Updated dependencies [6fb898a] - - @penumbra-zone/types@4.0.0 - -## 3.0.2 - -### Patch Changes - -- Updated dependencies [3148375] - - @penumbra-zone/types@3.0.0 - -## 3.0.1 - -### Patch Changes - -- @penumbra-zone/types@2.0.1 - -## 3.0.0 - -### Major Changes - -- b4082b7: /src/ import path requirement removed - -## 2.0.0 - -### Major Changes - -- 929d278: barrel imports to facilitate better tree shaking - -### Patch Changes - -- Updated dependencies [929d278] - - @penumbra-zone/types@2.0.0 - -## 1.0.1 - -### Patch Changes - -- Updated dependencies - - @penumbra-zone/types@1.1.0 diff --git a/packages/crypto/eslint.config.mjs b/packages/crypto/eslint.config.mjs deleted file mode 100644 index a53ed8e5..00000000 --- a/packages/crypto/eslint.config.mjs +++ /dev/null @@ -1,13 +0,0 @@ -import { penumbraEslintConfig } from '@penumbra-zone/eslint-config'; -import { config, parser } from 'typescript-eslint'; - -export default config({ - ...penumbraEslintConfig, - languageOptions: { - parser, - parserOptions: { - project: true, - tsconfigRootDir: import.meta.dirname, - }, - }, -}); diff --git a/packages/crypto/package.json b/packages/crypto/package.json deleted file mode 100644 index 2314c867..00000000 --- a/packages/crypto/package.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "name": "@penumbra-zone/crypto-web", - "version": "3.0.10", - "private": true, - "license": "(MIT OR Apache-2.0)", - "type": "module", - "scripts": { - "lint": "eslint src", - "test": "vitest run" - }, - "files": [ - "src/", - "*.md", - "!**/*.test.ts" - ], - "exports": { - "./mnemonic": "./src/mnemonic.ts", - "./encryption": "./src/encryption.ts", - "./sha256": "./src/sha256.ts" - }, - "dependencies": { - "@penumbra-zone/types": "workspace:*", - "bip39": "^3.1.0", - "crypto-js": "^4.2.0" - }, - "devDependencies": { - "@types/crypto-js": "^4.2.2" - } -} diff --git a/packages/crypto/src/encryption.test.ts b/packages/crypto/src/encryption.test.ts deleted file mode 100644 index f7d6553e..00000000 --- a/packages/crypto/src/encryption.test.ts +++ /dev/null @@ -1,173 +0,0 @@ -import { describe, expect, test } from 'vitest'; -import { Key, KeyPrint, uintArraysEqual } from './encryption'; -import { Box } from '@penumbra-zone/types/box'; - -// NOTE: To have the most accurate representation, these the web crypto API tests run in a browser environment - -describe('encryption', () => { - describe('Key', () => { - const password = 's0meUs3rP@ssword'; - const seedPhrase = 'correct horse battery staple'; - - describe('create', () => { - test('successfully creates a Key and KeyPrint instance', async () => { - const { key, keyPrint } = await Key.create(password); - expect(key).toBeInstanceOf(Key); - expect(keyPrint).toBeInstanceOf(KeyPrint); - }); - }); - - describe('recreate', () => { - test('successfully recreates the original Key', async () => { - const { key: originalKey, keyPrint } = await Key.create(password); - const recreatedKey = await Key.recreate(password, keyPrint); - expect(recreatedKey).toBeInstanceOf(Key); - - const originalBox = await originalKey.seal(seedPhrase); - const recreatedBox = await recreatedKey!.seal(seedPhrase); - - const originalUnsealedMessage = await originalKey.unseal(originalBox); - const recreatedUnsealedMessage = await recreatedKey!.unseal(recreatedBox); - - expect(originalUnsealedMessage).toEqual(seedPhrase); - expect(originalUnsealedMessage).toEqual(recreatedUnsealedMessage); - }); - - test('returns null when the password is incorrect', async () => { - const { keyPrint } = await Key.create(password); - const recreatedKey = await Key.recreate('wrongPassword', keyPrint); - expect(recreatedKey).toBeNull(); - }); - }); - - describe('seal', () => { - test('successfully encrypts a message', async () => { - const { key } = await Key.create(password); - const box = await key.seal(seedPhrase); - expect(box).toBeInstanceOf(Box); - }); - }); - - describe('unseal', () => { - test('successfully decrypts a message', async () => { - const { key } = await Key.create(password); - const box = await key.seal(seedPhrase); - const unsealedMessage = await key.unseal(box); - - expect(unsealedMessage).toEqual(seedPhrase); - }); - - test('returns null when the box cannot be decrypted (OperationError)', async () => { - const { key: key1 } = await Key.create(password); - const { key: key2 } = await Key.create('anotherPassword'); - const box = await key1.seal(seedPhrase); - const unsealedMessage = await key2.unseal(box); - - expect(unsealedMessage).toBeNull(); - }); - - test('returns a null with bad inputs', async () => { - const { key } = await Key.create(password); - // @ts-expect-error intentionally passing wrong types - const unsealedMessage = await key.unseal({ nonce: 123, cipherText: 456 }); - expect(unsealedMessage).toBeNull(); - }); - }); - }); - - describe('KeyPrint', () => { - const testHash = new Uint8Array([1, 2, 3]); - const testSalt = new Uint8Array([4, 5, 6]); - const testHashBase64 = 'AQID'; - const testSaltBase64 = 'BAUG'; - - test('constructor correctly assigns hash and salt', () => { - const keyPrint = new KeyPrint(testHash, testSalt); - - expect(keyPrint.hash).toEqual(testHash); - expect(keyPrint.salt).toEqual(testSalt); - }); - - test('correctly creates a KeyPrint from JSON', () => { - const json = { hash: testHashBase64, salt: testSaltBase64 }; - const keyPrint = KeyPrint.fromJson(json); - - expect(keyPrint.hash).toEqual(testHash); - expect(keyPrint.salt).toEqual(testSalt); - }); - - test('correctly creates JSON from a KeyPrint', () => { - const keyPrint = new KeyPrint(testHash, testSalt); - const json = keyPrint.toJson(); - - expect(json).toEqual({ hash: testHashBase64, salt: testSaltBase64 }); - }); - }); - - describe('Box', () => { - const testNonce = new Uint8Array([72, 101, 108, 108, 111]); - const testCipherText = new Uint8Array([87, 111, 114, 108, 100]); - const testNonceBase64 = 'SGVsbG8='; - const testCipherTextBase64 = 'V29ybGQ='; - - describe('constructor', () => { - test('correctly assigns nonce and cipherText', () => { - const box = new Box(testNonce, testCipherText); - - expect(box.nonce).toEqual(testNonce); - expect(box.cipherText).toEqual(testCipherText); - }); - }); - - describe('fromJson', () => { - test('correctly creates a Box from JSON', () => { - const json = { nonce: testNonceBase64, cipherText: testCipherTextBase64 }; - const box = Box.fromJson(json); - - expect(box.nonce).toEqual(testNonce); - expect(box.cipherText).toEqual(testCipherText); - }); - }); - - describe('toJson', () => { - test('correctly creates JSON from a Box', () => { - const box = new Box(testNonce, testCipherText); - const json = box.toJson(); - - expect(json).toEqual({ nonce: testNonceBase64, cipherText: testCipherTextBase64 }); - }); - }); - }); - - describe('uintArraysEqual', () => { - test('returns true for identical arrays', () => { - const a = new Uint8Array([1, 2, 3, 4, 5]); - const b = new Uint8Array([1, 2, 3, 4, 5]); - expect(uintArraysEqual(a, b)).toBe(true); - }); - - test('returns false for arrays of different lengths', () => { - const a = new Uint8Array([1, 2, 3, 4, 5]); - const b = new Uint8Array([1, 2, 3]); - expect(uintArraysEqual(a, b)).toBe(false); - }); - - test('returns false for arrays of the same length but different values', () => { - const a = new Uint8Array([1, 2, 3, 4, 5]); - const b = new Uint8Array([1, 2, 3, 4, 6]); - expect(uintArraysEqual(a, b)).toBe(false); - }); - - test('returns true for two empty arrays', () => { - const a = new Uint8Array([]); - const b = new Uint8Array([]); - expect(uintArraysEqual(a, b)).toBe(true); - }); - - test('returns false when one array is empty and the other is not', () => { - const a = new Uint8Array([]); - const b = new Uint8Array([1, 2, 3]); - expect(uintArraysEqual(a, b)).toBe(false); - }); - }); -}); diff --git a/packages/crypto/src/encryption.ts b/packages/crypto/src/encryption.ts deleted file mode 100644 index d76b909f..00000000 --- a/packages/crypto/src/encryption.ts +++ /dev/null @@ -1,162 +0,0 @@ -import { Base64Str, base64ToUint8Array, uint8ArrayToBase64 } from '@penumbra-zone/types/base64'; -import { Box } from '@penumbra-zone/types/box'; - -/** - * ==== Internal ==== - * Under-the-hood inner workings of hashing/encryption - */ - -// Hash a password with PBKDF2 using a provided salt -// Meant to hinder brute force or dictionary attacks -const keyStretchingHash = async (password: string, salt: Uint8Array): Promise => { - const enc = new TextEncoder(); - const importedKey = await crypto.subtle.importKey( - 'raw', - enc.encode(password), - { name: 'PBKDF2' }, - false, - ['deriveBits', 'deriveKey'], - ); - - return crypto.subtle.deriveKey( - { - name: 'PBKDF2', - salt, - iterations: 210_000, - hash: 'SHA-512', - }, - importedKey, - { name: 'AES-GCM', length: 256 }, - true, - ['encrypt', 'decrypt'], - ); -}; - -// Encrypt a message using AES-GCM -const encrypt = async (message: string, nonce: Uint8Array, key: CryptoKey): Promise => { - const enc = new TextEncoder(); - const buffer = await crypto.subtle.encrypt( - { name: 'AES-GCM', iv: nonce }, - key, - enc.encode(message), - ); - return new Uint8Array(buffer); -}; - -// Decrypt a ciphertext using AES-GCM -const decrypt = async ( - ciphertext: Uint8Array, - nonce: Uint8Array, // You need to provide both the same nonce & key used for encryption - key: CryptoKey, -): Promise => { - const dec = new TextDecoder(); - const decrypted = await crypto.subtle.decrypt({ name: 'AES-GCM', iv: nonce }, key, ciphertext); - return dec.decode(decrypted); -}; - -/** - * ==== External ==== - */ - -export interface KeyPrintJson { - hash: Base64Str; - salt: Base64Str; -} - -// Used to recreate the original key material -export class KeyPrint { - constructor( - readonly hash: Uint8Array, - readonly salt: Uint8Array, - ) {} - - static fromJson(json: KeyPrintJson): KeyPrint { - return new KeyPrint(base64ToUint8Array(json.hash), base64ToUint8Array(json.salt)); - } - - toJson(): KeyPrintJson { - return { - hash: uint8ArrayToBase64(this.hash), - salt: uint8ArrayToBase64(this.salt), - }; - } -} - -export const uintArraysEqual = (a: Uint8Array, b: Uint8Array): boolean => { - return a.length === b.length && a.every((num, i) => b[i] === num); -}; - -export interface KeyJson { - _inner: JsonWebKey; -} - -// Private key used to encrypt & decrypt messages. Do not expose publicly. -export class Key { - private constructor(private readonly key: CryptoKey) {} - - // Create a new Key instance from a password. Do not store the Key, only KeyPrint. - static async create(password: string): Promise<{ key: Key; keyPrint: KeyPrint }> { - const salt = crypto.getRandomValues(new Uint8Array(16)); // 128 bit - const key = await keyStretchingHash(password, salt); - const buffer = await crypto.subtle.exportKey('raw', key); - - // A second, fast hash to hide the result of the former - const hashedKey = await crypto.subtle.digest('SHA-256', buffer); - - return { - key: new Key(key), - keyPrint: new KeyPrint(new Uint8Array(hashedKey), salt), - }; - } - - // Takes a KeyPrint + password to recreate the original Key - static async recreate(password: string, print: KeyPrint): Promise { - const key = await keyStretchingHash(password, print.salt); - const buffer = await crypto.subtle.exportKey('raw', key); - const hashedKey = await crypto.subtle.digest('SHA-256', buffer); - - if (!uintArraysEqual(print.hash, new Uint8Array(hashedKey))) return null; - return new Key(key); - } - - static async fromJson(jwk: KeyJson): Promise { - const key = await crypto.subtle.importKey( - 'jwk', - jwk._inner, - { name: 'AES-GCM', length: 256 }, - false, - ['encrypt', 'decrypt'], - ); - return new Key(key); - } - - // Encrypts message. Box can be publicly stored. - async seal(message: string): Promise { - const nonce = crypto.getRandomValues(new Uint8Array(12)); // AES uses twelve bytes - const cipherText = await encrypt(message, nonce, this.key); - return new Box(nonce, cipherText); - } - - // Attempts to decrypt Box into message. If failure, returns `null`. - async unseal(box: Box): Promise { - try { - return await decrypt(box.cipherText, box.nonce, this.key); - } catch (e) { - if (e instanceof TypeError) { - return null; - } - - if (e instanceof DOMException) { - if (e.name === 'OperationError') { - return null; - } - } - - throw e; - } - } - - async toJson(): Promise { - return { _inner: await crypto.subtle.exportKey('jwk', this.key) }; - } -} diff --git a/packages/crypto/src/mnemonic.test.ts b/packages/crypto/src/mnemonic.test.ts deleted file mode 100644 index e79168a2..00000000 --- a/packages/crypto/src/mnemonic.test.ts +++ /dev/null @@ -1,189 +0,0 @@ -import { describe, expect, test } from 'vitest'; -import { - generateSeedPhrase, - generateValidationFields, - isInWordList, - SeedPhraseLength, - validateSeedPhrase, -} from './mnemonic'; -import { wordlists } from 'bip39'; - -describe('Mnemonic tests', () => { - describe('generateSeedPhrase()', () => { - test('can generate 128 bit phrases', () => { - const seedPhrase = generateSeedPhrase(SeedPhraseLength.TWELVE_WORDS); - expect(seedPhrase.length).toBe(12); - for (const word of seedPhrase) { - expect(wordlists['EN']?.includes(word)).toBeTruthy(); - } - }); - - test('can generate 256 bit phrases', () => { - const seedPhrase = generateSeedPhrase(SeedPhraseLength.TWENTY_FOUR_WORDS); - expect(seedPhrase.length).toBe(24); - for (const word of seedPhrase) { - expect(wordlists['EN']?.includes(word)).toBeTruthy(); - } - }); - - test('results are random each time', () => { - const seedPhraseA = generateSeedPhrase(SeedPhraseLength.TWELVE_WORDS); - const seedPhraseB = generateSeedPhrase(SeedPhraseLength.TWELVE_WORDS); - const seedPhraseC = generateSeedPhrase(SeedPhraseLength.TWELVE_WORDS); - - expect(seedPhraseA).not.toStrictEqual(seedPhraseB); - expect(seedPhraseA).not.toStrictEqual(seedPhraseC); - expect(seedPhraseB).not.toStrictEqual(seedPhraseC); - }); - - test('are always valid', () => { - Array.from({ length: 200 }).forEach(() => { - const seedPhraseShort = generateSeedPhrase(SeedPhraseLength.TWELVE_WORDS); - expect(validateSeedPhrase(seedPhraseShort)).toBeTruthy(); - - const seedPhraseLong = generateSeedPhrase(SeedPhraseLength.TWENTY_FOUR_WORDS); - expect(validateSeedPhrase(seedPhraseLong)).toBeTruthy(); - }); - }); - }); - - describe('generateValidationFields()', () => { - const valuesAscend = (arr: number[]) => arr.every((v, i, a) => !i || a[i - 1]! <= v); - - test('returns fields that correspond to phrase', () => { - // As it's random, run many times - Array.from({ length: 200 }).forEach(() => { - const seedPhrase = generateSeedPhrase(SeedPhraseLength.TWELVE_WORDS); - const fields = generateValidationFields(seedPhrase, 3); - const allMatch = fields.every(f => seedPhrase.at(f.index) === f.word); - expect(allMatch).toBeTruthy(); - - const isAscendingByIndex = valuesAscend(fields.map(f => f.index)); - expect(isAscendingByIndex).toBeTruthy(); - }); - }); - - test('works with 24 words as well', () => { - Array.from({ length: 200 }).forEach(() => { - const seedPhrase = generateSeedPhrase(SeedPhraseLength.TWENTY_FOUR_WORDS); - const fields = generateValidationFields(seedPhrase, 5); - const allMatch = fields.every(f => seedPhrase.at(f.index) === f.word); - expect(allMatch).toBeTruthy(); - - const isAscendingByIndex = valuesAscend(fields.map(f => f.index)); - expect(isAscendingByIndex).toBeTruthy(); - }); - }); - }); - - describe('validateSeedPhrase()', () => { - test('returns true on known valid addresses', () => { - const validSeedPhraseA = [ - 'cancel', - 'tilt', - 'shallow', - 'way', - 'roast', - 'utility', - 'profit', - 'satoshi', - 'mushroom', - 'seek', - 'shift', - 'helmet', - ]; - const validSeedPhraseB = [ - 'blouse', - 'injury', - 'into', - 'among', - 'depend', - 'flash', - 'blossom', - 'accuse', - 'empower', - 'swear', - 'merit', - 'tail', - 'rude', - 'stuff', - 'abuse', - 'noodle', - 'sniff', - 'element', - 'bubble', - 'monster', - 'put', - 'satoshi', - 'behave', - 'intact', - ]; - expect(validateSeedPhrase(validSeedPhraseA)).toBeTruthy(); - expect(validateSeedPhrase(validSeedPhraseB)).toBeTruthy(); - }); - - test('returns false on invalid seed phrases', () => { - const none: string[] = []; - const tooShort = ['cancel', 'tilt', 'shallow', 'way']; - const invalidCharacter = ['%']; - const wrongEndingWord = [ - 'cancel', - 'tilt', - 'shallow', - 'way', - 'roast', - 'utility', - 'profit', - 'satoshi', - 'mushroom', - 'seek', - 'shift', - 'cancel', // should be helmet - ]; - expect(validateSeedPhrase(none)).toBeFalsy(); - expect(validateSeedPhrase(tooShort)).toBeFalsy(); - expect(validateSeedPhrase(invalidCharacter)).toBeFalsy(); - expect(validateSeedPhrase(wrongEndingWord)).toBeFalsy(); - }); - }); - - describe('isInWordList()', () => { - test('returns true on valid words', () => { - const validWords = [ - 'cancel', - 'tilt', - 'shallow', - 'way', - 'roast', - 'utility', - 'profit', - 'satoshi', - 'mushroom', - 'seek', - 'shift', - 'helmet', - ]; - validWords.forEach(w => { - expect(isInWordList(w)).toBeTruthy(); - }); - }); - - test('returns false on invalid words', () => { - const invalidWords = [ - 'Haus', - 'Tisch', - 'Auto', - 'Blume', - 'Baum', - 'Telefon', - 'Fenster', - 'Stuhl', - 'Buch', - 'Schule', - ]; - invalidWords.forEach(w => { - expect(isInWordList(w)).toBeFalsy(); - }); - }); - }); -}); diff --git a/packages/crypto/src/mnemonic.ts b/packages/crypto/src/mnemonic.ts deleted file mode 100644 index 407f2192..00000000 --- a/packages/crypto/src/mnemonic.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { generateMnemonic, validateMnemonic, wordlists } from 'bip39'; - -export enum SeedPhraseLength { - TWELVE_WORDS = 12, // 128bits - TWENTY_FOUR_WORDS = 24, // 256bits -} - -export const generateSeedPhrase = (length: SeedPhraseLength): string[] => { - const entropy = length === SeedPhraseLength.TWELVE_WORDS ? 128 : 256; - return generateMnemonic(entropy).split(' '); -}; - -export interface ValidationField { - word: string; - index: number; -} - -export const generateValidationFields = ( - seedPhrase: string[], - amount: number, -): ValidationField[] => { - const allWords: ValidationField[] = seedPhrase.map((word, index) => ({ word, index })); - const shuffleWords = allWords.sort(() => 0.5 - Math.random()); - const pickWords = shuffleWords.slice(0, amount); - return pickWords.sort((a, b) => a.index - b.index); -}; - -export const validateSeedPhrase = (seedPhrase: string[]): boolean => { - return validateMnemonic(seedPhrase.join(' ')); -}; - -export const isInWordList = (word: string): boolean => { - return wordlists['EN']!.includes(word); -}; diff --git a/packages/crypto/src/sha256.test.ts b/packages/crypto/src/sha256.test.ts deleted file mode 100644 index d70c58d0..00000000 --- a/packages/crypto/src/sha256.test.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { describe, expect, test } from 'vitest'; -import { sha256HashStr } from './sha256'; - -describe('sha256Hash', () => { - test('returns correct hash for a given input', async () => { - const input = new Uint8Array([65, 66, 67, 68]); // ASCII for 'ABCD' - const expectedOutput = 'e12e115acf4552b2568b55e93cbd39394c4ef81c82447fafc997882a02d23677'; // SHA-256 of 'ABCD' - const result = await sha256HashStr(input); - expect(result).toBe(expectedOutput); - }); - - test('returns different hashes for different inputs', async () => { - const input1 = new Uint8Array([1, 2, 3, 4]); - const input2 = new Uint8Array([4, 3, 2, 1]); - const result1 = await sha256HashStr(input1); - const result2 = await sha256HashStr(input2); - expect(result1).not.toBe(result2); - }); - - test('returns the same hash for the same input', async () => { - const input = new Uint8Array([10, 20, 30, 40]); - const result1 = await sha256HashStr(input); - const result2 = await sha256HashStr(input); - expect(result1).toBe(result2); - }); -}); diff --git a/packages/crypto/src/sha256.ts b/packages/crypto/src/sha256.ts deleted file mode 100644 index 6de0ab4f..00000000 --- a/packages/crypto/src/sha256.ts +++ /dev/null @@ -1,12 +0,0 @@ -// Function to convert a byte to a hexadecimal string -const byteToHex = (byte: number): string => byte.toString(16).padStart(2, '0'); - -export const sha256HashStr = async (inputBuffer: Uint8Array): Promise => { - const uint8Arr = await sha256Hash(inputBuffer); - return Array.from(uint8Arr).map(byteToHex).join(''); -}; - -export const sha256Hash = async (inputBuffer: Uint8Array): Promise => { - const digestBuffer = await crypto.subtle.digest('SHA-256', inputBuffer); - return new Uint8Array(digestBuffer); -}; diff --git a/packages/crypto/tsconfig.json b/packages/crypto/tsconfig.json deleted file mode 100644 index 37906aab..00000000 --- a/packages/crypto/tsconfig.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "extends": "tsconfig/base.json", - "include": ["."], - "exclude": ["dist", "build", "node_modules"] -} diff --git a/packages/eslint-config/eslint.config.mjs b/packages/eslint-config/eslint.config.mjs index b92fc61b..01afa5bd 100644 --- a/packages/eslint-config/eslint.config.mjs +++ b/packages/eslint-config/eslint.config.mjs @@ -39,7 +39,7 @@ export const penumbraEslintConfig = { // extension) break. // // @see https://github.com/microsoft/vscode-eslint/issues/1706#issuecomment-1916389417 - config: require.resolve('@penumbra-zone/tailwind-config'), + config: require.resolve('@repo/tailwind-config'), }, }, rules: { diff --git a/packages/eslint-config/package.json b/packages/eslint-config/package.json index a23afc1b..b1e103da 100644 --- a/packages/eslint-config/package.json +++ b/packages/eslint-config/package.json @@ -1,5 +1,5 @@ { - "name": "@penumbra-zone/eslint-config", + "name": "@repo/eslint-config", "version": "1.0.1", "private": true, "license": "(MIT OR Apache-2.0)", diff --git a/packages/getters/CHANGELOG.md b/packages/getters/CHANGELOG.md deleted file mode 100644 index df091bad..00000000 --- a/packages/getters/CHANGELOG.md +++ /dev/null @@ -1,118 +0,0 @@ -# @penumbra-zone/getters - -## 6.1.0 - -### Minor Changes - -- 6b06e04: Introduce ZQuery package and use throughout minifront - -## 6.0.0 - -### Major Changes - -- 8fe4de6: correct ordering of default export - -### Patch Changes - -- Updated dependencies [8fe4de6] - - @penumbra-zone/bech32m@5.0.0 - -## 5.0.0 - -### Major Changes - -- 8b121ec: change package exports to use 'default' field - -### Patch Changes - -- Updated dependencies [8b121ec] - - @penumbra-zone/bech32m@4.0.0 - -## 4.1.0 - -### Minor Changes - -- 120b654: Support estimates of outputs for auctions; redesign the estimate results part of the swap/auction UI -- 3ea1e6c: update buf types dependencies - -### Patch Changes - -- Updated dependencies [3ea1e6c] - - @penumbra-zone/bech32m@3.2.0 - -## 4.0.0 - -### Major Changes - -- 8ccaf30: remove /src/ segment of import path -- 8ccaf30: externalize dependencies - -### Minor Changes - -- 146b48d: Support GDAs -- cf63b30: Show swap routes in the UI; extract a component. - -### Patch Changes - -- 8ccaf30: readme update recommending bsr -- e35c6f7: Deps bumped to latest -- Updated dependencies [e35c6f7] - - @penumbra-zone/bech32m@3.1.1 - -## 3.0.2 - -### Patch Changes - -- Updated dependencies - - @penumbra-zone/bech32m@3.1.0 - -## 3.0.1 - -### Patch Changes - -- Updated dependencies [8410d2f] - - @penumbra-zone/bech32m@3.0.1 - -## 3.0.0 - -### Major Changes - -- 3148375: remove `/src/` path segment from exports - -### Patch Changes - -- Updated dependencies [3148375] -- Updated dependencies [fdd4303] - - @penumbra-zone/constants@4.0.0 - - @penumbra-zone/bech32m@3.0.0 - -## 2.0.1 - -### Patch Changes - -- Updated dependencies [862283c] - - @penumbra-zone/constants@3.0.0 - -## 2.0.0 - -### Major Changes - -- 929d278: barrel imports to facilitate better tree shaking - -### Patch Changes - -- Updated dependencies [8933117] -- Updated dependencies [929d278] - - @penumbra-zone/constants@2.0.0 - - @penumbra-zone/bech32@2.0.0 - -## 1.1.0 - -### Minor Changes - -- Initial changest. Git tag v5.0.0 updates. - -### Patch Changes - -- Updated dependencies - - @penumbra-zone/constants@1.1.0 diff --git a/packages/getters/README.md b/packages/getters/README.md deleted file mode 100644 index 7e59f004..00000000 --- a/packages/getters/README.md +++ /dev/null @@ -1,108 +0,0 @@ -# Getters - -**To use this package, you need to [enable the Buf Schema Registry](https://buf.build/docs/bsr/generated-sdks/npm)** - -```sh -echo "@buf:registry=https://buf.build/gen/npm/v1/" >> .npmrc -``` - -Getters were designed to solve a common pain point when working with deserialized Protobuf messages: accessing deeply nested, often optional properties. - -For example, let's say you have an `AddressView`, and you want to render an `AddressIndex`. You'd need render it conditionally, like so: - -```tsx -

- {addressView.addressView.case === 'decoded' && addressView.addressView.value.index?.account && ( - {addressView.addressView.value.index.account} - )} -
-``` - -Not very readable, and pretty annoying to type. But it can get even worse! Imagine you now have a `MemoView`, which _optionally contains_ an `AddressView`. You still want to render an `AddressIndex`. So you'd render it with even more conditions, like so: - -```tsx -
- {memoView.memoView.case === 'visible' && - memoView.memoView.value.plaintext?.returnAddress.addressView.case === 'decoded' && - memoView.memoView.value.plaintext.returnAddress.addressView.value.index?.account && ( - {addressView.addressView.value.index.account} - )} -
-``` - -This quickly gets pretty cumbersome. You could, of course, throw a bunch of type guards at the top of your component to simplify your markup: - -```tsx -if (memoView.memoView.case !== 'visible') throw new Error() -if (memoView.memoView.value.plaintext?.returnAddress.addressView.case !== 'decoded') throw new Error() -if (typeof memoView.memoView.value.plaintext.returnAddress.addressView.value.index?.account === 'undefined') throw new Error() - -
- {addressView.addressView.value.index.account} -
-``` - -This works, but you still have a bunch of boilerplate code crowding your component. - -Getters solve all that. Getters are tiny, composable functions, inspired by the functional programming [lens pattern](https://www.bekk.christmas/post/2019/6/the-lens-pattern-in-typescript), that allow you to get at deeply nested, often optional properties without all the boilerplate. - -Let's solve the above problem with getters. First, let's create a getter that, when given a `MemoView`, returns its `AddressView`: - -```ts -const getAddressView = createGetter((memoView?: MemoView) => - memoView.memoView.case === 'visible' ? memoView.memoView.plaintext?.returnAddress : undefined, -); -``` - -`getAddressView()` is now a simple function that can be called with a `MemoView`, like this: `getAddressView(memoView)`. It will then return the `AddressView`, or throw if it's `undefined`. - -OK, next, let's create another getter that, when given an `AddressView`, returns its `AddressIndex`: - -```ts -const getAddressIndex = createGetter((addressView?: AddressView) => - addressView?.addressView.case === 'decoded' ? addressView.addressView.value.index : undefined, -); -``` - -Again, `getAddressIndex()` is a simple function that can be called with an `AddressView`, like this: `getAddressIndex(addressView)`. It will then return the `AddressIndex`, or throw if it's `undefined`. - -Since we defined these two functions with `createGetter()`, though, they have a `pipe` method that let us chain them together. That way, we can easily create a getter that, when given a `MemoView`, will return an `AddressIndex`: - -```ts -const getAddressIndexFromMemoView = getAddressView.pipe(getAddressIndex); -``` - -OK, now we can quickly clean up our component code: - -```tsx -
- {getAddressIndexFromMemoView(memoView)} -
-``` - -Way better! - -At this point, it's worth mentioning that getters are _required by default_. If any step along the getter chain above returns `undefined`, they will throw a `GetterMissingValueError`. - -(It might seem unintuitive that getter functions are required, but are defined with an _optional_ argument -- e.g., `createGetter((addressView?: AddressView) => ... )`. Without that optionality, you'd get a TypeScript complaint like `Type 'undefined' is not assignable to type 'AddressView'.` Getters assume that they can be passed `undefined`; otherwise, TypeScript would make `pipe()`ing impossible, since deeply nested properties are often optional. Don't worry, though: `createGetter` ensures that your getters still throw if they get `undefined`, which is what guarantees type safety.) - -What if the value you're getting _is_ optional, though? What if you don't want your getter to throw if either the value it's passed, or the value it returns, is `undefined`? That's what the `.optional()` property on the getter is for: - -```tsx -const addressView = getAddressView.optional()(memoView) - -
- {addressView && } -
-``` - -Or, if you want to chain multiple getters together and make the whole chain optional, call `.optional()` on the _first_ getter in the chain (which will then mark the rest of the chain as optional, too): - -```tsx -const getAddressIndexFromMemoView = getAddressView.optional().pipe(getAddressIndex); -const addressIndex = getAddressIndexFromMemoView(memoView) - -
- {addressIndex && } -
-``` diff --git a/packages/getters/package.json b/packages/getters/package.json deleted file mode 100644 index 332a875f..00000000 --- a/packages/getters/package.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "name": "@penumbra-zone/getters", - "version": "6.1.0", - "private": true, - "license": "(MIT OR Apache-2.0)", - "description": "Convenience getters for the deeply nested optionals of Penumbra's protobuf types", - "type": "module", - "scripts": { - "build": "tsc && vite build", - "clean": "rm -rfv dist", - "lint": "eslint src", - "test": "vitest run" - }, - "files": [ - "dist" - ], - "exports": { - "./*": "./src/*.ts" - }, - "publishConfig": { - "exports": { - "./*": { - "types": "./dist/*.d.ts", - "default": "./dist/*.js" - } - } - }, - "dependencies": { - "@penumbra-zone/bech32m": "workspace:*" - }, - "devDependencies": { - "@buf/penumbra-zone_penumbra.bufbuild_es": "1.9.0-20240528180215-8fe1c79485f8.1", - "@bufbuild/protobuf": "^1.10.0" - }, - "peerDependencies": { - "@buf/penumbra-zone_penumbra.bufbuild_es": "1.9.0-20240528180215-8fe1c79485f8.1", - "@bufbuild/protobuf": "^1.10.0" - } -} diff --git a/packages/getters/src/address-view.ts b/packages/getters/src/address-view.ts deleted file mode 100644 index 745db65f..00000000 --- a/packages/getters/src/address-view.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { AddressView } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb'; -import { createGetter } from './utils/create-getter'; - -export const getAddressIndex = createGetter((addressView?: AddressView) => - addressView?.addressView.case === 'decoded' ? addressView.addressView.value.index : undefined, -); - -export const getAddress = createGetter( - (addressView?: AddressView) => addressView?.addressView.value?.address, -); diff --git a/packages/getters/src/assets-response.ts b/packages/getters/src/assets-response.ts deleted file mode 100644 index 3ce91a8d..00000000 --- a/packages/getters/src/assets-response.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { createGetter } from './utils/create-getter'; -import { AssetsResponse } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; - -export const getDenomMetadata = createGetter( - (assetsResponse?: AssetsResponse) => assetsResponse?.denomMetadata, -); diff --git a/packages/getters/src/balances-response.ts b/packages/getters/src/balances-response.ts deleted file mode 100644 index 463a2b0e..00000000 --- a/packages/getters/src/balances-response.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { BalancesResponse } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; -import { createGetter } from './utils/create-getter'; -import { getMetadata } from './value-view'; -import { getAssetId, getDisplay } from './metadata'; - -export const getBalanceView = createGetter( - (balancesResponse?: BalancesResponse) => balancesResponse?.balanceView, -); - -export const getAssetIdFromBalancesResponseOptional = getBalanceView - .optional() - .pipe(getMetadata) - .pipe(getAssetId); - -export const getMetadataFromBalancesResponse = getBalanceView.pipe(getMetadata); - -export const getDisplayFromBalancesResponse = getMetadataFromBalancesResponse - .optional() - .pipe(getDisplay); - -export const getMetadataFromBalancesResponseOptional = getBalanceView.optional().pipe(getMetadata); - -export const getAddressIndex = createGetter((balancesResponse?: BalancesResponse) => - balancesResponse?.accountAddress?.addressView.case === 'decoded' - ? balancesResponse.accountAddress.addressView.value.index - : undefined, -); - -export const getAmount = createGetter( - (balancesResponse?: BalancesResponse) => balancesResponse?.balanceView?.valueView.value?.amount, -); diff --git a/packages/getters/src/batch-swap-output-data.ts b/packages/getters/src/batch-swap-output-data.ts deleted file mode 100644 index 27aa676c..00000000 --- a/packages/getters/src/batch-swap-output-data.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { createGetter } from './utils/create-getter'; -import { getAsset1, getAsset2 } from './trading-pair'; -import { BatchSwapOutputData } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/dex/v1/dex_pb'; - -export const getTradingPair = createGetter((b?: BatchSwapOutputData) => b?.tradingPair); -export const getSwapAsset1 = getTradingPair.pipe(getAsset1); -export const getSwapAsset2 = getTradingPair.pipe(getAsset2); - -export const getDelta1Amount = createGetter((b?: BatchSwapOutputData) => b?.delta1); -export const getDelta2Amount = createGetter((b?: BatchSwapOutputData) => b?.delta2); -export const getLambda1Amount = createGetter((b?: BatchSwapOutputData) => b?.lambda1); -export const getLambda2Amount = createGetter((b?: BatchSwapOutputData) => b?.lambda2); -export const getUnfilled1Amount = createGetter((b?: BatchSwapOutputData) => b?.unfilled1); -export const getUnfilled2Amount = createGetter((b?: BatchSwapOutputData) => b?.unfilled2); diff --git a/packages/getters/src/bonding-state.ts b/packages/getters/src/bonding-state.ts deleted file mode 100644 index c52b54f0..00000000 --- a/packages/getters/src/bonding-state.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { BondingState } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/stake/v1/stake_pb'; -import { createGetter } from './utils/create-getter'; - -export const getBondingStateEnum = createGetter( - (bondingState?: BondingState) => bondingState?.state, -); diff --git a/packages/getters/src/delegations-by-address-index-response.ts b/packages/getters/src/delegations-by-address-index-response.ts deleted file mode 100644 index 891f1cb7..00000000 --- a/packages/getters/src/delegations-by-address-index-response.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { DelegationsByAddressIndexResponse } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; -import { createGetter } from './utils/create-getter'; - -export const getValueView = createGetter( - (delegationsByAddressIndexResponse?: DelegationsByAddressIndexResponse) => - delegationsByAddressIndexResponse?.valueView, -); diff --git a/packages/getters/src/dutch-auction-description.ts b/packages/getters/src/dutch-auction-description.ts deleted file mode 100644 index 51931c28..00000000 --- a/packages/getters/src/dutch-auction-description.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { DutchAuctionDescription } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/auction/v1/auction_pb'; -import { createGetter } from './utils/create-getter'; - -export const getInputAssetId = createGetter( - (dutchAuctionDescription?: DutchAuctionDescription) => dutchAuctionDescription?.input?.assetId, -); - -export const getOutputAssetId = createGetter( - (dutchAuctionDescription?: DutchAuctionDescription) => dutchAuctionDescription?.outputId, -); diff --git a/packages/getters/src/dutch-auction.ts b/packages/getters/src/dutch-auction.ts deleted file mode 100644 index 24fe3249..00000000 --- a/packages/getters/src/dutch-auction.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { DutchAuction } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/auction/v1/auction_pb'; -import { createGetter } from './utils/create-getter'; - -export const getDescription = createGetter( - (dutchAuction?: DutchAuction) => dutchAuction?.description, -); - -export const getInputAssetId = createGetter( - (dutchAuction?: DutchAuction) => dutchAuction?.description?.input?.assetId, -); - -export const getOutputAssetId = createGetter( - (dutchAuction?: DutchAuction) => dutchAuction?.description?.outputId, -); diff --git a/packages/getters/src/equivalent-value.ts b/packages/getters/src/equivalent-value.ts deleted file mode 100644 index 48cd9f79..00000000 --- a/packages/getters/src/equivalent-value.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { - EquivalentValue, - ValueView, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; -import { createGetter } from './utils/create-getter'; - -export const asValueView = createGetter((equivalentValue?: EquivalentValue) => - equivalentValue - ? new ValueView({ - valueView: { - case: 'knownAssetId', - value: { - amount: equivalentValue.equivalentAmount, - metadata: equivalentValue.numeraire, - }, - }, - }) - : undefined, -); diff --git a/packages/getters/src/fee.ts b/packages/getters/src/fee.ts deleted file mode 100644 index 26a4b813..00000000 --- a/packages/getters/src/fee.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { createGetter } from './utils/create-getter'; -import { Fee } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/fee/v1/fee_pb'; - -export const getAmount = createGetter((fee?: Fee) => fee?.amount); diff --git a/packages/getters/src/funding-stream.ts b/packages/getters/src/funding-stream.ts deleted file mode 100644 index b1f567c6..00000000 --- a/packages/getters/src/funding-stream.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { FundingStream } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/stake/v1/stake_pb'; -import { createGetter } from './utils/create-getter'; - -export const getRateBpsFromFundingStream = createGetter( - (fundingStream?: FundingStream) => fundingStream?.recipient.value?.rateBps, -); diff --git a/packages/getters/src/get-validator-info-response.ts b/packages/getters/src/get-validator-info-response.ts deleted file mode 100644 index 7528a5e7..00000000 --- a/packages/getters/src/get-validator-info-response.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { createGetter } from './utils/create-getter'; -import { GetValidatorInfoResponse } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/stake/v1/stake_pb'; - -export const getValidatorInfo = createGetter( - (validatorInfoResponse?: GetValidatorInfoResponse) => validatorInfoResponse?.validatorInfo, -); diff --git a/packages/getters/src/metadata.test.ts b/packages/getters/src/metadata.test.ts deleted file mode 100644 index 1376fb65..00000000 --- a/packages/getters/src/metadata.test.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { Metadata } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; -import { describe, expect, it } from 'vitest'; -import { getDisplayDenomExponent } from './metadata'; - -describe('getDisplayDenomExponent()', () => { - it("gets the exponent from the denom unit whose `denom` is equal to the metadata's `display` property", () => { - const penumbraMetadata = new Metadata({ - display: 'penumbra', - denomUnits: [ - { - denom: 'penumbra', - exponent: 6, - }, - { - denom: 'mpenumbra', - exponent: 3, - }, - { - denom: 'upenumbra', - exponent: 0, - }, - ], - }); - - expect(getDisplayDenomExponent(penumbraMetadata)).toBe(6); - }); -}); diff --git a/packages/getters/src/metadata.ts b/packages/getters/src/metadata.ts deleted file mode 100644 index 046a96ce..00000000 --- a/packages/getters/src/metadata.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Metadata } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; -import { createGetter } from './utils/create-getter'; - -export const getAssetId = createGetter((metadata?: Metadata) => metadata?.penumbraAssetId); - -/** - * Returns the exponent for a given asset type's display denom unit, given that - * denom's metadata. - * - * `Metadata`s have an array of `DenomUnit`s, describing the exponent of - * each denomination in relation to the base unit. For example, upenumbra is - * penumbra's base unit -- the unit which can not be further divided into - * decimals. 1 penumbra is equal to 1,000,000 (AKA, 10 to the 6th) upenumbra, so - * penumbra's display exponent -- the exponent used to multiply the base unit - * when displaying a penumbra value to a user -- is 6. (For a non-crypto - * example, think of US dollars. The dollar is the display unit; the cent is the - * base unit; the display exponent is 2 (10 to the 2nd).) - */ -export const getDisplayDenomExponent = createGetter( - (metadata?: Metadata) => - metadata?.denomUnits.find(denomUnit => denomUnit.denom === metadata.display)?.exponent, -); - -export const getDisplay = createGetter((metadata?: Metadata) => metadata?.display); - -export const getSymbol = createGetter((metadata?: Metadata) => metadata?.symbol); diff --git a/packages/getters/src/note-view.ts b/packages/getters/src/note-view.ts deleted file mode 100644 index 66d0185a..00000000 --- a/packages/getters/src/note-view.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { NoteView } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/shielded_pool/v1/shielded_pool_pb'; -import { createGetter } from './utils/create-getter'; - -export const getValue = createGetter((noteView?: NoteView) => noteView?.value); -export const getAddress = createGetter((noteView?: NoteView) => noteView?.address); diff --git a/packages/getters/src/output-view.ts b/packages/getters/src/output-view.ts deleted file mode 100644 index 99c6a686..00000000 --- a/packages/getters/src/output-view.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { OutputView } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/shielded_pool/v1/shielded_pool_pb'; -import { createGetter } from './utils/create-getter'; - -export const getNote = createGetter((outputView?: OutputView) => - outputView?.outputView.case === 'visible' ? outputView.outputView.value.note : undefined, -); diff --git a/packages/getters/src/rate-data.ts b/packages/getters/src/rate-data.ts deleted file mode 100644 index 9508352d..00000000 --- a/packages/getters/src/rate-data.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { RateData } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/stake/v1/stake_pb'; -import { createGetter } from './utils/create-getter'; - -export const getValidatorRewardRate = createGetter( - (rateData?: RateData) => rateData?.validatorRewardRate, -); - -export const getValidatorExchangeRate = createGetter( - (rateData?: RateData) => rateData?.validatorExchangeRate, -); diff --git a/packages/getters/src/spend-view.ts b/packages/getters/src/spend-view.ts deleted file mode 100644 index b5538c2c..00000000 --- a/packages/getters/src/spend-view.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { SpendView } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/shielded_pool/v1/shielded_pool_pb'; -import { createGetter } from './utils/create-getter'; - -export const getNote = createGetter((spendView?: SpendView) => - spendView?.spendView.case === 'visible' ? spendView.spendView.value.note : undefined, -); diff --git a/packages/getters/src/spendable-note-record.ts b/packages/getters/src/spendable-note-record.ts deleted file mode 100644 index 9093510e..00000000 --- a/packages/getters/src/spendable-note-record.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { createGetter } from './utils/create-getter'; -import { SpendableNoteRecord } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; - -export const getAssetIdFromRecord = createGetter( - (noteRecord?: SpendableNoteRecord) => noteRecord?.note?.value?.assetId, -); - -export const getAmountFromRecord = createGetter( - (noteRecord?: SpendableNoteRecord) => noteRecord?.note?.value?.amount, -); diff --git a/packages/getters/src/swap-claim-view.ts b/packages/getters/src/swap-claim-view.ts deleted file mode 100644 index 5b72ed66..00000000 --- a/packages/getters/src/swap-claim-view.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { SwapClaimView } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/dex/v1/dex_pb'; -import { createGetter } from './utils/create-getter'; -import { getValue } from './note-view'; - -export const getOutput1 = createGetter((swapClaimView?: SwapClaimView) => - swapClaimView?.swapClaimView.case === 'visible' - ? swapClaimView.swapClaimView.value.output1 - : undefined, -); - -export const getOutput2 = createGetter((swapClaimView?: SwapClaimView) => - swapClaimView?.swapClaimView.case === 'visible' - ? swapClaimView.swapClaimView.value.output2 - : undefined, -); - -export const getOutput1ValueOptional = getOutput1.optional().pipe(getValue); -export const getOutput2ValueOptional = getOutput2.optional().pipe(getValue); - -export const getSwapClaimFee = createGetter((swapClaimView?: SwapClaimView) => - swapClaimView?.swapClaimView.case === 'visible' || swapClaimView?.swapClaimView.case === 'opaque' - ? swapClaimView.swapClaimView.value.swapClaim?.body?.fee - : undefined, -); diff --git a/packages/getters/src/swap-record.ts b/packages/getters/src/swap-record.ts deleted file mode 100644 index 30ad4843..00000000 --- a/packages/getters/src/swap-record.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { createGetter } from './utils/create-getter'; -import { SwapRecord } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; -import { getAsset1, getAsset2 } from './trading-pair'; - -export const getSwapRecordCommitment = createGetter((swap?: SwapRecord) => swap?.swapCommitment); -export const getTradingPair = createGetter((s?: SwapRecord) => s?.swap?.tradingPair); -export const getSwapAsset1 = getTradingPair.pipe(getAsset1); -export const getSwapAsset2 = getTradingPair.pipe(getAsset2); diff --git a/packages/getters/src/swap-view.ts b/packages/getters/src/swap-view.ts deleted file mode 100644 index dc210bfb..00000000 --- a/packages/getters/src/swap-view.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { - SwapBody, - SwapPlaintext, - SwapView, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/dex/v1/dex_pb'; -import { createGetter } from './utils/create-getter'; - -// Generic getter function for 'Output1' -export const getOutput1Value = createGetter((swapView?: SwapView) => { - switch (swapView?.swapView.case) { - case 'visible': - return swapView.swapView.value.output1?.value; - case 'opaque': - return swapView.swapView.value.output1Value; - default: - return undefined; - } -}); - -// Generic getter function for 'Output2' -export const getOutput2Value = createGetter((swapView?: SwapView) => { - switch (swapView?.swapView.case) { - case 'visible': - return swapView.swapView.value.output2?.value; - case 'opaque': - return swapView.swapView.value.output2Value; - default: - return undefined; - } -}); - -// Generic getter function that returns the value of a specified property from either 'swapPlaintext' or 'swapBody'. -// This pattern utilizes parameterized types, 'T', to handle property access, 'K' within different nested objects based on the case -// of 'SwapView'. These parameterized types can represent an intersection of multiple types. -type SwapBodyCombined = SwapPlaintext & SwapBody; -const createSwapGetter = (property: K) => { - return createGetter((swapView?: SwapView) => { - let swapValue: SwapBodyCombined[K] | undefined; - - switch (swapView?.swapView.case) { - case 'visible': - swapValue = swapView.swapView.value.swapPlaintext?.[property as keyof SwapPlaintext] as - | SwapBodyCombined[K] - | undefined; - break; - case 'opaque': - swapValue = swapView.swapView.value.swap?.body?.[property as keyof SwapBody] as - | SwapBodyCombined[K] - | undefined; - break; - default: - return undefined; - } - - if (swapValue === undefined) { - return undefined; - } - - return swapValue; - }); -}; - -// Generic getter function for 'delta1I' -export const getDelta1IFromSwapView = createSwapGetter<'delta1I'>('delta1I'); - -// Generic getter function for 'delta2I' -export const getDelta2IFromSwapView = createSwapGetter<'delta2I'>('delta2I'); - -// Generic getter function for 'claimFee' -export const getClaimFeeFromSwapView = createSwapGetter<'claimFee'>('claimFee'); - -// Generic getter function for 'Asset1Metadata' -export const getAsset1Metadata = createGetter((swapView?: SwapView) => - swapView?.swapView.case === 'visible' || swapView?.swapView.case === 'opaque' - ? swapView.swapView.value.asset1Metadata - : undefined, -); - -// Generic getter function for 'Asset2Metadata' -export const getAsset2Metadata = createGetter((swapView?: SwapView) => - swapView?.swapView.case === 'visible' || swapView?.swapView.case === 'opaque' - ? swapView.swapView.value.asset2Metadata - : undefined, -); - -// Getter function for 'ClaimTx' -export const getClaimTx = createGetter((swapView?: SwapView) => - swapView?.swapView.case === 'visible' ? swapView.swapView.value.claimTx : undefined, -); - -/** - * This is a sort of odd getter. It looks in both `output1` and `output2` for - * the output address. We could get the address from `claimAddress` under the - * `swapPlaintext` property, but that's just an `Address`, not an `AddressView`, - * and we want to display the address view because that includes details like - * the account index. - */ -export const getAddressView = createGetter((swapView?: SwapView) => - swapView?.swapView.case === 'visible' - ? swapView.swapView.value.output1?.address ?? swapView.swapView.value.output2?.address - : undefined, -); diff --git a/packages/getters/src/swap.ts b/packages/getters/src/swap.ts deleted file mode 100644 index ef3a5b18..00000000 --- a/packages/getters/src/swap.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { createGetter } from './utils/create-getter'; -import { Swap } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/dex/v1/dex_pb'; - -export const getCommitment = createGetter((swap?: Swap) => swap?.body?.payload?.commitment); diff --git a/packages/getters/src/trading-pair.ts b/packages/getters/src/trading-pair.ts deleted file mode 100644 index 2dbd85db..00000000 --- a/packages/getters/src/trading-pair.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { createGetter } from './utils/create-getter'; -import { TradingPair } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/dex/v1/dex_pb'; - -export const getAsset1 = createGetter((pair?: TradingPair) => pair?.asset1); -export const getAsset2 = createGetter((pair?: TradingPair) => pair?.asset2); diff --git a/packages/getters/src/transaction.ts b/packages/getters/src/transaction.ts deleted file mode 100644 index dd6fdc8b..00000000 --- a/packages/getters/src/transaction.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { createGetter } from './utils/create-getter'; -import { Transaction } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/transaction/v1/transaction_pb'; -import { Swap } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/dex/v1/dex_pb'; -import { getCommitment } from './swap'; - -const getSwap = createGetter( - (transaction?: Transaction) => - transaction?.body?.actions.find(action => action.action.case === 'swap')?.action.value as - | Swap - | undefined, -); - -export const getSwapCommitmentFromTx = getSwap.pipe(getCommitment); diff --git a/packages/getters/src/unbonding-tokens-by-address-index-response.ts b/packages/getters/src/unbonding-tokens-by-address-index-response.ts deleted file mode 100644 index 21dec850..00000000 --- a/packages/getters/src/unbonding-tokens-by-address-index-response.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { UnbondingTokensByAddressIndexResponse } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; -import { createGetter } from './utils/create-getter'; - -export const getValueView = createGetter( - (unbondingTokensByAddressIndexResponse?: UnbondingTokensByAddressIndexResponse) => - unbondingTokensByAddressIndexResponse?.valueView, -); diff --git a/packages/getters/src/unclaimed-swaps-response.ts b/packages/getters/src/unclaimed-swaps-response.ts deleted file mode 100644 index 1031bc33..00000000 --- a/packages/getters/src/unclaimed-swaps-response.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { createGetter } from './utils/create-getter'; -import { UnclaimedSwapsResponse } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; - -export const getUnclaimedSwaps = createGetter( - (response?: UnclaimedSwapsResponse) => response?.swap, -); diff --git a/packages/getters/src/undelegate-claim-body.ts b/packages/getters/src/undelegate-claim-body.ts deleted file mode 100644 index 5734de8a..00000000 --- a/packages/getters/src/undelegate-claim-body.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { UndelegateClaimBody } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/stake/v1/stake_pb'; -import { createGetter } from './utils/create-getter'; - -export const getValidatorIdentity = createGetter( - (undelegateClaimBody?: UndelegateClaimBody) => undelegateClaimBody?.validatorIdentity, -); diff --git a/packages/getters/src/undelegate-claim.ts b/packages/getters/src/undelegate-claim.ts deleted file mode 100644 index 7af2253e..00000000 --- a/packages/getters/src/undelegate-claim.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { - UndelegateClaim, - UndelegateClaimBody, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/stake/v1/stake_pb'; -import { createGetter } from './utils/create-getter'; -import { getValidatorIdentity } from './undelegate-claim-body'; - -export const getBody = createGetter((undelegateClaim?: UndelegateClaim) => undelegateClaim?.body); - -export const getValidatorIdentityFromUndelegateClaim = getBody.pipe(getValidatorIdentity); - -export const getUnbondingStartHeightFromUndelegateClaim = getBody.pipe( - // Defining this inline rather than exporting `getUnbondingStartHeight` from - // `undelegate-claim-body.ts`, since `getUnbondingStartHeight` is already - // defined elsewhere and thus would result in a naming conflict in the exports - // from this package. - createGetter( - (undelegateClaimBody?: UndelegateClaimBody) => undelegateClaimBody?.unbondingStartHeight, - ), -); diff --git a/packages/getters/src/utils/create-getter.test.ts b/packages/getters/src/utils/create-getter.test.ts deleted file mode 100644 index 38f41302..00000000 --- a/packages/getters/src/utils/create-getter.test.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { describe, expect, it } from 'vitest'; -import { createGetter } from './create-getter'; - -interface Address { - city: string; - state: string; - country?: string; -} - -interface Employee { - firstName: string; - lastName?: string; - address?: Address; -} - -const employee: Employee = { - firstName: 'Alice', - address: { - city: 'San Francisco', - state: 'California', - }, -}; - -const getFirstName = createGetter((employee?: Employee) => employee?.firstName); -const getLastName = createGetter((employee?: Employee) => employee?.lastName); -const getAddress = createGetter((employee?: Employee) => employee?.address); -const getCity = createGetter((address?: Address) => address?.city); -const getCountry = createGetter((address?: Address) => address?.country); -const getFirstLetter = createGetter((value?: string) => value?.[0]); - -describe('createGetter()', () => { - describe('getter()', () => { - it('gets the value via the function passed into `createGetter()`', () => { - expect(getFirstName(employee)).toBe('Alice'); - }); - - it('throws when the whole value is undefined', () => { - expect(() => getFirstName(undefined)).toThrow(); - }); - - it('throws for an undefined property', () => { - expect(() => getLastName(employee)).toThrow(); - }); - - it('does not throw if a value is falsey but not undefined', () => { - const employee: Employee = { firstName: 'Alice', lastName: '' }; - expect(() => getLastName(employee)).not.toThrow(); - }); - }); - - describe('getter.optional()', () => { - it('returns `undefined` when the whole value is undefined', () => { - expect(getLastName.optional()(undefined)).toBeUndefined(); - }); - - it('returns `undefined` for an undefined property', () => { - expect(getLastName.optional()(employee)).toBeUndefined(); - }); - }); - - describe('getter.pipe()', () => { - it('pipes the getters together and returns the final result', () => { - expect(getAddress.pipe(getCity)(employee)).toBe('San Francisco'); - }); - - it('throws when any value in the property chain is undefined', () => { - expect(() => getAddress.pipe(getCity)(undefined)).toThrow(); - expect(() => getAddress.pipe(getCity)({ firstName: 'Alice' })).toThrow(); - expect(() => getAddress.pipe(getCountry)(employee)).toThrow(); - }); - - describe('getter.pipe() with .optional())', () => { - const employee: Employee = { - firstName: 'Alice', - address: { - city: '', // `getFirstLetter` will return undefined - state: 'California', - }, - }; - - it('does not throw when the first getter is used with `.optional()` and some value in the chain is undefined', () => { - expect(() => - getAddress.optional().pipe(getCity).pipe(getFirstLetter)(employee), - ).not.toThrow(); - }); - }); - }); -}); diff --git a/packages/getters/src/utils/create-getter.ts b/packages/getters/src/utils/create-getter.ts deleted file mode 100644 index c57869c1..00000000 --- a/packages/getters/src/utils/create-getter.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { Getter } from './getter'; -import { GetterMissingValueError } from './getter-missing-value-error'; - -export const createGetter = ( - getterFunction: (value: SourceType | undefined) => TargetType | undefined, - optional?: Optional, -): Getter => { - const getter: Getter = value => { - const result = getterFunction(value); - if (result === undefined && !optional) { - const errorMessage = `Failed to extract from ${JSON.stringify(value)}`; - throw new GetterMissingValueError(errorMessage); - } - return result as Optional extends true ? TargetType | undefined : TargetType; - }; - - getter.optional = () => - createGetter(value => getterFunction(value), true); - - getter.pipe = ( - next: Getter, - ) => { - return createGetter(value => { - try { - return next(getterFunction(value)); - } catch (e) { - if (!optional || !(e instanceof GetterMissingValueError)) throw e; - else return undefined; - } - }, optional); - }; - - return getter; -}; diff --git a/packages/getters/src/utils/getter-missing-value-error.ts b/packages/getters/src/utils/getter-missing-value-error.ts deleted file mode 100644 index 755f855d..00000000 --- a/packages/getters/src/utils/getter-missing-value-error.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * This error will be thrown when a getter that hasn't been marked `.optional()` - * returns `undefined`. You can import this error class in your code to - * differentiate between this specific type of error and others. (If you want to - * catch this error just to make a getter optional, though, it's easier to just - * call `.optional()` on the getter first: - * `getAddressIndex.optional()(addressView)`.) - */ -export class GetterMissingValueError extends Error {} diff --git a/packages/getters/src/utils/getter.ts b/packages/getters/src/utils/getter.ts deleted file mode 100644 index bc49b4ad..00000000 --- a/packages/getters/src/utils/getter.ts +++ /dev/null @@ -1,56 +0,0 @@ -/** - * Given a value of type `SourceType`, returns a (possibly nested) property of - * that value, of type `TargetType`. If `Optional` is `true`, returns - * undefined if the property or an ancestor is undefined; if `false`, throws - * when the property or an ancestor is undefined. - */ -type GetterFunction = ( - value: SourceType | undefined, -) => Optional extends true ? TargetType | undefined : TargetType; - -interface GetterMethods { - /** - * Returns a getter that, when given a value of type `SourceType`, returns a - * (possibly nested) property of that value, of type `TargetType`. If the - * property or any of its ancestors are undefined, returned undefined. - * - * @example - * ```ts - * const getMetadata = createGetter(valueView => - * valueView?.valueView.case === 'knownAssetId' ? valueView.valueView.value.metadata : undefined, - * ); - * - * // Note that `valueView` has no metadata, nor even a `case`. - * const valueView = new ValueView(); - * - * // Doesn't throw, even though the metadata is missing. - * const metadata = getMetadata.optional()(valueView); - * ``` - */ - optional: () => Getter; - - /** - * Pipes the output of this getter to another getter or getter function. - * - * @example - * ```ts - * // Gets the deeply nested `inner` property in a metadata object, or throws - * // if any step in the pipe is undefined. - * const assetId1 = getMetadata.pipe(getAssetId).pipe(getInner)(valueView); - * // Gets the deeply nested `inner` property in a metadata object, or returns - * // undefined if any step in the pipe is undefined. Note that `.optional()` - * // must be called at the _beginning_ of the chain. - * const assetId2 = getMetadata.optional().pipe(getAssetId).pipe(getInner)(valueView); - * ``` - */ - pipe: ( - pipedGetter: Getter, - ) => Getter; -} - -export type Getter< - SourceType = unknown, - TargetType = unknown, - Optional extends boolean = false, -> = GetterFunction & - GetterMethods; diff --git a/packages/getters/src/validator-info-response.ts b/packages/getters/src/validator-info-response.ts deleted file mode 100644 index 17c4617a..00000000 --- a/packages/getters/src/validator-info-response.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { ValidatorInfoResponse } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/stake/v1/stake_pb'; -import { createGetter } from './utils/create-getter'; -import { getIdentityKeyFromValidatorInfo, getRateData } from './validator-info'; -import { getValidatorExchangeRate } from './rate-data'; - -export const getValidatorInfo = createGetter( - (validatorInfoResponse?: ValidatorInfoResponse) => validatorInfoResponse?.validatorInfo, -); - -export const getExchangeRateFromValidatorInfoResponse = getValidatorInfo - .pipe(getRateData) - .pipe(getValidatorExchangeRate); - -export const getIdentityKeyFromValidatorInfoResponse = getValidatorInfo.pipe( - getIdentityKeyFromValidatorInfo, -); diff --git a/packages/getters/src/validator-info.ts b/packages/getters/src/validator-info.ts deleted file mode 100644 index d44f4509..00000000 --- a/packages/getters/src/validator-info.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { ValidatorInfo } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/stake/v1/stake_pb'; -import { createGetter } from './utils/create-getter'; -import { getBondingState, getState, getVotingPower } from './validator-status'; -import { getValidatorStateEnum } from './validator-state'; -import { getValidatorRewardRate } from './rate-data'; -import { getBondingStateEnum } from './bonding-state'; -import { getFundingStreams, getIdentityKey } from './validator'; - -export const getStatus = createGetter((validatorInfo?: ValidatorInfo) => validatorInfo?.status); - -export const getRateData = createGetter((validatorInfo?: ValidatorInfo) => validatorInfo?.rateData); - -export const getValidator = createGetter( - (validatorInfo?: ValidatorInfo) => validatorInfo?.validator, -); - -export const getVotingPowerFromValidatorInfo = getStatus.pipe(getVotingPower); - -export const getStateEnumFromValidatorInfo = getStatus.pipe(getState).pipe(getValidatorStateEnum); - -export const getBondingStateEnumFromValidatorInfo = getStatus - .pipe(getBondingState) - .pipe(getBondingStateEnum); - -export const getValidatorRewardRateFromValidatorInfoOptional = getStatus - .optional() - .pipe(getRateData) - .pipe(getValidatorRewardRate); - -export const getFundingStreamsFromValidatorInfo = getValidator.pipe(getFundingStreams); - -export const getIdentityKeyFromValidatorInfo = getValidator.pipe(getIdentityKey); diff --git a/packages/getters/src/validator-state.ts b/packages/getters/src/validator-state.ts deleted file mode 100644 index e109d3b8..00000000 --- a/packages/getters/src/validator-state.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { ValidatorState } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/stake/v1/stake_pb'; -import { createGetter } from './utils/create-getter'; - -export const getValidatorStateEnum = createGetter( - (validatorState?: ValidatorState) => validatorState?.state, -); diff --git a/packages/getters/src/validator-status.ts b/packages/getters/src/validator-status.ts deleted file mode 100644 index a5bb0167..00000000 --- a/packages/getters/src/validator-status.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { ValidatorStatus } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/stake/v1/stake_pb'; -import { createGetter } from './utils/create-getter'; - -export const getVotingPower = createGetter( - (validatorStatus?: ValidatorStatus) => validatorStatus?.votingPower, -); - -export const getState = createGetter((validatorStatus?: ValidatorStatus) => validatorStatus?.state); - -export const getBondingState = createGetter( - (validatorStatus?: ValidatorStatus) => validatorStatus?.bondingState, -); diff --git a/packages/getters/src/validator.ts b/packages/getters/src/validator.ts deleted file mode 100644 index 27d1b270..00000000 --- a/packages/getters/src/validator.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { Validator } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/stake/v1/stake_pb'; -import { createGetter } from './utils/create-getter'; - -export const getFundingStreams = createGetter((validator?: Validator) => validator?.fundingStreams); - -export const getIdentityKey = createGetter((validator?: Validator) => validator?.identityKey); diff --git a/packages/getters/src/value-view.ts b/packages/getters/src/value-view.ts deleted file mode 100644 index a050bab6..00000000 --- a/packages/getters/src/value-view.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { ValueView } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; -import { createGetter } from './utils/create-getter'; -import { bech32mAssetId } from '@penumbra-zone/bech32m/passet'; -import { getDisplayDenomExponent, getSymbol } from './metadata'; -import { Any } from '@bufbuild/protobuf'; -import { ValidatorInfo } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/stake/v1/stake_pb'; -import { getIdentityKeyFromValidatorInfo } from './validator-info'; - -export const getMetadata = createGetter((valueView?: ValueView) => - valueView?.valueView.case === 'knownAssetId' ? valueView.valueView.value.metadata : undefined, -); - -export const getExtendedMetadata = createGetter((valueView?: ValueView) => - valueView?.valueView.case === 'knownAssetId' - ? valueView.valueView.value.extendedMetadata - : undefined, -); - -export const getEquivalentValues = createGetter((valueView?: ValueView) => - valueView?.valueView.case === 'knownAssetId' - ? valueView.valueView.value.equivalentValues - : undefined, -); - -const getValidatorInfo = createGetter((any?: Any) => - any ? ValidatorInfo.fromBinary(any.value) : undefined, -); - -/** - * Only to be used on `ValueView`s that contain delegation tokens -- and thus, - * validator infos. - */ -export const getValidatorInfoFromValueView = getExtendedMetadata.pipe(getValidatorInfo); - -/** - * Only to be used on `ValueView`s that contain delegation tokens -- and thus, - * validator infos. - */ -export const getValidatorIdentityKeyFromValueView = getValidatorInfoFromValueView.pipe( - getIdentityKeyFromValidatorInfo, -); - -export const getDisplayDenomExponentFromValueView = createGetter((valueView?: ValueView) => - valueView?.valueView.case === 'knownAssetId' - ? getDisplayDenomExponent.optional()(valueView.valueView.value.metadata) - : undefined, -); - -export const getAssetIdFromValueView = createGetter((v?: ValueView) => { - switch (v?.valueView.case) { - case 'knownAssetId': - return v.valueView.value.metadata?.penumbraAssetId; - case 'unknownAssetId': - return v.valueView.value.assetId; - default: - return undefined; - } -}); - -export const getAmount = createGetter( - (valueView?: ValueView) => valueView?.valueView.value?.amount, -); - -export const getSymbolFromValueView = createGetter((valueView?: ValueView) => { - const metadata = getMetadata.optional()(valueView); - return getSymbol.optional()(metadata); -}); - -export const getDisplayDenomFromView = createGetter((view?: ValueView) => { - if (view?.valueView.case === 'unknownAssetId') { - if (!view.valueView.value.assetId) return undefined; - return bech32mAssetId(view.valueView.value.assetId); - } - - if (view?.valueView.case === 'knownAssetId') { - const displayDenom = view.valueView.value.metadata?.display; - if (displayDenom) return displayDenom; - - const assetId = view.valueView.value.metadata?.penumbraAssetId; - if (assetId) return bech32mAssetId(assetId); - - return 'unknown'; - } - - return 'unknown'; -}); diff --git a/packages/getters/src/value.ts b/packages/getters/src/value.ts deleted file mode 100644 index 994ccb1c..00000000 --- a/packages/getters/src/value.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { Value } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; -import { createGetter } from './utils/create-getter'; - -export const getAssetIdFromValue = createGetter((value?: Value) => value?.assetId); - -export const getAmountFromValue = createGetter((value?: Value) => value?.amount); diff --git a/packages/getters/tsconfig.json b/packages/getters/tsconfig.json deleted file mode 100644 index 459b3e49..00000000 --- a/packages/getters/tsconfig.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": "tsconfig/base.json", - "exclude": ["node_modules"], - "compilerOptions": { - "outDir": "dist", - "noEmit": true - } -} diff --git a/packages/getters/vite.config.ts b/packages/getters/vite.config.ts deleted file mode 100644 index 59c01ee6..00000000 --- a/packages/getters/vite.config.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { defineConfig } from 'vite'; -import dts from 'vite-plugin-dts'; -import { externalizeDeps } from 'vite-plugin-externalize-deps'; - -export default defineConfig({ - build: { - lib: { - entry: { - 'address-view': './src/address-view.ts', - 'batch-swap-output-data': './src/batch-swap-output-data.ts', - 'delegations-by-address-index-response': './src/delegations-by-address-index-response.ts', - 'funding-stream': './src/funding-stream.ts', - metadata: './src/metadata.ts', - 'rate-data': './src/rate-data.ts', - swap: './src/swap.ts', - 'swap-record': './src/swap-record.ts', - 'spendable-note-record': './src/spendable-note-record.ts', - 'trading-pair': './src/trading-pair.ts', - transaction: './src/transaction.ts', - 'unclaimed-swaps-response': './src/unclaimed-swaps-response.ts', - 'undelegate-claim': './src/undelegate-claim.ts', - 'undelegate-claim-body': './src/undelegate-claim-body.ts', - validator: './src/validator.ts', - 'validator-info': './src/validator-info.ts', - 'validator-info-response': './src/validator-info-response.ts', - 'validator-state': './src/validator-state.ts', - 'validator-status': './src/validator-status.ts', - value: './src/value.ts', - 'value-view': './src/value-view.ts', - }, - formats: ['es'], - }, - }, - plugins: [dts({ rollupTypes: true }), externalizeDeps()], -}); diff --git a/packages/keys/CHANGELOG.md b/packages/keys/CHANGELOG.md deleted file mode 100644 index 2ccdcce4..00000000 --- a/packages/keys/CHANGELOG.md +++ /dev/null @@ -1,29 +0,0 @@ -# @penumbra-zone/keys - -## 4.1.0 - -### Minor Changes - -- 87de709: proving keys 77 - -## 4.0.0 - -### Major Changes - -- 0b7c427: keys v0.76.0 - -## 2.0.0 - -### Major Changes - -- 55f31c9: Support new v0.73.0 keys - -### Minor Changes - -- 6a05b38: increment key version - -## 1.0.0 - -### Major Changes - -- 14ba695: publish package containing keys diff --git a/packages/keys/README.md b/packages/keys/README.md deleted file mode 100644 index cd2bfcb5..00000000 --- a/packages/keys/README.md +++ /dev/null @@ -1,89 +0,0 @@ -# `@penumbra-zone/keys` - -This package contains cryptographic keys relevant to the Penumbra blockchain, -and checksums to validate the integrity of those keys. - -The default export is a JSON mapping of Penumbra `Action` names to their -relevant key, necessary for building cryptographic proofs for those actions. -Keys are exported as `[key_name]_pk.bin`. - -A basic shell script `penumbra-download-keys` is provided, if you have specific -versioning, bundling, or copying needs. Most users can use the keys exported -from the package. - -## Using Keys - -If your bundler supports `import.meta.resolve`, you can handle the raw key material like this: - -```ts -const res: Result = await fetch(import.meta.resolve('@penumbra-zone/keys/convert_pk.bin')); -const keyBuf: ArrayBuffer = await res.arrayBuffer(); -const convertPk = new Uint8Array(keyBuf); -``` - -## A More Complex Example - -If your bundler doesn't support `import.meta.resolve`, or you rely on customized -bundling, you might want to just handle URLs. Our `@penumbra-zone/wasm` package -expects you to input key URL strings when building `Action`s. - -Here's a simplified example of how we use the packages together in our reference -wallet extension: - -```ts -import actionKeys from '@penumbra-zone/keys'; - -import type { FullViewingKey } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb'; -import type { - Action, - TransactionPlan, - WitnessData, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/transaction/v1/transaction_pb'; - -// map filenames to bundled key asset URLs -const keyUrls = actionKeys.map(keyFileName => new URL(`keys/${keyFileName}`, PRAX_ORIGIN)); - -async function buildAction( - txPlan: TransactionPlan, - witness: WitnessData, - fvk: FullViewingKey, - actionIndex: number, -): Promise { - // Dynamically load wasm module - const builder = await import('@penumbra-zone/wasm/build'); - - // Identify action type - const actionType: Action['value']['case'] = transactionPlan.actions[actionPlanIndex]!.action.case; - - // Identify key url, if present - const keyUrl: string | undefined = keyUrls[actionType]?.href; - - // Build action - return builder.buildActionParallel(txPlan, witness, fvk, actionIndex, keyUrl); -} -``` - -### Using the management script - -An executable `penumbra-download-keys` is included. It can checksum the keys -included in this package, and download other versions referenced by git tag if -you are working with a testnet or other custom chain with its own proving keys. - -In any workspace where this package is installed, you can use - -```sh -[npm|pnpm|yarn] exec penumbra-download-keys [output-path] [git tag] [sha256 manifest] -``` - -Which will acquire the default keys and display checksum validation, if a key -manifest is already present. You can further specify a version and custom -manifest file. - -#### Updating the keys - -If new keys are released by core, change the `defaultKeysVersion` variable in the `download-keys` script to the new version of the keys. Then: - -1. Run the `download-keys` script (per the instructions above) -2. `cd keys` -3. `shasum -a 256 *.bin > ../shasums/vX.X.X.shasum` (change `vX.X.X` to the actual version number of the keys) -4. Commit your changes. diff --git a/packages/keys/action-keys.json b/packages/keys/action-keys.json deleted file mode 100644 index c3ceb8d9..00000000 --- a/packages/keys/action-keys.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "delegatorVote": "delegator_vote_pk.bin", - "output": "output_pk.bin", - "spend": "spend_pk.bin", - "swap": "swap_pk.bin", - "swapClaim": "swapclaim_pk.bin", - "undelegateClaim": "convert_pk.bin" -} diff --git a/packages/keys/download-keys b/packages/keys/download-keys deleted file mode 100755 index 6ff4dd90..00000000 --- a/packages/keys/download-keys +++ /dev/null @@ -1,90 +0,0 @@ -#!/bin/sh -set -e - -defaultKeysVersion="v0.77.0" - -scriptDir=$(dirname "$(readlink -f -- "$0")") -cacheDir="$scriptDir/keys" -scriptName=$(basename "$0") -shaCmd=$(which sha256sum || which shasum || true) - -[ -z $shaCmd ] && ( - echo "No checksum tool found. $scriptName requires sha256sum or shasum in \$PATH." - exit 69 # EX_UNAVAILABLE -) - -# usage -usage() { - echo "$1" - echo "Usage: $scriptName [output-path] [git tag] [sha256 manifest]" - exit 64 # EX_USAGE -} - -# nearest_checksums -nearest_checksums() { - ( - ( - # generate list - echo "$1.zzzEND" # version.zzzEND will sort after version.shasum - ls -1 "$scriptDir/shasums" # list known checksum manifests - ) | - # select nearest - sort --version-sort | # sort by version - grep --before-context=1 --max-count=1 "zzzEND" | # locate sentinel and previous item - grep -v "zzzEND" # remove sentinel, leaving previous/nothing - ) || ( - # if all of that fails, use latest - ls -1 "$scriptDir/shasums" | sort --version-sort | tail -n 1 - ) -} - -# env var or arg or default -outDir="$PENUMBRA_KEYS_OUT" # env var output path -[ -z "$outDir" ] && outDir="$1" # arg output path -[ -z "$outDir" ] && outDir="$scriptDir/keys" # default -[ -d "$outDir" ] || mkdir -p "$outDir" # create output dir -# resolve absolute -outDir=$(readlink -f "$outDir" || usage "No output directory available") - -# env var or arg or default -keysVersion=$PENUMBRA_KEYS_VERSION -[ -z $keysVersion ] && keysVersion=$2 -[ -z $keysVersion ] && keysVersion=$defaultKeysVersion - -# env var or arg or default to nearest version -shaFile="$PENUMBRA_KEYS_SHA256" -[ -z "$shaFile"] && shaFile="$3" -[ -z "$shaFile" ] && shaFile="$scriptDir/shasums/"$(nearest_checksums $keysVersion) -# resolve absolute -shaFile=$(readlink -f "$shaFile" || usage "No checksum manifest available") - -# check_keys -check_keys() { - pwd=$(pwd) # save current dir - ( - # cd, check, cd back - cd "$1" && $shaCmd -c "$shaFile" 2>/dev/null && cd "$pwd" - ) || ( - # if that fails, cd back and fail - cd "$pwd" && false - ) - # return failure - return $? -} - -## main ## - -# if good keys exist, we're already done -check_keys "$outDir" && exit 0 - -if [ -z $PENUMBRA_KEYS_SKIP ]; then - keysUrl="https://github.com/penumbra-zone/penumbra/raw/$keysVersion/crates/crypto/proof-params/src/gen/" - keysGlob="{convert,delegator_vote,nullifier_derivation,output,spend,swap,swapclaim}_pk.bin" - curl --output-dir "$outDir/$keysVersion" --continue-at - \ - --parallel --create-dirs --location --remote-name \ - "$keysUrl$keysGlob" -fi - -cp -v "$cacheDir/$keysVersion/"*_pk.bin "$outDir" - -check_keys "$outDir" diff --git a/packages/keys/package.json b/packages/keys/package.json deleted file mode 100644 index f15da3b3..00000000 --- a/packages/keys/package.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "@penumbra-zone/keys", - "version": "4.1.0", - "private": true, - "license": "(MIT OR Apache-2.0)", - "description": "Tool to download proving keys for Penumbra", - "type": "module", - "scripts": { - "prepare": "./download-keys ./keys" - }, - "files": [ - "action-keys.json", - "download-keys", - "keys/*_pk.bin" - ], - "exports": { - ".": "./action-keys.json", - "./*_pk.bin": "./keys/*_pk.bin" - }, - "bin": { - "penumbra-download-keys": "./download-keys" - } -} diff --git a/packages/keys/shasums/v0.73.0.shasum b/packages/keys/shasums/v0.73.0.shasum deleted file mode 100644 index 80128294..00000000 --- a/packages/keys/shasums/v0.73.0.shasum +++ /dev/null @@ -1,7 +0,0 @@ -882527eb795af2819f8df4f6233d5844757768fb03d51a000f11b100eeea573f convert_pk.bin -6712a90216c7c0cfb12ef2a37d48ffae666f8d2bd9a722836864d0a70064dce7 delegator_vote_pk.bin -ac9568335c1c158edddb2a70212c7b98d7c7aeff633b485a088049ecc01cc0ef nullifier_derivation_pk.bin -a8c5ccc9d6c74150a21a8411e90d523e6ebb0f2a2985327d9fb4ef690600461e output_pk.bin -69694b15abd96fdbeba5bbe1ba982d2240129be05813a9693acce31a1b43b0fd spend_pk.bin -3d75cac8a227cd8c6680cd40f94a436b89f10d9b9bb1a118cf4479f1aa9b3fef swap_pk.bin -1190707f9815bf0135169547b888716d6731cdbe1bc4ea2fbd22655a03fe56cd swapclaim_pk.bin diff --git a/packages/keys/shasums/v0.76.0.shasum b/packages/keys/shasums/v0.76.0.shasum deleted file mode 100644 index 16a228c7..00000000 --- a/packages/keys/shasums/v0.76.0.shasum +++ /dev/null @@ -1,7 +0,0 @@ -3db846f177bb0ea7421380fa883b0d9ed26f5d6088daaf14e322b69c56c43d24 convert_pk.bin -34896638d63dbd30f99ea0d9dff5433d9a4df01929464eaa9fc16cb9be4f4042 delegator_vote_pk.bin -1bdbec8b4d2688d9661d14a9292ac8ec911b887a5d2ee2b4a0ed5a9f83a6d2e2 nullifier_derivation_pk.bin -aa7bf00743622370582b7b7250d9912b3b0ca9420d8188ff77ee7270b43221fa output_pk.bin -ce5841047eabeccb63571e7533156a1721659ca34a8e3a0522b24f9e28418379 spend_pk.bin -92dc050073e1af027692e43115fadc853c10db9410584713f719be4d544719c0 swap_pk.bin -8971c76869ef15e2d81d0747036a880b831756efd816838c0086c559fbb4d62f swapclaim_pk.bin diff --git a/packages/keys/shasums/v0.77.0.shasum b/packages/keys/shasums/v0.77.0.shasum deleted file mode 100644 index 693281fc..00000000 --- a/packages/keys/shasums/v0.77.0.shasum +++ /dev/null @@ -1,7 +0,0 @@ -e253e17cbdea9701d2505259c7b128ec545bab2d4fca0a54436e658bc6d750ed convert_pk.bin -04630e363355436882ddb9bcee2294876a60da4e17262fd7118abb34d019be0a delegator_vote_pk.bin -668b0e5dccf9bc0e08cd7c9ae4263430a3a345e1f8561756da58e3c104548280 nullifier_derivation_pk.bin -321db68f5b222fa980d93006e414582e1ba6fa79db8351590cab7f09933de25a output_pk.bin -f3c33594b988a804b39fe92d179ebbd2a0aa8b00c170b49b8a6d49390b707f13 spend_pk.bin -60da33ae5f37cbae5647c83cda6ec6308e3541ac00c42b3a14fe827457bdacf9 swap_pk.bin -a508d818082cb81faece2a37faea73f21a8fe5c125e3ca6aff84687afa0d467a swapclaim_pk.bin diff --git a/packages/perspective/CHANGELOG.md b/packages/perspective/CHANGELOG.md deleted file mode 100644 index d16d2cc9..00000000 --- a/packages/perspective/CHANGELOG.md +++ /dev/null @@ -1,161 +0,0 @@ -# @penumbra-zone/perspective - -## 4.0.1 - -### Patch Changes - -- Updated dependencies [ab9d743] -- Updated dependencies [282eabf] -- Updated dependencies [81b9536] -- Updated dependencies [14ba562] -- Updated dependencies [6b06e04] -- Updated dependencies [c8e8d15] - - @penumbra-zone/types@7.1.0 - - @penumbra-zone/wasm@7.1.0 - - @penumbra-zone/getters@6.1.0 - -## 4.0.0 - -### Major Changes - -- 8fe4de6: correct ordering of default export - -### Patch Changes - -- Updated dependencies [8fe4de6] - - @penumbra-zone/bech32m@5.0.0 - - @penumbra-zone/getters@6.0.0 - - @penumbra-zone/wasm@7.0.0 - - @penumbra-zone/types@7.0.1 - -## 3.0.0 - -### Major Changes - -- 8b121ec: change package exports to use 'default' field - -### Patch Changes - -- Updated dependencies [bb5f621] -- Updated dependencies [8b121ec] - - @penumbra-zone/types@7.0.0 - - @penumbra-zone/bech32m@4.0.0 - - @penumbra-zone/getters@5.0.0 - - @penumbra-zone/wasm@6.0.0 - -## 2.1.0 - -### Minor Changes - -- 3ea1e6c: update buf types dependencies - -### Patch Changes - -- Updated dependencies [120b654] -- Updated dependencies [029eebb] -- Updated dependencies [e86448e] -- Updated dependencies [3ea1e6c] - - @penumbra-zone/getters@4.1.0 - - @penumbra-zone/types@6.0.0 - - @penumbra-zone/wasm@5.1.0 - - @penumbra-zone/bech32m@3.2.0 - -## 2.0.1 - -### Patch Changes - -- @penumbra-zone/wasm@5.0.1 - -## 2.0.0 - -### Major Changes - -- 8ccaf30: externalize dependencies - -### Minor Changes - -- e4c9fce: Add features to handle auction withdrawals - -### Patch Changes - -- e35c6f7: Deps bumped to latest -- Updated dependencies [146b48d] -- Updated dependencies [65677c1] -- Updated dependencies [8ccaf30] -- Updated dependencies [8ccaf30] -- Updated dependencies [e35c6f7] -- Updated dependencies [cf63b30] -- Updated dependencies [99feb9d] -- Updated dependencies [e4c9fce] -- Updated dependencies [8ccaf30] - - @penumbra-zone/getters@4.0.0 - - @penumbra-zone/types@5.0.0 - - @penumbra-zone/wasm@5.0.0 - - @penumbra-zone/bech32m@3.1.1 - -## 1.0.6 - -### Patch Changes - -- Updated dependencies - - @penumbra-zone/bech32m@3.1.0 - - @penumbra-zone/types@4.1.0 - - @penumbra-zone/wasm@4.0.4 - - @penumbra-zone/getters@3.0.2 - -## 1.0.5 - -### Patch Changes - -- Updated dependencies [8410d2f] - - @penumbra-zone/bech32m@3.0.1 - - @penumbra-zone/getters@3.0.1 - - @penumbra-zone/types@4.0.1 - - @penumbra-zone/wasm@4.0.3 - -## 1.0.4 - -### Patch Changes - -- Updated dependencies [6fb898a] - - @penumbra-zone/types@4.0.0 - - @penumbra-zone/wasm@4.0.2 - -## 1.0.3 - -### Patch Changes - -- Updated dependencies [3148375] -- Updated dependencies [fdd4303] - - @penumbra-zone/types@3.0.0 - - @penumbra-zone/bech32m@3.0.0 - - @penumbra-zone/wasm@4.0.1 - -## 1.0.2 - -### Patch Changes - -- Updated dependencies [78ab976] - - @penumbra-zone/wasm@4.0.0 - - @penumbra-zone/types@2.0.1 - -## 1.0.1 - -### Patch Changes - -- Updated dependencies [66c2407] - - @penumbra-zone/wasm@3.0.0 - -## 1.0.0 - -### Major Changes - -- 929d278: barrel imports to facilitate better tree shaking - -### Patch Changes - -- Updated dependencies [8933117] -- Updated dependencies [929d278] - - @penumbra-zone/wasm@2.0.0 - - @penumbra-zone/bech32@2.0.0 - - @penumbra-zone/types@2.0.0 diff --git a/packages/perspective/eslint.config.mjs b/packages/perspective/eslint.config.mjs deleted file mode 100644 index a53ed8e5..00000000 --- a/packages/perspective/eslint.config.mjs +++ /dev/null @@ -1,13 +0,0 @@ -import { penumbraEslintConfig } from '@penumbra-zone/eslint-config'; -import { config, parser } from 'typescript-eslint'; - -export default config({ - ...penumbraEslintConfig, - languageOptions: { - parser, - parserOptions: { - project: true, - tsconfigRootDir: import.meta.dirname, - }, - }, -}); diff --git a/packages/perspective/package.json b/packages/perspective/package.json deleted file mode 100644 index 8ffd54d7..00000000 --- a/packages/perspective/package.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "name": "@penumbra-zone/perspective", - "version": "4.0.1", - "private": true, - "license": "(MIT OR Apache-2.0)", - "description": "Tools for assuming different perspectives of Penumbra transactions", - "type": "module", - "scripts": { - "build": "vite build", - "clean": "rm -rfv dist", - "lint": "eslint plan transaction translators", - "test": "vitest run" - }, - "files": [ - "./dist" - ], - "publishConfig": { - "exports": { - "./plan/*": { - "types": "./dist/plan/*.d.ts", - "default": "./dist/plan/*.js" - }, - "./transaction/*": { - "types": "./dist/transaction/*.d.ts", - "default": "./dist/transaction/*.js" - }, - "./translators/*": { - "types": "./dist/translators/*.d.ts", - "default": "./dist/translators/*.js" - } - } - }, - "dependencies": { - "@penumbra-zone/bech32m": "workspace:*", - "@penumbra-zone/getters": "workspace:*", - "@penumbra-zone/types": "workspace:*", - "@penumbra-zone/wasm": "workspace:*" - }, - "devDependencies": { - "@buf/penumbra-zone_penumbra.bufbuild_es": "1.9.0-20240528180215-8fe1c79485f8.1" - }, - "peerDependencies": { - "@buf/penumbra-zone_penumbra.bufbuild_es": "1.9.0-20240528180215-8fe1c79485f8.1" - } -} diff --git a/packages/perspective/plan/get-address-view.test.ts b/packages/perspective/plan/get-address-view.test.ts deleted file mode 100644 index 207f2403..00000000 --- a/packages/perspective/plan/get-address-view.test.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { beforeEach, describe, expect, test, vi } from 'vitest'; -import { getAddressView } from './get-address-view'; -import { - Address, - AddressIndex, - AddressView, - FullViewingKey, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb'; -import { addressFromBech32m } from '@penumbra-zone/bech32m/penumbra'; - -const mockGetAddressIndexByAddress = vi.hoisted(() => vi.fn()); - -vi.mock('@penumbra-zone/wasm/address', () => ({ - getAddressIndexByAddress: mockGetAddressIndexByAddress, -})); - -describe('getAddressView()', () => { - const addressAsBech32 = - 'penumbra147mfall0zr6am5r45qkwht7xqqrdsp50czde7empv7yq2nk3z8yyfh9k9520ddgswkmzar22vhz9dwtuem7uxw0qytfpv7lk3q9dp8ccaw2fn5c838rfackazmgf3ahh09cxmz'; - const address = new Address(addressFromBech32m(addressAsBech32)); - - beforeEach(() => { - mockGetAddressIndexByAddress.mockReset(); - }); - - describe('when the address is controlled by the user represented by the full viewing key', () => { - beforeEach(() => { - mockGetAddressIndexByAddress.mockImplementation(() => new AddressIndex({ account: 123 })); - }); - - test('returns a visible `AddressView`', () => { - const expected = new AddressView({ - addressView: { - case: 'decoded', - value: { - address, - index: { - account: 123, - }, - }, - }, - }); - - expect(getAddressView(address, new FullViewingKey()).equals(expected)).toBe(true); - }); - }); - - describe('when the address is not controlled by the user represented by the full viewing key', () => { - beforeEach(() => { - mockGetAddressIndexByAddress.mockImplementation(() => undefined); - }); - - test('returns an opaque `AddressView`', () => { - const expected = new AddressView({ - addressView: { - case: 'opaque', - value: { - address, - }, - }, - }); - - expect(getAddressView(address, new FullViewingKey()).equals(expected)).toBe(true); - }); - }); -}); diff --git a/packages/perspective/plan/get-address-view.ts b/packages/perspective/plan/get-address-view.ts deleted file mode 100644 index edd471e7..00000000 --- a/packages/perspective/plan/get-address-view.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { - Address, - AddressView, - FullViewingKey, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb'; -import { getAddressIndexByAddress } from '@penumbra-zone/wasm/address'; - -export const getAddressView = (address: Address, fullViewingKey: FullViewingKey): AddressView => { - const index = getAddressIndexByAddress(fullViewingKey, address); - - if (index) { - return new AddressView({ - addressView: { - case: 'decoded', - value: { - address, - index, - }, - }, - }); - } else { - return new AddressView({ - addressView: { - case: 'opaque', - value: { - address, - }, - }, - }); - } -}; diff --git a/packages/perspective/plan/index.test.ts b/packages/perspective/plan/index.test.ts deleted file mode 100644 index 280899f3..00000000 --- a/packages/perspective/plan/index.test.ts +++ /dev/null @@ -1,112 +0,0 @@ -import { - Address, - FullViewingKey, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb'; -import { describe, expect, test, vi } from 'vitest'; -import { viewTransactionPlan } from '.'; -import { - MemoView_Visible, - TransactionPlan, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/transaction/v1/transaction_pb'; -import { addressFromBech32m } from '@penumbra-zone/bech32m/penumbra'; -import { Metadata } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; -import { fullViewingKeyFromBech32m } from '@penumbra-zone/bech32m/penumbrafullviewingkey'; - -describe('viewTransactionPlan()', () => { - const returnAddressAsBech32 = - 'penumbra147mfall0zr6am5r45qkwht7xqqrdsp50czde7empv7yq2nk3z8yyfh9k9520ddgswkmzar22vhz9dwtuem7uxw0qytfpv7lk3q9dp8ccaw2fn5c838rfackazmgf3ahh09cxmz'; - const returnAddress = new Address(addressFromBech32m(returnAddressAsBech32)); - const chainId = 'testnet'; - const expiryHeight = 100n; - const metadataByAssetId = vi.fn(() => Promise.resolve(new Metadata())); - const mockFvk = new FullViewingKey( - fullViewingKeyFromBech32m( - 'penumbrafullviewingkey1vzfytwlvq067g2kz095vn7sgcft47hga40atrg5zu2crskm6tyyjysm28qg5nth2fqmdf5n0q530jreumjlsrcxjwtfv6zdmfpe5kqsa5lg09', - ), - ); - - const validTxnPlan = new TransactionPlan({ - memo: { - plaintext: { - returnAddress, - text: 'Memo text here', - }, - }, - transactionParameters: { - fee: { amount: { hi: 1n, lo: 0n } }, - chainId, - expiryHeight, - }, - }); - - test('includes the return address if it exists', async () => { - const txnView = await viewTransactionPlan(validTxnPlan, metadataByAssetId, mockFvk); - const memoViewValue = txnView.bodyView!.memoView!.memoView.value! as MemoView_Visible; - - expect( - memoViewValue.plaintext!.returnAddress?.addressView.value?.address!.equals(returnAddress), - ).toBe(true); - }); - - test('leaves out the return address when it does not exist', async () => { - const view = viewTransactionPlan( - new TransactionPlan({ - transactionParameters: { - fee: { - amount: { - hi: 1n, - lo: 0n, - }, - }, - }, - }), - metadataByAssetId, - mockFvk, - ); - await expect(view).resolves.toHaveProperty('bodyView.memoView.memoView.value.plaintext.text'); - await expect(view).resolves.not.toHaveProperty( - 'bodyView.memoView.memoView.value.plaintext.returnAddress', - ); - }); - - test('includes the fee', async () => - expect(viewTransactionPlan(validTxnPlan, metadataByAssetId, mockFvk)).resolves.toMatchObject({ - bodyView: { transactionParameters: { fee: validTxnPlan.transactionParameters!.fee } }, - })); - - test('throws when there is no fee', () => - expect( - viewTransactionPlan( - new TransactionPlan({ - memo: { - plaintext: { - returnAddress, - }, - }, - transactionParameters: { - //fee, - chainId, - expiryHeight, - }, - }), - metadataByAssetId, - mockFvk, - ), - ).rejects.toThrow('No fee found in transaction plan')); - - test('includes the memo', async () => - expect(viewTransactionPlan(validTxnPlan, metadataByAssetId, mockFvk)).resolves.toMatchObject({ - bodyView: { memoView: { memoView: { value: { plaintext: { text: 'Memo text here' } } } } }, - })); - - test('includes the transaction parameters', () => - expect(viewTransactionPlan(validTxnPlan, metadataByAssetId, mockFvk)).resolves.toMatchObject({ - bodyView: { - transactionParameters: { - fee: validTxnPlan.transactionParameters!.fee, - chainId, - expiryHeight, - }, - }, - })); -}); diff --git a/packages/perspective/plan/index.ts b/packages/perspective/plan/index.ts deleted file mode 100644 index 50fca88c..00000000 --- a/packages/perspective/plan/index.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { - AssetId, - Metadata, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; -import { getAddressView } from './get-address-view'; -import { - TransactionPlan, - TransactionView, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/transaction/v1/transaction_pb'; -import { viewActionPlan } from './view-action-plan'; -import { FullViewingKey } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb'; - -/** - * Given a `TransactionPlan`, returns a `TransactionView` that can be passed to - * a `` so as to render the plan as though it's an - * already-completed transaction. - * - * Note that, since it is of course _not_ actually a completed transaction, the - * `TransactionView` is sort of a stub -- that is, it will be missing some - * properties. Its main purpose is to be able to render the transaction plan, - * not to be exhaustive. - */ -export const viewTransactionPlan = async ( - txPlan: TransactionPlan, - metadataByAssetId: (id: AssetId) => Promise, - fullViewingKey: FullViewingKey, -): Promise => { - const returnAddress = txPlan.memo?.plaintext?.returnAddress; - const transactionParameters = txPlan.transactionParameters; - if (!transactionParameters?.fee) throw new Error('No fee found in transaction plan'); - - return new TransactionView({ - bodyView: { - actionViews: await Promise.all( - txPlan.actions.map(viewActionPlan(metadataByAssetId, fullViewingKey)), - ), - memoView: { - memoView: { - case: 'visible', - value: { - plaintext: { - returnAddress: returnAddress - ? getAddressView(returnAddress, fullViewingKey) - : undefined, - text: txPlan.memo?.plaintext?.text ?? '', - }, - }, - }, - }, - transactionParameters, - }, - }); -}; diff --git a/packages/perspective/plan/view-action-plan.test.ts b/packages/perspective/plan/view-action-plan.test.ts deleted file mode 100644 index b6b426f4..00000000 --- a/packages/perspective/plan/view-action-plan.test.ts +++ /dev/null @@ -1,633 +0,0 @@ -import { describe, expect, test, vi } from 'vitest'; -import { viewActionPlan } from './view-action-plan'; -import { - ActionPlan, - ActionView, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/transaction/v1/transaction_pb'; -import { - OutputView, - OutputView_Visible, - SpendView, - SpendView_Visible, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/shielded_pool/v1/shielded_pool_pb'; -import { - AssetId, - Metadata, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; -import { - Address, - FullViewingKey, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb'; -import { - SwapPlaintext, - BatchSwapOutputData, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/dex/v1/dex_pb'; -import { - Delegate, - Undelegate, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/stake/v1/stake_pb'; -import { addressFromBech32m } from '@penumbra-zone/bech32m/penumbra'; -import { fullViewingKeyFromBech32m } from '@penumbra-zone/bech32m/penumbrafullviewingkey'; -import { - ActionDutchAuctionSchedule, - ActionDutchAuctionWithdrawPlan, - AuctionId, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/auction/v1/auction_pb'; - -vi.mock('@penumbra-zone/wasm/auction', () => ({ - getAuctionId: () => new AuctionId({ inner: new Uint8Array([0, 1, 2, 3]) }), -})); - -describe('viewActionPlan()', () => { - const addressAsBech32 = - 'penumbra147mfall0zr6am5r45qkwht7xqqrdsp50czde7empv7yq2nk3z8yyfh9k9520ddgswkmzar22vhz9dwtuem7uxw0qytfpv7lk3q9dp8ccaw2fn5c838rfackazmgf3ahh09cxmz'; - const address = new Address(addressFromBech32m(addressAsBech32)); - const assetId = new AssetId({ inner: new Uint8Array() }); - const metadata = new Metadata({ penumbraAssetId: assetId }); - const metadataByAssetId = vi.fn(() => Promise.resolve(metadata)); - const mockFvk = new FullViewingKey( - fullViewingKeyFromBech32m( - 'penumbrafullviewingkey1vzfytwlvq067g2kz095vn7sgcft47hga40atrg5zu2crskm6tyyjysm28qg5nth2fqmdf5n0q530jreumjlsrcxjwtfv6zdmfpe5kqsa5lg09', - ), - ); - - describe('`spend` action', () => { - const validSpendActionPlan = new ActionPlan({ - action: { - case: 'spend', - value: { - note: { - address, - value: { - amount: { hi: 1n, lo: 0n }, - assetId, - }, - }, - }, - }, - }); - - test('throws if the address is missing', async () => { - const actionPlan = new ActionPlan({ - action: { - case: 'spend', - value: { - note: {}, - }, - }, - }); - - await expect(viewActionPlan(metadataByAssetId, mockFvk)(actionPlan)).rejects.toThrow( - 'No address in spend plan', - ); - }); - - test('includes the amount', async () => { - const actionView = await viewActionPlan(metadataByAssetId, mockFvk)(validSpendActionPlan); - const spendView = actionView.actionView.value as SpendView; - const spendViewVisible = spendView.spendView.value as SpendView_Visible; - - expect(spendViewVisible.note!.value?.valueView.value?.amount).toEqual({ - hi: 1n, - lo: 0n, - }); - }); - - test('throws if the amount is missing', async () => { - const actionPlan = new ActionPlan({ - action: { - case: 'spend', - value: { - note: { - address, - }, - }, - }, - }); - - await expect(viewActionPlan(metadataByAssetId, mockFvk)(actionPlan)).rejects.toThrow( - 'No value in note', - ); - }); - - test('includes the denom metadata', () => - expect( - viewActionPlan(metadataByAssetId, mockFvk)(validSpendActionPlan), - ).resolves.toHaveProperty( - 'actionView.value.spendView.value.note.value.valueView.value.metadata', - metadata, - )); - - test('throws if the asset ID is missing', async () => { - const actionPlan = new ActionPlan({ - action: { - case: 'spend', - value: { - note: { - address, - value: { amount: { hi: 1n, lo: 0n } }, - }, - }, - }, - }); - - await expect(viewActionPlan(metadataByAssetId, mockFvk)(actionPlan)).rejects.toThrow( - 'No asset ID in value', - ); - }); - }); - - describe('`output` action', () => { - const addressAsBech32 = - 'penumbra147mfall0zr6am5r45qkwht7xqqrdsp50czde7empv7yq2nk3z8yyfh9k9520ddgswkmzar22vhz9dwtuem7uxw0qytfpv7lk3q9dp8ccaw2fn5c838rfackazmgf3ahh09cxmz'; - const destAddress = new Address(addressFromBech32m(addressAsBech32)); - const validOutputActionPlan = new ActionPlan({ - action: { - case: 'output', - value: { - value: { - amount: { hi: 1n, lo: 0n }, - assetId, - }, - destAddress, - }, - }, - }); - - test('includes the destAddress', async () => { - const actionView = await viewActionPlan(metadataByAssetId, mockFvk)(validOutputActionPlan); - const outputView = actionView.actionView.value as OutputView; - const outputViewVisible = outputView.outputView.value as OutputView_Visible; - - expect(outputViewVisible.note?.address?.addressView.value?.address).toEqual(destAddress); - }); - - test('throws if the destAddress is missing', async () => { - const actionPlan = new ActionPlan({ - action: { - case: 'output', - value: { - value: { - amount: { hi: 1n, lo: 0n }, - assetId, - }, - }, - }, - }); - - await expect(viewActionPlan(metadataByAssetId, mockFvk)(actionPlan)).rejects.toThrow( - 'No destAddress in output plan', - ); - }); - - test('includes the amount', async () => { - const actionView = await viewActionPlan(metadataByAssetId, mockFvk)(validOutputActionPlan); - const outputView = actionView.actionView.value as OutputView; - const outputViewVisible = outputView.outputView.value as OutputView_Visible; - - expect(outputViewVisible.note?.value?.valueView.value?.amount).toEqual({ - hi: 1n, - lo: 0n, - }); - }); - - test('throws if the amount is missing', async () => { - const actionPlan = new ActionPlan({ - action: { - case: 'output', - value: { - destAddress, - }, - }, - }); - - await expect(viewActionPlan(metadataByAssetId, mockFvk)(actionPlan)).rejects.toThrow( - 'No value to view', - ); - }); - - test('includes the denom metadata', () => - expect( - viewActionPlan(metadataByAssetId, mockFvk)(validOutputActionPlan), - ).resolves.toHaveProperty( - 'actionView.value.outputView.value.note.value.valueView.value.metadata', - metadata, - )); - - test('throws if the asset ID is missing', async () => { - const actionPlan = new ActionPlan({ - action: { - case: 'output', - value: { - value: { - amount: { hi: 1n, lo: 0n }, - }, - destAddress, - }, - }, - }); - - await expect(viewActionPlan(metadataByAssetId, mockFvk)(actionPlan)).rejects.toThrow( - 'No asset ID in value', - ); - }); - }); - - describe('`swap` action', () => { - test('returns an action view with the `swap` case', async () => { - const swapPlaintext = new SwapPlaintext({ - claimAddress: { - inner: new Uint8Array([0, 1, 2, 3]), - }, - claimFee: { - amount: { - hi: 123n, - lo: 456n, - }, - assetId: { - inner: new Uint8Array([0, 1, 2, 3]), - }, - }, - delta1I: { - hi: 123n, - lo: 456n, - }, - delta2I: { - hi: 123n, - lo: 456n, - }, - rseed: new Uint8Array([0, 1, 2, 3]), - tradingPair: { - asset1: { - inner: new Uint8Array([0, 1, 2, 3]), - }, - asset2: { - inner: new Uint8Array([4, 5, 6, 7]), - }, - }, - }); - - const actionPlan = new ActionPlan({ - action: { - case: 'swap', - value: { - feeBlinding: new Uint8Array([0, 1, 2, 3]), - proofBlindingR: new Uint8Array([0, 1, 2, 3]), - proofBlindingS: new Uint8Array([0, 1, 2, 3]), - swapPlaintext, - }, - }, - }); - - const actionView = viewActionPlan(metadataByAssetId, mockFvk)(actionPlan); - - const expected = new ActionView({ - actionView: { - case: 'swap', - value: { - swapView: { - case: 'visible', - value: { - swap: { - body: { - delta1I: swapPlaintext.delta1I, - delta2I: swapPlaintext.delta2I, - tradingPair: swapPlaintext.tradingPair, - }, - }, - swapPlaintext, - asset1Metadata: metadata, - asset2Metadata: metadata, - }, - }, - }, - }, - }); - - await expect(actionView).resolves.toEqual(expected); - }); - }); - - describe('`swapClaim` action', () => { - test('returns an action view with the `swapClaim` case', async () => { - const asset1Id = new AssetId({ inner: new Uint8Array([0, 1, 2, 3]) }); - const asset2Id = new AssetId({ inner: new Uint8Array([4, 5, 6, 7]) }); - const metadataByAssetId = vi.fn((id: AssetId) => - Promise.resolve(new Metadata({ penumbraAssetId: id })), - ); - - const swapPlaintext = new SwapPlaintext({ - claimAddress: address, - claimFee: { - amount: { - hi: 123n, - lo: 456n, - }, - assetId: { - inner: new Uint8Array([0, 1, 2, 3]), - }, - }, - delta1I: { - hi: 123n, - lo: 456n, - }, - delta2I: { - hi: 123n, - lo: 456n, - }, - rseed: new Uint8Array([0, 1, 2, 3]), - tradingPair: { - asset1: asset1Id, - asset2: asset2Id, - }, - }); - - const outputData = new BatchSwapOutputData({ - delta1: swapPlaintext.delta1I, - delta2: swapPlaintext.delta2I, - epochStartingHeight: 1n, - unfilled1: { hi: 123n, lo: 456n }, - unfilled2: { hi: 456n, lo: 789n }, - height: 2n, - lambda1: { - hi: 1n, - lo: 2n, - }, - lambda2: { - hi: 3n, - lo: 4n, - }, - tradingPair: swapPlaintext.tradingPair, - }); - - const actionPlan = new ActionPlan({ - action: { - case: 'swapClaim', - value: { - epochDuration: 1n, - position: 1n, - proofBlindingR: new Uint8Array([0, 1, 2, 3]), - proofBlindingS: new Uint8Array([4, 5, 6, 7]), - swapPlaintext, - outputData, - }, - }, - }); - - const actionView = await viewActionPlan(metadataByAssetId, mockFvk)(actionPlan); - - const expected = new ActionView({ - actionView: { - case: 'swapClaim', - value: { - swapClaimView: { - case: 'visible', - value: { - output1: { - address: { - addressView: { - case: 'decoded', - value: { - address: swapPlaintext.claimAddress, - index: {}, - }, - }, - }, - value: { - valueView: { - case: 'knownAssetId', - value: { - amount: outputData.lambda1, - metadata: await metadataByAssetId(asset1Id), - }, - }, - }, - }, - output2: { - address: { - addressView: { - case: 'decoded', - value: { - address: swapPlaintext.claimAddress, - index: {}, - }, - }, - }, - value: { - valueView: { - case: 'knownAssetId', - value: { - amount: outputData.lambda2, - metadata: await metadataByAssetId(asset2Id), - }, - }, - }, - }, - swapClaim: { - body: { - fee: swapPlaintext.claimFee, - outputData, - }, - epochDuration: 1n, - }, - }, - }, - }, - }, - }); - - // Since these are such big objects, we'll compare their JSON outputs - // rather than using `expect(actionView.equals(expected)).toBe(true)`, - // since the former gives us much more useful output when the test fails. - expect(actionView.toJson()).toEqual(expected.toJson()); - }); - }); - - describe('`withdrawal` action', () => { - test('returns an action view with the `ics20Withdrawal` case as-is', async () => { - const actionPlan = new ActionPlan({ - action: { - case: 'ics20Withdrawal', - value: { amount: { hi: 1n, lo: 0n } }, - }, - }); - - const actionView = viewActionPlan(metadataByAssetId, mockFvk)(actionPlan); - - await expect(actionView).resolves.toEqual( - new ActionView({ - actionView: { - case: 'ics20Withdrawal', - value: { amount: { hi: 1n, lo: 0n } }, - }, - }), - ); - }); - }); - - describe('`delegate` action', () => { - test('returns an action view with the action as-is', async () => { - const delegate = new Delegate({ - epochIndex: 0n, - delegationAmount: { hi: 123n, lo: 456n }, - }); - const actionPlan = new ActionPlan({ - action: { - case: 'delegate', - value: delegate, - }, - }); - - const actionView = viewActionPlan(metadataByAssetId, mockFvk)(actionPlan); - - await expect(actionView).resolves.toEqual( - new ActionView({ - actionView: { - case: 'delegate', - value: delegate, - }, - }), - ); - }); - }); - - describe('`undelegate` action', () => { - test('returns an action view with the action as-is', async () => { - const undelegate = new Undelegate({ - startEpochIndex: 0n, - delegationAmount: { hi: 123n, lo: 456n }, - }); - const actionPlan = new ActionPlan({ - action: { - case: 'undelegate', - value: undelegate, - }, - }); - - const actionView = viewActionPlan(metadataByAssetId, mockFvk)(actionPlan); - - await expect(actionView).resolves.toEqual( - new ActionView({ - actionView: { - case: 'undelegate', - value: undelegate, - }, - }), - ); - }); - }); - - describe('`actionDutchAuctionSchedule` action', () => { - test('returns an action view with the appropriate view', async () => { - const schedule = new ActionDutchAuctionSchedule({ - description: { - input: { - amount: { hi: 0n, lo: 1n }, - assetId: {}, - }, - outputId: {}, - }, - }); - const actionPlan = new ActionPlan({ - action: { - case: 'actionDutchAuctionSchedule', - value: schedule, - }, - }); - - const actionView = viewActionPlan(metadataByAssetId, mockFvk)(actionPlan); - - await expect(actionView).resolves.toEqual( - new ActionView({ - actionView: { - case: 'actionDutchAuctionSchedule', - value: { - action: schedule, - auctionId: { inner: new Uint8Array([0, 1, 2, 3]) }, - inputMetadata: metadata, - outputMetadata: metadata, - }, - }, - }), - ); - }); - }); - - describe('`actionDutchAuctionWithdraw` action', () => { - test('returns an action view with the action and reserves', async () => { - const withdraw = new ActionDutchAuctionWithdrawPlan({ - auctionId: {}, - seq: 0n, - reservesInput: { - amount: { hi: 0n, lo: 1234n }, - assetId: {}, - }, - reservesOutput: { - amount: { hi: 0n, lo: 5678n }, - assetId: {}, - }, - }); - const actionPlan = new ActionPlan({ - action: { - case: 'actionDutchAuctionWithdraw', - value: withdraw, - }, - }); - - const actionView = viewActionPlan(metadataByAssetId, mockFvk)(actionPlan); - - await expect(actionView).resolves.toEqual( - new ActionView({ - actionView: { - case: 'actionDutchAuctionWithdraw', - value: { - action: withdraw, - reserves: [ - { - valueView: { - case: 'knownAssetId', - value: { - amount: { hi: 0n, lo: 1234n }, - metadata, - }, - }, - }, - { - valueView: { - case: 'knownAssetId', - value: { - amount: { hi: 0n, lo: 5678n }, - metadata, - }, - }, - }, - ], - }, - }, - }), - ); - }); - }); - - describe('all other action cases', () => { - test('returns an action view with the case but no value', async () => { - const actionPlan = new ActionPlan({ - action: { - case: 'proposalSubmit', - value: {}, - }, - }); - - const actionView = viewActionPlan(metadataByAssetId, mockFvk)(actionPlan); - - await expect(actionView).resolves.toEqual( - new ActionView({ - actionView: { - case: 'proposalSubmit', - value: {}, - }, - }), - ); - }); - }); -}); diff --git a/packages/perspective/plan/view-action-plan.ts b/packages/perspective/plan/view-action-plan.ts deleted file mode 100644 index d2d5e727..00000000 --- a/packages/perspective/plan/view-action-plan.ts +++ /dev/null @@ -1,338 +0,0 @@ -import { - ActionPlan, - ActionView, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/transaction/v1/transaction_pb'; -import { - AssetId, - Metadata, - Value, - ValueView, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; -import { getAddressView } from './get-address-view'; -import { - Note, - NoteView, - OutputPlan, - OutputView, - SpendPlan, - SpendView, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/shielded_pool/v1/shielded_pool_pb'; -import { - SwapClaimPlan, - SwapClaimView, - SwapPlan, - SwapView, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/dex/v1/dex_pb'; -import { FullViewingKey } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb'; -import { getAuctionId } from '@penumbra-zone/wasm/auction'; -import { - getInputAssetId, - getOutputAssetId, -} from '@penumbra-zone/getters/dutch-auction-description'; -import { - ActionDutchAuctionWithdrawPlan, - ActionDutchAuctionWithdrawView, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/auction/v1/auction_pb'; -import { PartialMessage } from '@bufbuild/protobuf'; - -const getValueView = async ( - value: Value | undefined, - denomMetadataByAssetId: (id: AssetId) => Promise, -): Promise => { - if (!value) throw new Error('No value to view'); - if (!value.assetId) throw new Error('No asset ID in value'); - if (!value.amount) throw new Error('No amount in value'); - - return new ValueView({ - valueView: { - case: 'knownAssetId', - value: { - amount: value.amount, - metadata: await denomMetadataByAssetId(value.assetId), - }, - }, - }); -}; - -const getNoteView = async ( - note: Note | undefined, - denomMetadataByAssetId: (id: AssetId) => Promise, - fullViewingKey: FullViewingKey, -) => { - if (!note) throw new Error('No note to view'); - if (!note.address) throw new Error('No address in note'); - if (!note.value) throw new Error('No value in note'); - - return new NoteView({ - address: getAddressView(note.address, fullViewingKey), - value: await getValueView(note.value, denomMetadataByAssetId), - }); -}; - -const getSpendView = async ( - spendPlan: SpendPlan, - denomMetadataByAssetId: (id: AssetId) => Promise, - fullViewingKey: FullViewingKey, -): Promise => { - if (!spendPlan.note?.address) throw new Error('No address in spend plan'); - - return new SpendView({ - spendView: { - case: 'visible', - value: { - note: await getNoteView(spendPlan.note, denomMetadataByAssetId, fullViewingKey), - }, - }, - }); -}; - -const getOutputView = async ( - outputPlan: OutputPlan, - denomMetadataByAssetId: (id: AssetId) => Promise, - fullViewingKey: FullViewingKey, -): Promise => { - if (!outputPlan.destAddress) throw new Error('No destAddress in output plan'); - - return new OutputView({ - outputView: { - case: 'visible', - - value: { - note: { - value: await getValueView(outputPlan.value, denomMetadataByAssetId), - address: getAddressView(outputPlan.destAddress, fullViewingKey), - }, - }, - }, - }); -}; - -const getSwapView = async ( - swapPlan: SwapPlan, - denomMetadataByAssetId: (id: AssetId) => Promise, -): Promise => { - const [asset1Metadata, asset2Metadata] = await Promise.all([ - swapPlan.swapPlaintext?.tradingPair?.asset1 - ? await denomMetadataByAssetId(swapPlan.swapPlaintext.tradingPair.asset1) - : undefined, - swapPlan.swapPlaintext?.tradingPair?.asset2 - ? await denomMetadataByAssetId(swapPlan.swapPlaintext.tradingPair.asset2) - : undefined, - ]); - - return new SwapView({ - swapView: { - case: 'visible', - value: { - swap: { - body: { - delta1I: swapPlan.swapPlaintext?.delta1I, - delta2I: swapPlan.swapPlaintext?.delta2I, - tradingPair: swapPlan.swapPlaintext?.tradingPair, - }, - }, - swapPlaintext: swapPlan.swapPlaintext, - asset1Metadata, - asset2Metadata, - }, - }, - }); -}; - -const getActionDutchAuctionWithdrawView = async ( - action: ActionDutchAuctionWithdrawPlan, - denomMetadataByAssetId: (id: AssetId) => Promise, -): Promise> => { - const reserves = []; - - if (action.reservesInput) { - reserves.push(getValueView(action.reservesInput, denomMetadataByAssetId)); - } - if (action.reservesOutput) { - reserves.push(getValueView(action.reservesOutput, denomMetadataByAssetId)); - } - - return { - action, - reserves: await Promise.all(reserves), - }; -}; - -const getSwapClaimView = async ( - swapClaimPlan: SwapClaimPlan, - denomMetadataByAssetId: (id: AssetId) => Promise, - fullViewingKey: FullViewingKey, -): Promise => { - return new SwapClaimView({ - swapClaimView: { - case: 'visible', - value: { - output1: { - address: swapClaimPlan.swapPlaintext?.claimAddress - ? getAddressView(swapClaimPlan.swapPlaintext.claimAddress, fullViewingKey) - : undefined, - value: swapClaimPlan.outputData?.lambda1 - ? await getValueView( - new Value({ - amount: swapClaimPlan.outputData.lambda1, - assetId: swapClaimPlan.outputData.tradingPair?.asset1, - }), - denomMetadataByAssetId, - ) - : undefined, - }, - output2: { - address: swapClaimPlan.swapPlaintext?.claimAddress - ? getAddressView(swapClaimPlan.swapPlaintext.claimAddress, fullViewingKey) - : undefined, - value: swapClaimPlan.outputData?.lambda2 - ? await getValueView( - new Value({ - amount: swapClaimPlan.outputData.lambda2, - assetId: swapClaimPlan.outputData.tradingPair?.asset2, - }), - denomMetadataByAssetId, - ) - : undefined, - }, - swapClaim: { - body: { - fee: swapClaimPlan.swapPlaintext?.claimFee, - outputData: swapClaimPlan.outputData, - }, - epochDuration: swapClaimPlan.epochDuration, - }, - }, - }, - }); -}; - -export const viewActionPlan = - (denomMetadataByAssetId: (id: AssetId) => Promise, fullViewingKey: FullViewingKey) => - async (actionPlan: ActionPlan): Promise => { - switch (actionPlan.action.case) { - case 'spend': - return new ActionView({ - actionView: { - case: 'spend', - value: await getSpendView( - actionPlan.action.value, - denomMetadataByAssetId, - fullViewingKey, - ), - }, - }); - case 'output': - return new ActionView({ - actionView: { - case: 'output', - value: await getOutputView( - actionPlan.action.value, - denomMetadataByAssetId, - fullViewingKey, - ), - }, - }); - case 'swap': - return new ActionView({ - actionView: { - case: 'swap', - value: await getSwapView(actionPlan.action.value, denomMetadataByAssetId), - }, - }); - case 'swapClaim': - return new ActionView({ - actionView: { - case: 'swapClaim', - value: await getSwapClaimView( - actionPlan.action.value, - denomMetadataByAssetId, - fullViewingKey, - ), - }, - }); - case 'ics20Withdrawal': - /** - * Special case -- the `withdrawal` case in the action plan maps to the - * `ics20Withdrawal` case in the action view. - * - * This should probably be renamed for consistency. See - * https://github.com/penumbra-zone/penumbra/issues/3614. - */ - return new ActionView({ - actionView: { - case: 'ics20Withdrawal', - value: actionPlan.action.value, - }, - }); - case 'delegate': - case 'undelegate': - return new ActionView({ actionView: actionPlan.action }); - - case 'undelegateClaim': - return new ActionView({ - actionView: { - case: 'undelegateClaim', - value: { - body: actionPlan.action.value, - }, - }, - }); - - case 'actionDutchAuctionSchedule': { - const inputAssetId = getInputAssetId.optional()(actionPlan.action.value.description); - const outputAssetId = getOutputAssetId.optional()(actionPlan.action.value.description); - const [inputMetadata, outputMetadata] = await Promise.all([ - inputAssetId ? await denomMetadataByAssetId(inputAssetId) : undefined, - outputAssetId ? await denomMetadataByAssetId(outputAssetId) : undefined, - ]); - - return new ActionView({ - actionView: { - case: 'actionDutchAuctionSchedule', - value: { - action: actionPlan.action.value, - auctionId: actionPlan.action.value.description - ? getAuctionId(actionPlan.action.value.description) - : undefined, - inputMetadata, - outputMetadata, - }, - }, - }); - } - - case 'actionDutchAuctionWithdraw': - return new ActionView({ - actionView: { - case: 'actionDutchAuctionWithdraw', - value: await getActionDutchAuctionWithdrawView( - actionPlan.action.value, - denomMetadataByAssetId, - ), - }, - }); - - case 'actionDutchAuctionEnd': - return new ActionView({ - actionView: actionPlan.action, - }); - - case undefined: - throw new Error('No action case in action plan'); - default: - /** - * `` only renders data about the `spend` and - * `output` cases. For all other cases, it just renders the action name. - * - * @todo As we render more data about other action types, add them as - * cases above. - */ - return new ActionView({ - actionView: { - case: actionPlan.action.case, - value: {}, - }, - }); - } - }; diff --git a/packages/perspective/transaction/classification.ts b/packages/perspective/transaction/classification.ts deleted file mode 100644 index bf9d4b3b..00000000 --- a/packages/perspective/transaction/classification.ts +++ /dev/null @@ -1,29 +0,0 @@ -export type TransactionClassification = - /** We don't know what kind of transaction this is, or it's undefined. */ - | 'unknown' - /** We know that it's internal (e.g, a swap), but nothing more. */ - | 'unknownInternal' - /** The transaction is an internal transfer between the user's accounts. */ - | 'internalTransfer' - /** The transaction is a send to an external account. */ - | 'send' - /** The transaction is a receive from an external account. */ - | 'receive' - /** The transaction contains a `swap` action. */ - | 'swap' - /** The transaction contains a `swapClaim` action. */ - | 'swapClaim' - /** The transaction contains a `delegate` action. */ - | 'delegate' - /** The transaction contains an `undelegate` action. */ - | 'undelegate' - /** The transaction contains an `undelegateClaim` action. */ - | 'undelegateClaim' - /** The transaction contains an `ics20Withdrawal` action. */ - | 'ics20Withdrawal' - /** The transaction contains an `actionDutchAuctionSchedule` action. */ - | 'dutchAuctionSchedule' - /** The transaction contains an `actionDutchAuctionEnd` action. */ - | 'dutchAuctionEnd' - /** The transaction contains an `actionDutchAuctionWithdraw` action. */ - | 'dutchAuctionWithdraw'; diff --git a/packages/perspective/transaction/classify.test.ts b/packages/perspective/transaction/classify.test.ts deleted file mode 100644 index d741ce5b..00000000 --- a/packages/perspective/transaction/classify.test.ts +++ /dev/null @@ -1,388 +0,0 @@ -import { describe, expect, it } from 'vitest'; -import { classifyTransaction } from './classify'; -import { TransactionView } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/transaction/v1/transaction_pb'; - -describe('classifyTransaction()', () => { - it('returns `receive` for transactions with an opaque spend and a visible output + address', () => { - const transactionView = new TransactionView({ - bodyView: { - actionViews: [ - { - actionView: { - case: 'spend', - value: { - spendView: { - case: 'opaque', - value: {}, - }, - }, - }, - }, - { - actionView: { - case: 'output', - value: { - outputView: { - case: 'visible', - value: { - note: { - address: { - addressView: { - case: 'decoded', - value: {}, - }, - }, - }, - }, - }, - }, - }, - }, - ], - }, - }); - - expect(classifyTransaction(transactionView)).toBe('receive'); - }); - - it('returns `send` for transactions with visible spends but at least one opaque output', () => { - const transactionView = new TransactionView({ - bodyView: { - actionViews: [ - { - actionView: { - case: 'spend', - value: { - spendView: { - case: 'visible', - value: { - note: { - address: { - addressView: { - case: 'decoded', - value: {}, - }, - }, - }, - }, - }, - }, - }, - }, - { - actionView: { - case: 'output', - value: { - outputView: { - case: 'visible', - value: { - note: { - address: { - addressView: { - case: 'decoded', - value: {}, - }, - }, - }, - }, - }, - }, - }, - }, - { - actionView: { - case: 'output', - value: { - outputView: { - case: 'visible', - value: { - note: { - address: { - addressView: { - case: 'opaque', - value: {}, - }, - }, - }, - }, - }, - }, - }, - }, - ], - }, - }); - - expect(classifyTransaction(transactionView)).toBe('send'); - }); - - it('returns `internalTransfer` for transactions with fully visible spends, outputs, and addresses', () => { - const transactionView = new TransactionView({ - bodyView: { - actionViews: [ - { - actionView: { - case: 'spend', - value: { - spendView: { - case: 'visible', - value: {}, - }, - }, - }, - }, - { - actionView: { - case: 'output', - value: { - outputView: { - case: 'visible', - value: { - note: { - address: { - addressView: { - case: 'decoded', - value: {}, - }, - }, - }, - }, - }, - }, - }, - }, - { - actionView: { - case: 'output', - value: { - outputView: { - case: 'visible', - value: { - note: { - address: { - addressView: { - case: 'decoded', - value: {}, - }, - }, - }, - }, - }, - }, - }, - }, - ], - }, - }); - - expect(classifyTransaction(transactionView)).toBe('internalTransfer'); - }); - - it('returns `swap` for transactions with a `swap` action', () => { - const transactionView = new TransactionView({ - bodyView: { - actionViews: [ - { - actionView: { - case: 'swap', - value: {}, - }, - }, - { - actionView: { - case: 'spend', - value: {}, - }, - }, - { - actionView: { - case: 'output', - value: {}, - }, - }, - ], - }, - }); - - expect(classifyTransaction(transactionView)).toBe('swap'); - }); - - it('returns `swapClaim` for transactions with a `swapClaim` action', () => { - const transactionView = new TransactionView({ - bodyView: { - actionViews: [ - { - actionView: { - case: 'swapClaim', - value: {}, - }, - }, - { - actionView: { - case: 'output', - value: {}, - }, - }, - ], - }, - }); - - expect(classifyTransaction(transactionView)).toBe('swapClaim'); - }); - - it('returns `delegate` for transactions with a `delegate` action', () => { - const transactionView = new TransactionView({ - bodyView: { - actionViews: [ - { - actionView: { - case: 'delegate', - value: {}, - }, - }, - { - actionView: { - case: 'spend', - value: {}, - }, - }, - { - actionView: { - case: 'output', - value: {}, - }, - }, - ], - }, - }); - - expect(classifyTransaction(transactionView)).toBe('delegate'); - }); - - it('returns `undelegate` for transactions with an `undelegate` action', () => { - const transactionView = new TransactionView({ - bodyView: { - actionViews: [ - { - actionView: { - case: 'undelegate', - value: {}, - }, - }, - { - actionView: { - case: 'spend', - value: {}, - }, - }, - { - actionView: { - case: 'output', - value: {}, - }, - }, - ], - }, - }); - - expect(classifyTransaction(transactionView)).toBe('undelegate'); - }); - - it('returns `undelegateClaim` for transactions with an `undelegateClaim` action', () => { - const transactionView = new TransactionView({ - bodyView: { - actionViews: [ - { - actionView: { - case: 'undelegateClaim', - value: {}, - }, - }, - { - actionView: { - case: 'spend', - value: {}, - }, - }, - { - actionView: { - case: 'output', - value: {}, - }, - }, - ], - }, - }); - - expect(classifyTransaction(transactionView)).toBe('undelegateClaim'); - }); - - it('returns `dutchAuctionSchedule` for transactions with an `actionDutchAuctionSchedule` action', () => { - const transactionView = new TransactionView({ - bodyView: { - actionViews: [{ actionView: { case: 'actionDutchAuctionSchedule', value: {} } }], - }, - }); - - expect(classifyTransaction(transactionView)).toBe('dutchAuctionSchedule'); - }); - - it('returns `dutchAuctionEnd` for transactions with an `actionDutchAuctionEnd` action', () => { - const transactionView = new TransactionView({ - bodyView: { - actionViews: [{ actionView: { case: 'actionDutchAuctionEnd', value: {} } }], - }, - }); - - expect(classifyTransaction(transactionView)).toBe('dutchAuctionEnd'); - }); - - it('returns `dutchAuctionWithdraw` for transactions with an `actionDutchAuctionWithdraw` action', () => { - const transactionView = new TransactionView({ - bodyView: { - actionViews: [{ actionView: { case: 'actionDutchAuctionWithdraw', value: {} } }], - }, - }); - - expect(classifyTransaction(transactionView)).toBe('dutchAuctionWithdraw'); - }); - - it("returns `unknown` for transactions that don't fit the above categories", () => { - const transactionView = new TransactionView({ - bodyView: { - actionViews: [ - { - actionView: { - case: 'spend', - value: { - spendView: { - case: 'visible', - value: {}, - }, - }, - }, - }, - { - actionView: { - case: 'output', - value: { - outputView: { - case: 'opaque', - value: {}, - }, - }, - }, - }, - { - actionView: { - case: 'delegatorVote', - value: {}, - }, - }, - ], - }, - }); - - expect(classifyTransaction(transactionView)).toBe('unknown'); - }); -}); diff --git a/packages/perspective/transaction/classify.ts b/packages/perspective/transaction/classify.ts deleted file mode 100644 index 20a19455..00000000 --- a/packages/perspective/transaction/classify.ts +++ /dev/null @@ -1,100 +0,0 @@ -import { TransactionView } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/transaction/v1/transaction_pb'; -import { TransactionClassification } from './classification'; - -export const classifyTransaction = (txv?: TransactionView): TransactionClassification => { - // Check if 'txv' is undefined and return "Unknown" if it is. - if (!txv) { - return 'unknown'; - } - - const allActionCases = new Set(txv.bodyView?.actionViews.map(a => a.actionView.case)); - - if (allActionCases.has('swap')) return 'swap'; - if (allActionCases.has('swapClaim')) return 'swapClaim'; - if (allActionCases.has('delegate')) return 'delegate'; - if (allActionCases.has('undelegate')) return 'undelegate'; - if (allActionCases.has('undelegateClaim')) return 'undelegateClaim'; - if (allActionCases.has('ics20Withdrawal')) return 'ics20Withdrawal'; - if (allActionCases.has('actionDutchAuctionSchedule')) return 'dutchAuctionSchedule'; - if (allActionCases.has('actionDutchAuctionEnd')) return 'dutchAuctionEnd'; - if (allActionCases.has('actionDutchAuctionWithdraw')) return 'dutchAuctionWithdraw'; - - const hasOpaqueSpend = txv.bodyView?.actionViews.some( - a => a.actionView.case === 'spend' && a.actionView.value.spendView.case === 'opaque', - ); - const allSpendsVisible = !hasOpaqueSpend; - - const hasOpaqueOutput = txv.bodyView?.actionViews.some( - a => a.actionView.case === 'output' && a.actionView.value.outputView.case === 'opaque', - ); - const allOutputsVisible = !hasOpaqueOutput; - - // A visible output whose note is controlled by an opaque address is an output we don't control. - const hasVisibleOutputWithOpaqueAddress = txv.bodyView?.actionViews.some( - a => - a.actionView.case === 'output' && - a.actionView.value.outputView.case === 'visible' && - a.actionView.value.outputView.value.note?.address?.addressView.case === 'opaque', - ); - - // A visible output whose note is controlled by an opaque address is an output we do control. - const hasVisibleOutputWithVisibleAddress = txv.bodyView?.actionViews.some( - a => - a.actionView.case === 'output' && - a.actionView.value.outputView.case === 'visible' && - a.actionView.value.outputView.value.note?.address?.addressView.case === 'decoded', - ); - - // A transaction is internal if all spends and outputs are visible, and there are no outputs we don't control. - const isInternal = allSpendsVisible && allOutputsVisible && !hasVisibleOutputWithOpaqueAddress; - - // Call a transaction a "transfer" if it only has spends and outputs. - const isTransfer = txv.bodyView?.actionViews.every( - a => a.actionView.case === 'spend' || a.actionView.case === 'output', - ); - - // If the tx has only spends and outputs, then it's a transfer. What kind? - if (isTransfer) { - // If we can't see at least one spend, but we can see an output we control, it's a receive. - if (hasOpaqueSpend && hasVisibleOutputWithVisibleAddress) { - return 'receive'; - } - // If we can see all spends and outputs, it's a transaction we created... - if (allSpendsVisible && allOutputsVisible) { - // ... so it's either a send or an internal transfer, depending on whether there's an output we don't control. - if (isInternal) { - return 'internalTransfer'; - } else { - return 'send'; - } - } - } - - if (isInternal) { - // TODO: fill this in with classification of swaps, swapclaims, etc. - return 'unknownInternal'; - } - - // Fallthrough - return 'unknown'; -}; - -export const TRANSACTION_LABEL_BY_CLASSIFICATION: Record = { - unknown: 'Unknown', - unknownInternal: 'Unknown (Internal)', - receive: 'Receive', - send: 'Send', - internalTransfer: 'Internal Transfer', - swap: 'Swap', - swapClaim: 'Swap Claim', - delegate: 'Delegate', - undelegate: 'Undelegate', - undelegateClaim: 'Undelegate Claim', - ics20Withdrawal: 'Ics20 Withdrawal', - dutchAuctionSchedule: 'Dutch Auction Schedule', - dutchAuctionEnd: 'Dutch Auction End', - dutchAuctionWithdraw: 'Dutch Auction Withdraw', -}; - -export const getTransactionClassificationLabel = (txv?: TransactionView): string => - TRANSACTION_LABEL_BY_CLASSIFICATION[classifyTransaction(txv)]; diff --git a/packages/perspective/translators/README.md b/packages/perspective/translators/README.md deleted file mode 100644 index f6e61d74..00000000 --- a/packages/perspective/translators/README.md +++ /dev/null @@ -1,25 +0,0 @@ -# Translators - -This directory contains translators: pure functions that translate an object into a different object. - -## Organization - -Files are named and organized by the type of **input** that the translator accepts, not by the type of **output** that the translator returns. For example, a file with `TransactionPlan` -> `Transaction` and `TransactionPlan` -> `TransactionView` translators should be in `transaction-plan.ts`. - -## Naming - -Translator functions should start with the word `as` and end with the type which they are returning. For example, a translator that takes a `MemoView` and returns an opaque `MemoView` should be called `asOpaqueMemoView`. That will prevent naming collisions and make each function's purpose clearer when you're importing multiple translators at once: - -```TS -import { asOpaqueAddressView, asOpaqueMemoView } from '@penumbra-zone/types'; -``` - -## Delegation - -Translators should be as simple as possible, delegating to other translators for nested object types. For example, the `asPublicTransactionView` translator doesn't itself modify a transaction view's nested memo view; rather, it delegates that work to `asOpaqueMemoView`. This way, each translator is easy to understand, and easy to test. - -## Contexts - -Some translators require context beyond the object they're translating. For example, the `asReceiverOutputView` translator requires an asynchronous `isControlledAddress` function that it can call with the output's address to determine whether to render the address as opaque or visible. - -In that case, you can define a `CtxType` as the third generic type argument to `Translator` with a key/value pair of context values to pass to that translator. (Even if you only have one context value to pass, a key/value pair is still required, to give the value a name and thus make it clear what its purpose is.) diff --git a/packages/perspective/translators/action-view.test.ts b/packages/perspective/translators/action-view.test.ts deleted file mode 100644 index 5cc6c67f..00000000 --- a/packages/perspective/translators/action-view.test.ts +++ /dev/null @@ -1,402 +0,0 @@ -import { ActionView } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/transaction/v1/transaction_pb'; -import { asPublicActionView, asReceiverActionView } from './action-view'; -import { describe, expect, test, vi } from 'vitest'; - -const u8 = (length: number) => Uint8Array.from({ length }, () => Math.floor(Math.random() * 256)); - -describe('asPublicActionView()', () => { - describe('when passed `undefined`', () => { - test('returns an empty action view', () => { - expect(asPublicActionView(undefined)).toBeUndefined(); - }); - }); - - describe('when passed an action view with an `undefined` case', () => { - test('returns an empty action view', () => { - expect( - asPublicActionView(new ActionView({ actionView: { case: undefined } })).equals( - new ActionView(), - ), - ).toBe(true); - }); - }); - - describe('when passed a spend action view', () => { - const actionView = new ActionView({ - actionView: { - case: 'spend', - value: { - spendView: { - case: 'visible', - value: { - note: { - address: { - addressView: { - case: 'decoded', - value: { - address: { - inner: u8(80), - }, - index: { - account: 0, - }, - }, - }, - }, - value: { - valueView: { - case: 'unknownAssetId', - value: { - amount: { - hi: 1n, - lo: 0n, - }, - assetId: { - inner: u8(32), - }, - }, - }, - }, - }, - spend: { - body: { - balanceCommitment: { - inner: new Uint8Array(), // no idea - }, - }, - }, - }, - }, - }, - }, - }); - - test('returns an action view with an opaque spend view', () => { - const expected = new ActionView({ - actionView: { - case: 'spend', - value: { - spendView: { - case: 'opaque', - value: { - spend: { - body: { - balanceCommitment: { - inner: new Uint8Array(), // no idea - }, - }, - }, - }, - }, - }, - }, - }); - - expect(asPublicActionView(actionView).equals(expected)).toBe(true); - }); - }); - - describe('when passed an output action view', () => { - const actionView = new ActionView({ - actionView: { - case: 'output', - value: { - outputView: { - case: 'visible', - value: { - note: { - address: { - addressView: { - case: 'decoded', - value: { - address: { - inner: u8(80), - }, - index: { - account: 0, - }, - }, - }, - }, - value: { - valueView: { - case: 'unknownAssetId', - value: { - amount: { - hi: 1n, - lo: 0n, - }, - assetId: { - inner: u8(32), - }, - }, - }, - }, - }, - output: { - body: { - balanceCommitment: { - inner: new Uint8Array(), // no idea - }, - }, - }, - }, - }, - }, - }, - }); - - test('returns an action view with an opaque output view', () => { - const expected = new ActionView({ - actionView: { - case: 'output', - value: { - outputView: { - case: 'opaque', - value: { - output: { - body: { - balanceCommitment: { - inner: new Uint8Array(), // no ide - }, - }, - }, - }, - }, - }, - }, - }); - - expect(asPublicActionView(actionView).equals(expected)).toBe(true); - }); - }); - - describe('when passed a delegate action view', () => { - const actionView = new ActionView({ - actionView: { - case: 'delegate', - value: { - epochIndex: 0n, - delegationAmount: { hi: 0n, lo: 1n }, - }, - }, - }); - - test('returns the action view as-is', () => { - expect(asPublicActionView(actionView).equals(actionView)).toBe(true); - }); - }); - - describe('when passed an undelegate action view', () => { - const actionView = new ActionView({ - actionView: { - case: 'undelegate', - value: { - startEpochIndex: 0n, - delegationAmount: { hi: 0n, lo: 1n }, - }, - }, - }); - - test('returns the action view as-is', () => { - expect(asPublicActionView(actionView).equals(actionView)).toBe(true); - }); - }); -}); - -describe('asReceiverActionView()', () => { - describe('when passed `undefined`', () => { - test('returns an empty action view', async () => { - const isControlledAddress = vi.fn(); - const result = await asReceiverActionView(undefined, { isControlledAddress }); - - expect(result).toBeUndefined(); - }); - }); - - describe('when passed an action view with an `undefined` case', () => { - test('returns an empty action view', async () => { - const isControlledAddress = vi.fn(); - const result = await asReceiverActionView( - new ActionView({ actionView: { case: undefined } }), - { isControlledAddress }, - ); - - expect(result.equals(new ActionView())).toBe(true); - }); - }); - - describe('when passed a spend action view', () => { - const actionView = new ActionView({ - actionView: { - case: 'spend', - value: { - spendView: { - case: 'visible', - value: { - note: { - address: { - addressView: { - case: 'decoded', - value: { - address: { - inner: u8(80), - }, - index: { - account: 0, - }, - }, - }, - }, - value: { - valueView: { - case: 'unknownAssetId', - value: { - amount: { - hi: 1n, - lo: 0n, - }, - assetId: { - inner: u8(32), - }, - }, - }, - }, - }, - spend: { - body: { - balanceCommitment: { - inner: new Uint8Array(), // no idea - }, - }, - }, - }, - }, - }, - }, - }); - - test('returns an action view with an opaque spend view', async () => { - const expected = new ActionView({ - actionView: { - case: 'spend', - value: { - spendView: { - case: 'opaque', - value: { - spend: { - body: { - balanceCommitment: { - inner: new Uint8Array(), // no idea - }, - }, - }, - }, - }, - }, - }, - }); - - const isControlledAddress = vi.fn(); - const result = await asReceiverActionView(actionView, { isControlledAddress }); - - expect(result.equals(expected)).toBe(true); - }); - }); - - describe('when passed an output action view', () => { - const actionView = new ActionView({ - actionView: { - case: 'output', - value: { - outputView: { - case: 'visible', - value: { - note: { - address: { - addressView: { - case: 'decoded', - value: { - address: { - inner: u8(80), - }, - index: { - account: 0, - }, - }, - }, - }, - value: { - valueView: { - case: 'unknownAssetId', - value: { - amount: { - hi: 1n, - lo: 0n, - }, - assetId: { - inner: u8(32), - }, - }, - }, - }, - }, - output: { - body: { - balanceCommitment: { - inner: new Uint8Array(), - }, - }, - }, - }, - }, - }, - }, - }); - - test('returns an action view with a receiver output view', async () => { - const isControlledAddress = () => Promise.resolve(false); - const result = await asReceiverActionView(actionView, { isControlledAddress }); - - expect(result.equals(actionView)).toBe(true); - }); - }); - - describe('when passed a delegate action view', () => { - const actionView = new ActionView({ - actionView: { - case: 'delegate', - value: { - epochIndex: 0n, - delegationAmount: { hi: 0n, lo: 1n }, - }, - }, - }); - - test('returns the action view as-is', async () => { - const isControlledAddress = () => Promise.resolve(false); - const result = await asReceiverActionView(actionView, { isControlledAddress }); - - expect(result.equals(actionView)).toBe(true); - }); - }); - - describe('when passed an undelegate action view', () => { - const actionView = new ActionView({ - actionView: { - case: 'undelegate', - value: { - startEpochIndex: 0n, - delegationAmount: { hi: 0n, lo: 1n }, - }, - }, - }); - - test('returns the action view as-is', async () => { - const isControlledAddress = () => Promise.resolve(false); - const result = await asReceiverActionView(actionView, { isControlledAddress }); - - expect(result.equals(actionView)).toBe(true); - }); - }); -}); diff --git a/packages/perspective/translators/action-view.ts b/packages/perspective/translators/action-view.ts deleted file mode 100644 index 758c6ad3..00000000 --- a/packages/perspective/translators/action-view.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { ActionView } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/transaction/v1/transaction_pb'; -import { Translator } from './types'; -import { asOpaqueSpendView } from './spend-view'; -import { asOpaqueOutputView, asReceiverOutputView } from './output-view'; -import { Address } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb'; -import { asOpaqueSwapView } from './swap-view'; -import { asOpaqueSwapClaimView } from './swap-claim-view'; - -export const asPublicActionView: Translator = actionView => { - switch (actionView?.actionView.case) { - case 'spend': - return new ActionView({ - actionView: { - case: 'spend', - value: asOpaqueSpendView(actionView.actionView.value), - }, - }); - - case 'output': - return new ActionView({ - actionView: { - case: 'output', - value: asOpaqueOutputView(actionView.actionView.value), - }, - }); - - case 'swap': - return new ActionView({ - actionView: { - case: 'swap', - value: asOpaqueSwapView(actionView.actionView.value), - }, - }); - - case 'swapClaim': - return new ActionView({ - actionView: { - case: 'swapClaim', - value: asOpaqueSwapClaimView(actionView.actionView.value), - }, - }); - - // Currently defaulting to displaying that all data is public as it's better - // to err on communicating private data as public than the other way around - // TODO: Do proper audit of what data for each action is public - default: - return actionView!; - } -}; - -export const asReceiverActionView: Translator< - ActionView, - Promise, - { isControlledAddress: (address: Address) => Promise } -> = async (actionView, ctx) => { - switch (actionView?.actionView.case) { - case 'output': - return new ActionView({ - actionView: { - case: 'output', - value: await asReceiverOutputView(actionView.actionView.value, ctx), - }, - }); - - default: - return asPublicActionView(actionView); - } -}; diff --git a/packages/perspective/translators/address-view.test.ts b/packages/perspective/translators/address-view.test.ts deleted file mode 100644 index 929b9505..00000000 --- a/packages/perspective/translators/address-view.test.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { - Address, - AddressView, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb'; -import { describe, expect, test } from 'vitest'; -import { asOpaqueAddressView } from './address-view'; - -const u8 = (length: number) => Uint8Array.from({ length }, () => Math.floor(Math.random() * 256)); - -const sameAddress = { - inner: u8(80), -}; - -describe('asOpaqueAddressView()', () => { - describe('when the address view is visible', () => { - const addressView = new AddressView({ - addressView: { - case: 'decoded', - value: { - address: sameAddress, - index: { - account: 0, - }, - walletId: { - inner: u8(32), - }, - }, - }, - }); - - test('returns an opaque address view', () => { - const expected = new AddressView({ - addressView: { - case: 'opaque', - value: { - address: sameAddress, - }, - }, - }); - - expect(asOpaqueAddressView(addressView).equals(expected)).toBe(true); - }); - }); - - describe('when the address view is already opaque', () => { - const addressView = new AddressView({ - addressView: { - case: 'opaque', - value: { - address: new Address(), - }, - }, - }); - - test('returns the address view as-is', () => { - expect(asOpaqueAddressView(addressView)).toBe(addressView); - }); - }); - - describe('when the address view is undefined', () => { - const addressView = undefined; - - test('returns an empty address view', () => { - expect(asOpaqueAddressView(addressView).equals(new AddressView())).toBe(true); - }); - }); -}); diff --git a/packages/perspective/translators/address-view.ts b/packages/perspective/translators/address-view.ts deleted file mode 100644 index 2c09549d..00000000 --- a/packages/perspective/translators/address-view.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { AddressView } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb'; -import { Translator } from './types'; - -export const asOpaqueAddressView: Translator = addressView => { - if (!addressView) return new AddressView(); - - if (addressView.addressView.case === 'opaque') return addressView; - - return new AddressView({ - addressView: { - case: 'opaque', - value: addressView.addressView.value ? addressView.addressView.value : {}, - }, - }); -}; diff --git a/packages/perspective/translators/memo-view.test.ts b/packages/perspective/translators/memo-view.test.ts deleted file mode 100644 index 513fa02b..00000000 --- a/packages/perspective/translators/memo-view.test.ts +++ /dev/null @@ -1,143 +0,0 @@ -import { describe, expect, test } from 'vitest'; -import { asOpaqueMemoView, asReceiverMemoView } from './memo-view'; -import { - MemoView, - MemoView_Visible, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/transaction/v1/transaction_pb'; -import { asOpaqueAddressView } from './address-view'; - -describe('asOpaqueMemoView()', () => { - describe('when passed a visible memo view', () => { - const memoView = new MemoView({ - memoView: { - case: 'visible', - value: { - plaintext: { - text: 'Memo text', - returnAddress: { - addressView: { - case: 'decoded', - value: { - address: { - inner: Uint8Array.from([0, 1, 2, 3]), - }, - index: { - account: 0, - }, - walletId: { - inner: Uint8Array.from([0, 1, 2, 3]), - }, - }, - }, - }, - }, - }, - }, - }); - - test('returns an opaque, empty memo view', () => { - expect( - asOpaqueMemoView(memoView).equals( - new MemoView({ memoView: { case: 'opaque', value: {} } }), - ), - ).toBe(true); - }); - }); - - describe('when passed an already-opaque memo view', () => { - const memoView = new MemoView({ - memoView: { - case: 'opaque', - value: { - ciphertext: { - inner: Uint8Array.from([0, 1, 2, 3]), - }, - }, - }, - }); - - test('returns the memo view as-is', () => { - expect(asOpaqueMemoView(memoView)).toBe(memoView); - }); - }); - - describe('when passed `undefined`', () => { - test('returns an opaque, empty memo view', () => { - expect( - asOpaqueMemoView(undefined).equals( - new MemoView({ memoView: { case: 'opaque', value: {} } }), - ), - ).toBe(true); - }); - }); -}); - -describe('asReceiverMemoView()', () => { - describe('when passed a visible memo view', () => { - const memoView = new MemoView({ - memoView: { - case: 'visible', - value: { - plaintext: { - text: 'Memo text', - returnAddress: { - addressView: { - case: 'decoded', - value: { - address: { - inner: Uint8Array.from([0, 1, 2, 3]), - }, - index: { - account: 0, - }, - walletId: { - inner: Uint8Array.from([0, 1, 2, 3]), - }, - }, - }, - }, - }, - ciphertext: { - inner: Uint8Array.from([0, 1, 2, 3]), - }, - }, - }, - }); - - test('makes the address view opaque, but leaves the rest as-is', () => { - const expected = memoView.clone(); - (expected.memoView.value as MemoView_Visible).plaintext!.returnAddress = asOpaqueAddressView( - (expected.memoView.value as MemoView_Visible).plaintext!.returnAddress, - )!; - - expect(asReceiverMemoView(memoView).equals(expected)).toBe(true); - }); - }); - - describe('when passed an opaque memo view', () => { - const memoView = new MemoView({ - memoView: { - case: 'opaque', - value: { - ciphertext: { - inner: Uint8Array.from([0, 1, 2, 3]), - }, - }, - }, - }); - - test('returns the memo view as-is', () => { - expect(asReceiverMemoView(memoView)).toBe(memoView); - }); - }); - - describe('when passed `undefined`', () => { - test('returns a visible, empty memo view', () => { - expect( - asReceiverMemoView(undefined).equals( - new MemoView({ memoView: { case: 'visible', value: {} } }), - ), - ).toBe(true); - }); - }); -}); diff --git a/packages/perspective/translators/memo-view.ts b/packages/perspective/translators/memo-view.ts deleted file mode 100644 index b8d06545..00000000 --- a/packages/perspective/translators/memo-view.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { MemoView } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/transaction/v1/transaction_pb'; -import { Translator } from './types'; -import { asOpaqueAddressView } from './address-view'; - -export const asOpaqueMemoView: Translator = memoView => - memoView?.memoView.case === 'opaque' - ? memoView - : new MemoView({ - memoView: { - case: 'opaque', - value: {}, - }, - }); - -export const asReceiverMemoView: Translator = memoView => - memoView?.memoView.case === 'opaque' - ? memoView - : new MemoView({ - memoView: { - case: 'visible', - value: { - ...memoView?.memoView.value, - - ...(memoView?.memoView.value?.plaintext - ? { - plaintext: { - ...memoView.memoView.value.plaintext, - - ...(memoView.memoView.value.plaintext.returnAddress - ? { - returnAddress: asOpaqueAddressView( - memoView.memoView.value.plaintext.returnAddress, - ), - } - : {}), - }, - } - : {}), - }, - }, - }); diff --git a/packages/perspective/translators/output-view.test.ts b/packages/perspective/translators/output-view.test.ts deleted file mode 100644 index 1d3255e6..00000000 --- a/packages/perspective/translators/output-view.test.ts +++ /dev/null @@ -1,193 +0,0 @@ -import { describe, expect, test, vi } from 'vitest'; -import { asOpaqueOutputView, asReceiverOutputView } from './output-view'; -import { OutputView } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/shielded_pool/v1/shielded_pool_pb'; - -describe('asOpaqueOutputView()', () => { - describe('when passed `undefined`', () => { - test('returns a blank output view', () => { - expect(asOpaqueOutputView(undefined).equals(new OutputView())).toBe(true); - }); - }); - - describe('when passed an already-opaque output view', () => { - const outputView = new OutputView({ - outputView: { - case: 'opaque', - value: { - output: { - body: { - balanceCommitment: { - inner: Uint8Array.from([0, 1, 2, 3]), - }, - }, - }, - }, - }, - }); - - test('returns the output view as-is', () => { - expect(asOpaqueOutputView(outputView)).toBe(outputView); - }); - }); - - describe('when passed a visible output view', () => { - const outputView = new OutputView({ - outputView: { - case: 'visible', - value: { - note: { - address: { - addressView: { - case: 'decoded', - value: { - address: { - inner: Uint8Array.from([0, 1, 2, 3]), - }, - index: { - account: 0, - }, - }, - }, - }, - value: { - valueView: { - case: 'unknownAssetId', - value: { - amount: { - hi: 1n, - lo: 0n, - }, - assetId: { - inner: Uint8Array.from([0, 1, 2, 3]), - }, - }, - }, - }, - }, - output: { - body: { - balanceCommitment: { - inner: Uint8Array.from([0, 1, 2, 3]), - }, - }, - }, - }, - }, - }); - - test('returns an opaque version of the output view', () => { - const result = asOpaqueOutputView(outputView); - - expect(result.outputView.case).toBe('opaque'); - expect(result.outputView.value?.output).toBe(outputView.outputView.value?.output); - expect(result.outputView.value).not.toHaveProperty('note'); - }); - }); -}); - -describe('asReceiverOutputView()', () => { - describe('when passed `undefined`', () => { - test('returns a blank output view', async () => { - const isControlledAddress = vi.fn(); - const result = await asReceiverOutputView(undefined, { isControlledAddress }); - - expect(result.equals(new OutputView())).toBe(true); - }); - }); - - describe('when passed an already-opaque output view', () => { - const outputView = new OutputView({ - outputView: { - case: 'opaque', - value: { - output: { - body: { - balanceCommitment: { - inner: Uint8Array.from([0, 1, 2, 3]), - }, - }, - }, - }, - }, - }); - - test('returns the output view as-is', async () => { - const isControlledAddress = vi.fn(); - await expect(asReceiverOutputView(outputView, { isControlledAddress })).resolves.toBe( - outputView, - ); - }); - }); - - describe('when passed a visible output view', () => { - const outputView = new OutputView({ - outputView: { - case: 'visible', - value: { - note: { - address: { - addressView: { - case: 'decoded', - value: { - address: { - inner: Uint8Array.from([0, 1, 2, 3]), - }, - index: { - account: 0, - }, - }, - }, - }, - value: { - valueView: { - case: 'unknownAssetId', - value: { - amount: { - hi: 1n, - lo: 0n, - }, - assetId: { - inner: Uint8Array.from([0, 1, 2, 3]), - }, - }, - }, - }, - }, - output: { - body: { - balanceCommitment: { - inner: Uint8Array.from([0, 1, 2, 3]), - }, - }, - }, - }, - }, - }); - - describe('when the address belongs to the current user', () => { - // If calling `isControlledAddress` resolves to `true`, the address - // belongs to the current user. - const isControlledAddress = () => Promise.resolve(true); - - test('returns an opaque version of the output view', async () => { - const result = await asReceiverOutputView(outputView, { isControlledAddress }); - - expect(result.outputView.case).toBe('opaque'); - expect(result.outputView.value?.output).toBe(outputView.outputView.value?.output); - expect(result.outputView.value).not.toHaveProperty('note'); - }); - }); - - describe('when the address does not belong to the current user', () => { - // If calling `isControlledAddress` resolves to `true`, the address - // belongs to the current user. - const isControlledAddress = () => Promise.resolve(false); - - test('returns the output view as-is', async () => { - const result = await asReceiverOutputView(outputView, { isControlledAddress }); - - expect(result).toBe(outputView); - }); - }); - }); -}); diff --git a/packages/perspective/translators/output-view.ts b/packages/perspective/translators/output-view.ts deleted file mode 100644 index f03c995e..00000000 --- a/packages/perspective/translators/output-view.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { OutputView } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/shielded_pool/v1/shielded_pool_pb'; -import { Translator } from './types'; -import { Address } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb'; - -export const asOpaqueOutputView: Translator = outputView => { - if (!outputView) return new OutputView(); - - if (outputView.outputView.case === 'opaque') return outputView; - - return new OutputView({ - outputView: { - case: 'opaque', - value: outputView.outputView.value?.output - ? { - output: outputView.outputView.value.output, - } - : {}, - }, - }); -}; - -export const asReceiverOutputView: Translator< - OutputView, - Promise, - { isControlledAddress: (address: Address) => Promise } -> = async (outputView, { isControlledAddress }) => { - if (!outputView) return new OutputView(); - - if (outputView.outputView.case === 'opaque') return outputView; - - const addressViewCase = outputView.outputView.value?.note?.address?.addressView.case; - const address = outputView.outputView.value?.note?.address?.addressView.value?.address; - - if (addressViewCase === 'decoded' && address && (await isControlledAddress(address))) { - return asOpaqueOutputView(outputView); - } else { - return outputView; - } -}; diff --git a/packages/perspective/translators/spend-view.test.ts b/packages/perspective/translators/spend-view.test.ts deleted file mode 100644 index 7448d592..00000000 --- a/packages/perspective/translators/spend-view.test.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { asOpaqueSpendView } from './spend-view'; -import { describe, expect, test } from 'vitest'; -import { SpendView } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/shielded_pool/v1/shielded_pool_pb'; - -describe('asOpaqueSpendView', () => { - describe('when passed `undefined`', () => { - test('returns an empty, opaque spend view', () => { - const expected = new SpendView({ - spendView: { - case: 'opaque', - value: {}, - }, - }); - - expect(asOpaqueSpendView(undefined).equals(expected)).toBe(true); - }); - }); - - describe('when passed an already-opaque spend view', () => { - const spendView = new SpendView({ - spendView: { - case: 'opaque', - value: { - spend: { - body: { - balanceCommitment: { - inner: Uint8Array.from([0, 1, 2, 3]), - }, - }, - }, - }, - }, - }); - - test('returns the spend view as-is', () => { - expect(asOpaqueSpendView(spendView)).toBe(spendView); - }); - }); - - describe('when passed a visible spend view', () => { - const spendView = new SpendView({ - spendView: { - case: 'visible', - value: { - note: { - address: { - addressView: { - case: 'decoded', - value: { - address: { - inner: Uint8Array.from([0, 1, 2, 3]), - }, - index: { - account: 0, - }, - }, - }, - }, - value: { - valueView: { - case: 'unknownAssetId', - value: { - amount: { - hi: 1n, - lo: 0n, - }, - assetId: { - inner: Uint8Array.from([0, 1, 2, 3]), - }, - }, - }, - }, - }, - spend: { - body: { - balanceCommitment: { - inner: Uint8Array.from([0, 1, 2, 3]), - }, - }, - }, - }, - }, - }); - - test('returns an opaque version of the spend view', () => { - const result = asOpaqueSpendView(spendView); - - expect(result.spendView.case).toBe('opaque'); - expect(result.spendView.value?.spend).toBe(spendView.spendView.value?.spend); - expect(result.spendView.value).not.toHaveProperty('note'); - }); - }); -}); diff --git a/packages/perspective/translators/spend-view.ts b/packages/perspective/translators/spend-view.ts deleted file mode 100644 index 5e5b3fe3..00000000 --- a/packages/perspective/translators/spend-view.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { SpendView } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/shielded_pool/v1/shielded_pool_pb'; -import { Translator } from './types'; - -export const asOpaqueSpendView: Translator = spendView => { - if (spendView?.spendView.case === 'opaque') { - return spendView; - } - - return new SpendView({ - spendView: { - case: 'opaque', - value: spendView?.spendView.value?.spend ? { spend: spendView.spendView.value.spend } : {}, - }, - }); -}; diff --git a/packages/perspective/translators/swap-claim-view.ts b/packages/perspective/translators/swap-claim-view.ts deleted file mode 100644 index 89b37f1c..00000000 --- a/packages/perspective/translators/swap-claim-view.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Translator } from './types'; -import { - SwapClaimView, - SwapClaimView_Opaque, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/dex/v1/dex_pb'; - -export const asOpaqueSwapClaimView: Translator = swapClaimView => { - if (swapClaimView?.swapClaimView.case === 'opaque') { - return swapClaimView; - } - - return new SwapClaimView({ - swapClaimView: { - case: 'opaque', - value: new SwapClaimView_Opaque({ - swapClaim: swapClaimView?.swapClaimView.value?.swapClaim, - }), - }, - }); -}; diff --git a/packages/perspective/translators/swap-view.ts b/packages/perspective/translators/swap-view.ts deleted file mode 100644 index f0c1b8ac..00000000 --- a/packages/perspective/translators/swap-view.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { Translator } from './types'; -import { - SwapView, - SwapView_Opaque, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/dex/v1/dex_pb'; - -export const asOpaqueSwapView: Translator = swapView => { - if (swapView?.swapView.case === 'opaque') { - return swapView; - } - - return new SwapView({ - swapView: { - case: 'opaque', - value: new SwapView_Opaque({ - swap: swapView?.swapView.value?.swap, - batchSwapOutputData: swapView?.swapView.value?.batchSwapOutputData, - output1Value: swapView?.swapView.value?.output1?.value, - output2Value: swapView?.swapView.value?.output2?.value, - asset1Metadata: swapView?.swapView.value?.asset1Metadata, - asset2Metadata: swapView?.swapView.value?.asset2Metadata, - }), - }, - }); -}; diff --git a/packages/perspective/translators/transaction-view.ts b/packages/perspective/translators/transaction-view.ts deleted file mode 100644 index e9bab451..00000000 --- a/packages/perspective/translators/transaction-view.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { asOpaqueMemoView, asReceiverMemoView } from './memo-view'; -import { asPublicActionView, asReceiverActionView } from './action-view'; -import { TransactionView } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/transaction/v1/transaction_pb'; -import { Translator } from './types'; -import { Address } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb'; - -export const asPublicTransactionView: Translator = transactionView => { - if (!transactionView?.bodyView) return new TransactionView(); - - return new TransactionView({ - bodyView: { - memoView: asOpaqueMemoView(transactionView.bodyView.memoView), - actionViews: transactionView.bodyView.actionViews.map(asPublicActionView), - - ...(transactionView.bodyView.transactionParameters - ? { transactionParameters: transactionView.bodyView.transactionParameters } - : {}), - }, - }); -}; - -export const asReceiverTransactionView: Translator< - TransactionView, - Promise, - { isControlledAddress: (address: Address) => Promise } -> = async (transactionView, ctx) => { - if (!transactionView?.bodyView) return new TransactionView(); - - return new TransactionView({ - bodyView: { - memoView: asReceiverMemoView(transactionView.bodyView.memoView), - actionViews: await Promise.all( - transactionView.bodyView.actionViews.map(actionView => - asReceiverActionView(actionView, ctx), - ), - ), - - ...(transactionView.bodyView.transactionParameters - ? { transactionParameters: transactionView.bodyView.transactionParameters } - : {}), - }, - }); -}; diff --git a/packages/perspective/translators/types.ts b/packages/perspective/translators/types.ts deleted file mode 100644 index ebf0fb9b..00000000 --- a/packages/perspective/translators/types.ts +++ /dev/null @@ -1,16 +0,0 @@ -export type TranslatorWithoutContext = ( - translatable: SourceType | undefined, -) => TargetType; - -export type TranslatorWithContext = ( - translatable: SourceType | undefined, - ctx: CtxType, -) => TargetType; - -export type Translator< - SourceType, - TargetType = SourceType, - CtxType extends undefined | Record = undefined, -> = CtxType extends undefined - ? TranslatorWithoutContext - : TranslatorWithContext; diff --git a/packages/perspective/tsconfig.json b/packages/perspective/tsconfig.json deleted file mode 100644 index 459b3e49..00000000 --- a/packages/perspective/tsconfig.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": "tsconfig/base.json", - "exclude": ["node_modules"], - "compilerOptions": { - "outDir": "dist", - "noEmit": true - } -} diff --git a/packages/perspective/vite.config.ts b/packages/perspective/vite.config.ts deleted file mode 100644 index 3fc950c9..00000000 --- a/packages/perspective/vite.config.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { defineConfig } from 'vite'; -import dts from 'vite-plugin-dts'; -import { externalizeDeps } from 'vite-plugin-externalize-deps'; - -export default defineConfig({ - build: { - lib: { - entry: { - classification: './transaction/classification.ts', - classify: './transaction/classify.ts', - 'action-view': './translators/action-view.ts', - 'address-view': './translators/address-view.ts', - 'memo-view': './translators/memo-view.ts', - 'output-view': './translators/output-view.ts', - 'spend-view': './translators/spend-view.ts', - 'get-address-view': './plan/get-address-view.ts', - index: './plan/index.ts', - 'view-action-plan': './plan/view-action-plan.ts', - }, - formats: ['es'], - }, - }, - plugins: [dts({ rollupTypes: true }), externalizeDeps()], -}); diff --git a/packages/perspective/vitest.config.ts b/packages/perspective/vitest.config.ts deleted file mode 100644 index 1ae230cc..00000000 --- a/packages/perspective/vitest.config.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { defineConfig } from 'vitest/config'; -import wasm from 'vite-plugin-wasm'; - -export default defineConfig({ - plugins: [wasm()], -}); diff --git a/packages/polyfills/CHANGELOG.md b/packages/polyfills/CHANGELOG.md deleted file mode 100644 index 1927d7d7..00000000 --- a/packages/polyfills/CHANGELOG.md +++ /dev/null @@ -1,26 +0,0 @@ -# @penumbra-zone/polyfills - -## 4.0.0 - -### Major Changes - -- 423e1d2: - don't publish - - remove polyfills now present in esnext - -## 3.0.0 - -### Major Changes - -- 3148375: remove `/src/` path segment from exports - -## 2.0.0 - -### Major Changes - -- 929d278: barrel imports to facilitate better tree shaking - -## 1.1.0 - -### Minor Changes - -- Initial changest. Git tag v5.0.0 updates. diff --git a/packages/polyfills/eslint.config.mjs b/packages/polyfills/eslint.config.mjs deleted file mode 100644 index a53ed8e5..00000000 --- a/packages/polyfills/eslint.config.mjs +++ /dev/null @@ -1,13 +0,0 @@ -import { penumbraEslintConfig } from '@penumbra-zone/eslint-config'; -import { config, parser } from 'typescript-eslint'; - -export default config({ - ...penumbraEslintConfig, - languageOptions: { - parser, - parserOptions: { - project: true, - tsconfigRootDir: import.meta.dirname, - }, - }, -}); diff --git a/packages/polyfills/package.json b/packages/polyfills/package.json deleted file mode 100644 index 3769281d..00000000 --- a/packages/polyfills/package.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "@penumbra-zone/polyfills", - "version": "4.0.0", - "private": true, - "license": "(MIT OR Apache-2.0)", - "type": "module", - "scripts": { - "lint": "eslint src", - "test": "vitest run" - }, - "exports": { - "./ReadableStream[Symbol.asyncIterator]": "./src/ReadableStream_Symbol.asyncIterator_.ts", - "./*": "./src/*.ts" - }, - "dependencies": { - "array-from-async": "^3.0.0" - } -} diff --git a/packages/polyfills/src/Array.fromAsync.test.ts b/packages/polyfills/src/Array.fromAsync.test.ts deleted file mode 100644 index 8bfe04df..00000000 --- a/packages/polyfills/src/Array.fromAsync.test.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { describe, expect, it } from 'vitest'; - -import Array from './Array.fromAsync'; -import './ReadableStream_Symbol.asyncIterator_'; - -describe('Array.fromAsync', () => { - it('should convert an async iterable to an array', async () => { - const asyncIterable = { - [Symbol.asyncIterator]: async function* () { - await Promise.resolve(); - yield 1; - yield 2; - yield 3; - }, - }; - - const result = await Array.fromAsync(asyncIterable); - expect(result).toEqual([1, 2, 3]); - }); - - it('should apply a map function to each element of the async iterable', async () => { - const asyncIterable = { - [Symbol.asyncIterator]: async function* () { - await Promise.resolve(); - yield 1; - yield 2; - yield 3; - }, - }; - - const mapFn = (value: number) => value * 2; - - const result = await Array.fromAsync(asyncIterable, mapFn); - expect(result).toEqual([2, 4, 6]); - }); - - it('should apply a map function with a thisArg to each element of the async iterable', async () => { - const asyncIterable = { - [Symbol.asyncIterator]: async function* () { - await Promise.resolve(); - yield 1; - yield 2; - yield 3; - }, - }; - - const objWithMapFn = { - multiplier: 3, - mapFn(value: number) { - return value * this.multiplier; - }, - }; - - // eslint-disable-next-line @typescript-eslint/unbound-method -- this is what we're testing - const result = await Array.fromAsync(asyncIterable, objWithMapFn.mapFn, { multiplier: 22 }); - expect(result).toEqual([22, 44, 66]); - }); - - it('should convert a stream into an array', async () => { - const stream = new ReadableStream({ - start(controller) { - controller.enqueue(1); - controller.enqueue(2); - controller.enqueue(3); - controller.close(); - }, - }); - - const result = await Array.fromAsync(stream); - expect(result).toEqual([1, 2, 3]); - }); -}); diff --git a/packages/polyfills/src/Array.fromAsync.ts b/packages/polyfills/src/Array.fromAsync.ts deleted file mode 100644 index 9eaf16fc..00000000 --- a/packages/polyfills/src/Array.fromAsync.ts +++ /dev/null @@ -1,17 +0,0 @@ -// eslint-disable-next-line @typescript-eslint/triple-slash-reference -/// -import fromAsync from 'array-from-async'; - -type FromAsync = ( - arrayLike: ArrayLike | AsyncIterable, - mapfn?: (v: T, k: number) => U, - thisArg?: unknown, -) => Promise; - -type ArrayWithFromAsync = typeof Array & { fromAsync: FromAsync }; - -if (!('fromAsync' in Array)) { - Object.assign(Array, { fromAsync: fromAsync as FromAsync }); -} - -export default Array as ArrayWithFromAsync; diff --git a/packages/polyfills/src/ReadableStream.from.test.ts b/packages/polyfills/src/ReadableStream.from.test.ts deleted file mode 100644 index 61f81950..00000000 --- a/packages/polyfills/src/ReadableStream.from.test.ts +++ /dev/null @@ -1,114 +0,0 @@ -import { describe, expect, test } from 'vitest'; -import ReadableStream from './ReadableStream.from'; - -describe('ReadableStream.from', () => { - test('should create a readable stream from an array', async () => { - const stream = ReadableStream.from([1, 2, 3]); - const reader = stream.getReader(); - - await expect(reader.read()).resolves.toEqual({ value: 1, done: false }); - await expect(reader.read()).resolves.toEqual({ value: 2, done: false }); - await expect(reader.read()).resolves.toEqual({ value: 3, done: false }); - await expect(reader.read()).resolves.toEqual({ value: undefined, done: true }); - }); - - test('should create a readable stream from a generator function', async () => { - const stream = ReadableStream.from( - (function* () { - yield 1; - yield 2; - yield 3; - })(), - ); - const reader = stream.getReader(); - - await expect(reader.read()).resolves.toEqual({ value: 1, done: false }); - await expect(reader.read()).resolves.toEqual({ value: 2, done: false }); - await expect(reader.read()).resolves.toEqual({ value: 3, done: false }); - await expect(reader.read()).resolves.toEqual({ value: undefined, done: true }); - }); - - test('should create a readable stream from an async generator function', async () => { - const stream = ReadableStream.from( - (async function* () { - let x = 1; - do { - yield x++; - await Promise.resolve(); - } while (x < 4); - })(), - ); - const reader = stream.getReader(); - - await expect(reader.read()).resolves.toEqual({ value: 1, done: false }); - await expect(reader.read()).resolves.toEqual({ value: 2, done: false }); - await expect(reader.read()).resolves.toEqual({ value: 3, done: false }); - await expect(reader.read()).resolves.toEqual({ value: undefined, done: true }); - }); - - test('should surface errors from a generator function', async () => { - const stream = ReadableStream.from( - (function* () { - yield 1; - yield 2; - throw new Error('test'); - // @ts-expect-error - this will be unreachable - yield 3; - })(), - ); - const reader = stream.getReader(); - - await expect(reader.read()).resolves.toEqual({ value: 1, done: false }); - await expect(reader.read()).resolves.toEqual({ value: 2, done: false }); - await expect(reader.read()).rejects.toThrow('test'); - await expect(reader.read()).rejects.toThrow('test'); - }); - - test('should surface errors from an async generator function', async () => { - const stream = ReadableStream.from( - (async function* () { - yield 1; - await Promise.resolve(); - yield 2; - // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors - await Promise.reject('hmmm'); - yield 3; - })(), - ); - const reader = stream.getReader(); - - await expect(reader.read()).resolves.toEqual({ value: 1, done: false }); - await expect(reader.read()).resolves.toEqual({ value: 2, done: false }); - await expect(reader.read()).rejects.toThrow('hmmm'); - }); -}); - -describe('ReadableStream cannot handle a return value', () => { - test('a Generator can end with a returned value', () => { - const gen = (function* () { - yield 1; - yield 2; - return 3; - })(); - - expect(gen.next()).toEqual({ value: 1, done: false }); - expect(gen.next()).toEqual({ value: 2, done: false }); - expect(gen.next()).toEqual({ value: 3, done: true }); - expect(gen.next()).toEqual({ value: undefined, done: true }); - }); - - test('but ReadableStream eats the returned value', async () => { - const stream = ReadableStream.from( - (function* () { - yield 1; - yield 2; - return 3; - })(), - ); - const reader = stream.getReader(); - - await expect(reader.read()).resolves.toEqual({ value: 1, done: false }); - await expect(reader.read()).resolves.toEqual({ value: 2, done: false }); - await expect(reader.read()).resolves.toEqual({ value: undefined, done: true }); - }); -}); diff --git a/packages/polyfills/src/ReadableStream.from.ts b/packages/polyfills/src/ReadableStream.from.ts deleted file mode 100644 index d18df52b..00000000 --- a/packages/polyfills/src/ReadableStream.from.ts +++ /dev/null @@ -1,40 +0,0 @@ -// This re-exports ReadableStream with a static method `from`, if the method is -// not already present. Unfortunately typescript's dom library types the global -// `ReadableStream` as a var and not just an interface, so we can't just extend -// and merge the global declarations. - -// It doesn't matter for any of our use cases, but notably, there seems to be a -// spec error: Unlike a Generator, a ReadableStream cannot be both 'done' and -// convey a 'value' at the same time, so this should not be used to streamify a -// generator with a return value. - -type ReadableStreamFrom = (iterable: Iterable | AsyncIterable) => ReadableStream; - -const ReadableStreamWithFrom: typeof ReadableStream & { from: ReadableStreamFrom } = - 'from' in ReadableStream - ? (ReadableStream as typeof ReadableStream & { from: ReadableStreamFrom }) - : Object.assign(ReadableStream, { - from(iterable: Iterable | AsyncIterable): ReadableStream { - if (Symbol.iterator in iterable) { - const it = iterable[Symbol.iterator](); - return new ReadableStream({ - pull(cont) { - const result = it.next(); - if (result.done) cont.close(); - else cont.enqueue(result.value); - }, - }); - } else if (Symbol.asyncIterator in iterable) { - const it = iterable[Symbol.asyncIterator](); - return new ReadableStream({ - async pull(cont) { - const result = await it.next(); - if (result.done) cont.close(); - else cont.enqueue(result.value); - }, - }); - } else throw TypeError('Not iterable'); - }, - }); - -export default ReadableStreamWithFrom; diff --git a/packages/polyfills/src/ReadableStream_Symbol.asyncIterator_.test.ts b/packages/polyfills/src/ReadableStream_Symbol.asyncIterator_.test.ts deleted file mode 100644 index a51ce1f6..00000000 --- a/packages/polyfills/src/ReadableStream_Symbol.asyncIterator_.test.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { describe, expect, test } from 'vitest'; -import './ReadableStream_Symbol.asyncIterator_'; - -describe('ReadableStream[Symbol.asyncIterator]', () => { - test('ReadableStream contains Symbol.asyncIterator', () => { - expect(Symbol.asyncIterator in ReadableStream.prototype).toBe(true); - }); - - test('ReadableStream can be iterated with `for await`', async () => { - const stream = new ReadableStream({ - start(controller) { - controller.enqueue(1); - controller.enqueue(2); - controller.enqueue(3); - controller.close(); - }, - }); - - const values = []; - for await (const value of stream) values.push(value); - expect(values).toEqual([1, 2, 3]); - }); - - test("ReadableStream can't be iterated with synchronous `for`", () => { - const stream = new ReadableStream({ - start(controller) { - controller.enqueue(1); - controller.enqueue(2); - controller.enqueue(3); - controller.close(); - }, - }); - - const values = []; - try { - // @ts-expect-error - this should be an error - for (const value of stream) values.push(value); - } catch (e) { - expect(e).toBeInstanceOf(TypeError); - } - }); - - test('ReadableStream can be yielded to by an async generator', async () => { - async function* genFn() { - yield* new ReadableStream({ - start(controller) { - controller.enqueue(1); - controller.enqueue(2); - controller.enqueue(3); - controller.close(); - }, - }); - } - - const values = []; - for await (const value of genFn()) values.push(value); - expect(values).toEqual([1, 2, 3]); - }); - - test("ReadableStream can't be yielded to by a synchronous generator", () => { - function* genFn() { - // @ts-expect-error - this should be an error - yield* new ReadableStream({ - start(controller) { - controller.enqueue(1); - controller.enqueue(2); - controller.enqueue(3); - controller.close(); - }, - }); - } - expect(genFn()).toThrow(TypeError); - }); -}); diff --git a/packages/polyfills/src/ReadableStream_Symbol.asyncIterator_.ts b/packages/polyfills/src/ReadableStream_Symbol.asyncIterator_.ts deleted file mode 100644 index 11da9a33..00000000 --- a/packages/polyfills/src/ReadableStream_Symbol.asyncIterator_.ts +++ /dev/null @@ -1,26 +0,0 @@ -// ReadableStreams are supposed to be async iterables, but chrome has failed to -// ship the patches. This polyfill replaces `streamToGenerator` formerly in -// `stream.ts` It's close to release, so we should be able to remove soon. -// https://chromium-review.googlesource.com/c/chromium/src/+/5263918/11 - -// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -ReadableStream.prototype[Symbol.asyncIterator] ??= async function* () { - const reader = this.getReader(); - try { - for (;;) { - const result = await reader.read(); - if (result.done) return; - else yield result.value; - } - } finally { - reader.releaseLock(); - } -}; - -declare global { - interface ReadableStream extends AsyncIterable { - [Symbol.asyncIterator](): AsyncIterableIterator; - } -} - -export {}; diff --git a/packages/polyfills/src/array-from-async.d.ts b/packages/polyfills/src/array-from-async.d.ts deleted file mode 100644 index 018fed0b..00000000 --- a/packages/polyfills/src/array-from-async.d.ts +++ /dev/null @@ -1 +0,0 @@ -declare module 'array-from-async'; diff --git a/packages/polyfills/src/streamToPromise.test.ts b/packages/polyfills/src/streamToPromise.test.ts deleted file mode 100644 index 7be43b23..00000000 --- a/packages/polyfills/src/streamToPromise.test.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { beforeEach, describe, expect, test } from 'vitest'; - -import Array from './Array.fromAsync'; - -const streamToPromise = Array.fromAsync; - -describe('streamToPromise()', () => { - describe('when one of the streamed items throws', () => { - let error: unknown; - const query = async function* () { - yield* [ - await new Promise(() => { - throw error; - }), - ]; - }; - - describe('when the thrown value is an instance of `Error`', () => { - beforeEach(() => { - error = new Error('oops'); - }); - - test('rejects with the error', async () => { - await expect(streamToPromise(query())).rejects.toThrow(error as Error); - }); - }); - - describe('old streamToPromise behavior that Array.fromAsync does not exhibit', () => { - describe('when the thrown value is a string', () => { - beforeEach(() => { - error = 'oops'; - }); - - test.fails("don't reject with the string wrapped in an instance of `Error`", async () => { - await expect(streamToPromise(query())).rejects.toThrow(new Error('oops')); - }); - }); - - describe('when the thrown value is neither an `Error` instance nor a string', () => { - beforeEach(() => { - error = 1n; - }); - - test.fails("don't reject with an unknown error", async () => { - await expect(streamToPromise(query())).rejects.toThrow( - new Error('Unknown error in `streamToPromise`'), - ); - }); - }); - }); - }); -}); diff --git a/packages/polyfills/tsconfig.json b/packages/polyfills/tsconfig.json deleted file mode 100644 index 459b3e49..00000000 --- a/packages/polyfills/tsconfig.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": "tsconfig/base.json", - "exclude": ["node_modules"], - "compilerOptions": { - "outDir": "dist", - "noEmit": true - } -} diff --git a/packages/protobuf/CHANGELOG.md b/packages/protobuf/CHANGELOG.md deleted file mode 100644 index e3bba54d..00000000 --- a/packages/protobuf/CHANGELOG.md +++ /dev/null @@ -1,53 +0,0 @@ -# @penumbra-zone/protobuf - -## 4.1.0 - -### Minor Changes - -- 81b9536: add ibc types to registry, address wasm ser/de of protobuf.Any types - -## 4.0.0 - -### Major Changes - -- 8fe4de6: correct ordering of default export - -## 3.0.0 - -### Major Changes - -- 8b121ec: change package exports to use 'default' field - -## 2.1.0 - -### Minor Changes - -- 3ea1e6c: update buf types dependencies - -### Patch Changes - -- 4f8c150: restore DutchAuction type to registry -- 029eebb: organize internally, export service definitions - -## 2.0.0 - -### Major Changes - -- 8ccaf30: externalize dependencies - -### Patch Changes - -- 8ccaf30: readme update recommending bsr -- e35c6f7: Deps bumped to latest - -## 1.1.0 - -### Minor Changes - -- v8.0.0 versioning and manifest - -## 1.0.0 - -### Major Changes - -- 6fb898a: initial release of `@penumbra-zone/protobuf` package containing `typeRegistry`. same removed from `@penumbra-zone/types` diff --git a/packages/protobuf/README.md b/packages/protobuf/README.md deleted file mode 100644 index 9466f9cb..00000000 --- a/packages/protobuf/README.md +++ /dev/null @@ -1,44 +0,0 @@ -# `@penumbra-zone/protobuf` - -## If you are looking for a Penumbra extension client - -You should install `@penumbra-zone/client`. This package is provided for -developers interested in lower-level work or more detailed configuration. - ---- - -This package collects types and some configuration intended for use with -`@penumbra-zone/transport-dom`. - -**To use this package, you need to [enable the Buf Schema Registry](https://buf.build/docs/bsr/generated-sdks/npm):** - -```sh -echo "@buf:registry=https://buf.build/gen/npm/v1/" >> .npmrc -``` - -### Exports - -This package exports a `typeRegistry` (and `jsonOptions` including said -registry) for use with `createChannelTransport` or any `@connectrpc` transport. - -All types necessary for a to serialize/deserialize communication with Prax or -any other Penumbra extension are included. - -Service definitions for all relevant services are also re-exported. - -### A Simple example - -```js -import { jsonOptions } from '@penumbra-zone/protobuf'; -import { createChannelTransport } from '@penumbra-zone/transport-dom'; - -// naively get first available provider -const provider = Object.values(window[Symbol.for('penumbra')])[0]; -void provider.request(); - -// establish a transport -const transport = createChannelTransport({ jsonOptions, getPort: provider.connect }); - -// export function to create client -export const createPenumbraClient = serviceType => createPromiseClient(serviceType, transport); -``` diff --git a/packages/protobuf/eslint.config.mjs b/packages/protobuf/eslint.config.mjs deleted file mode 100644 index a53ed8e5..00000000 --- a/packages/protobuf/eslint.config.mjs +++ /dev/null @@ -1,13 +0,0 @@ -import { penumbraEslintConfig } from '@penumbra-zone/eslint-config'; -import { config, parser } from 'typescript-eslint'; - -export default config({ - ...penumbraEslintConfig, - languageOptions: { - parser, - parserOptions: { - project: true, - tsconfigRootDir: import.meta.dirname, - }, - }, -}); diff --git a/packages/protobuf/package.json b/packages/protobuf/package.json deleted file mode 100644 index 4ddca135..00000000 --- a/packages/protobuf/package.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "name": "@penumbra-zone/protobuf", - "version": "4.1.0", - "private": true, - "license": "(MIT OR Apache-2.0)", - "description": "Exports a `@bufbuild/protobuf` type registry with all message types necessary to communicate with a Penumbra extension", - "type": "module", - "scripts": { - "build": "tsc --build", - "clean": "rm -rfv dist", - "lint": "eslint src", - "prepack": "pnpm clean && pnpm build" - }, - "exports": { - ".": "./src/index.ts" - }, - "publishConfig": { - "exports": { - ".": { - "types": "./dist/index.d.ts", - "default": "./dist/index.js" - } - } - }, - "devDependencies": { - "@bufbuild/protobuf": "^1.10.0", - "@connectrpc/connect": "^1.4.0" - }, - "peerDependencies": { - "@buf/cosmos_ibc.bufbuild_es": "1.9.0-20240530142100-ad4444393387.1", - "@buf/cosmos_ibc.connectrpc_es": "1.4.0-20240530142100-ad4444393387.2", - "@buf/penumbra-zone_penumbra.connectrpc_es": "1.4.0-20240528180215-8fe1c79485f8.2", - "@bufbuild/protobuf": "^1.10.0", - "@connectrpc/connect": "^1.4.0" - } -} diff --git a/packages/protobuf/src/ibc-core.ts b/packages/protobuf/src/ibc-core.ts deleted file mode 100644 index 734a440e..00000000 --- a/packages/protobuf/src/ibc-core.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { Query as IbcChannelService } from '@buf/cosmos_ibc.connectrpc_es/ibc/core/channel/v1/query_connect'; -export { Query as IbcClientService } from '@buf/cosmos_ibc.connectrpc_es/ibc/core/client/v1/query_connect'; -export { Query as IbcConnectionService } from '@buf/cosmos_ibc.connectrpc_es/ibc/core/connection/v1/query_connect'; diff --git a/packages/protobuf/src/index.ts b/packages/protobuf/src/index.ts deleted file mode 100644 index 75a14a84..00000000 --- a/packages/protobuf/src/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -export * from './ibc-core'; -export * from './penumbra'; -export * from './penumbra-core'; -export * from './penumbra-cnidarium'; -export * from './penumbra-proxy'; - -export * from './registry'; -export * from './web'; diff --git a/packages/protobuf/src/penumbra-cnidarium.ts b/packages/protobuf/src/penumbra-cnidarium.ts deleted file mode 100644 index d87ca54f..00000000 --- a/packages/protobuf/src/penumbra-cnidarium.ts +++ /dev/null @@ -1 +0,0 @@ -export { QueryService as CnidariumService } from '@buf/penumbra-zone_penumbra.connectrpc_es/penumbra/cnidarium/v1/cnidarium_connect'; diff --git a/packages/protobuf/src/penumbra-core.ts b/packages/protobuf/src/penumbra-core.ts deleted file mode 100644 index 6f0f49a0..00000000 --- a/packages/protobuf/src/penumbra-core.ts +++ /dev/null @@ -1,12 +0,0 @@ -export { QueryService as AppService } from '@buf/penumbra-zone_penumbra.connectrpc_es/penumbra/core/app/v1/app_connect'; - -export { QueryService as AuctionService } from '@buf/penumbra-zone_penumbra.connectrpc_es/penumbra/core/component/auction/v1/auction_connect'; -export { QueryService as CompactBlockService } from '@buf/penumbra-zone_penumbra.connectrpc_es/penumbra/core/component/compact_block/v1/compact_block_connect'; -export { - QueryService as DexService, - SimulationService, -} from '@buf/penumbra-zone_penumbra.connectrpc_es/penumbra/core/component/dex/v1/dex_connect'; -export { QueryService as GovernanceService } from '@buf/penumbra-zone_penumbra.connectrpc_es/penumbra/core/component/governance/v1/governance_connect'; -export { QueryService as SctService } from '@buf/penumbra-zone_penumbra.connectrpc_es/penumbra/core/component/sct/v1/sct_connect'; -export { QueryService as ShieldedPoolService } from '@buf/penumbra-zone_penumbra.connectrpc_es/penumbra/core/component/shielded_pool/v1/shielded_pool_connect'; -export { QueryService as StakeService } from '@buf/penumbra-zone_penumbra.connectrpc_es/penumbra/core/component/stake/v1/stake_connect'; diff --git a/packages/protobuf/src/penumbra-proxy.ts b/packages/protobuf/src/penumbra-proxy.ts deleted file mode 100644 index fb0e1dc3..00000000 --- a/packages/protobuf/src/penumbra-proxy.ts +++ /dev/null @@ -1 +0,0 @@ -export { TendermintProxyService } from '@buf/penumbra-zone_penumbra.connectrpc_es/penumbra/util/tendermint_proxy/v1/tendermint_proxy_connect'; diff --git a/packages/protobuf/src/penumbra.ts b/packages/protobuf/src/penumbra.ts deleted file mode 100644 index 38799d2e..00000000 --- a/packages/protobuf/src/penumbra.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { CustodyService } from '@buf/penumbra-zone_penumbra.connectrpc_es/penumbra/custody/v1/custody_connect'; -export { ViewService } from '@buf/penumbra-zone_penumbra.connectrpc_es/penumbra/view/v1/view_connect'; diff --git a/packages/protobuf/src/registry.ts b/packages/protobuf/src/registry.ts deleted file mode 100644 index 3e7d707e..00000000 --- a/packages/protobuf/src/registry.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { IMessageTypeRegistry, createRegistry } from '@bufbuild/protobuf'; - -import * as ibcCore from './ibc-core'; -import * as penumbra from './penumbra'; -import * as penumbraCore from './penumbra-core'; -import * as penumbraCnidarium from './penumbra-cnidarium'; -import * as penumbraProxy from './penumbra-proxy'; - -import { - ClientState, - Header, -} from '@buf/cosmos_ibc.bufbuild_es/ibc/lightclients/tendermint/v1/tendermint_pb'; -import { MsgUpdateClient } from '@buf/cosmos_ibc.bufbuild_es/ibc/core/client/v1/tx_pb'; -import { MsgRecvPacket } from '@buf/cosmos_ibc.bufbuild_es/ibc/core/channel/v1/tx_pb'; -import { DutchAuction } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/auction/v1/auction_pb'; - -/** - * This type registry is for JSON serialization of protobuf messages. - * - * Some specced messages contain 'Any'-type fields, serialized with type - * annotation URLs resolved with this registry. - * - * This registry currently contains types for all services used in communication - * with a Penumbra extension, and should be able to resolve any message type - * encountered. - */ - -export const typeRegistry: IMessageTypeRegistry = createRegistry( - ...Object.values(ibcCore), - ...Object.values(penumbra), - ...Object.values(penumbraCore), - ...Object.values(penumbraCnidarium), - ...Object.values(penumbraProxy), - - // Types not explicitly referenced by any above services should be added here. - // Otherwise, it will not be possible to serialize/deserialize these types if, - // e.g., they're used in an `Any` protobuf. - - // @buf/cosmos_ibc.bufbuild_es/ibc/lightclients/tendermint/v1/tendermint_pb - ClientState, - Header, - - // @buf/cosmos_ibc.bufbuild_es/ibc/core/client/v1/tx_pb - MsgUpdateClient, - - // @buf/cosmos_ibc.bufbuild_es/ibc/core/channel/v1/tx_pb - MsgRecvPacket, - - // @buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/auction/v1/auction_pb - DutchAuction, -); - -/** - * Appropriate for any ConnectRPC `Transport` object or protobuf `Any` - * pack/unpack that handles protojson expected to contain these registry types. - * @see https://docs.cosmos.network/v0.50/build/architecture/adr-027-deterministic-protobuf-serialization - */ -export const jsonOptions = { - typeRegistry, - - // read options - ignoreUnknownFields: true, - - // write options - emitDefaultValues: false, -}; diff --git a/packages/protobuf/src/web.ts b/packages/protobuf/src/web.ts deleted file mode 100644 index 95c4ae8a..00000000 --- a/packages/protobuf/src/web.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { IbcChannelService, IbcClientService, IbcConnectionService } from './ibc-core'; -import type { CustodyService, ViewService } from './penumbra'; -import type { DexService, SctService, SimulationService, StakeService } from './penumbra-core'; -import type { TendermintProxyService } from './penumbra-proxy'; - -export type PenumbraService = - | typeof CustodyService - | typeof DexService - | typeof IbcChannelService - | typeof IbcClientService - | typeof IbcConnectionService - | typeof SctService - | typeof SimulationService - | typeof StakeService - | typeof TendermintProxyService - | typeof ViewService; diff --git a/packages/protobuf/tsconfig.json b/packages/protobuf/tsconfig.json deleted file mode 100644 index 059881bc..00000000 --- a/packages/protobuf/tsconfig.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": "tsconfig/base.json", - "include": ["src/*.ts"], - "exclude": ["node_modules", "dist"], - "compilerOptions": { - "outDir": "dist" - } -} diff --git a/packages/query/CHANGELOG.md b/packages/query/CHANGELOG.md deleted file mode 100644 index 1ee63548..00000000 --- a/packages/query/CHANGELOG.md +++ /dev/null @@ -1,214 +0,0 @@ -# @penumbra-zone/query - -## 4.1.0 - -### Minor Changes - -- ab9d743: decouple service/rpc init - -### Patch Changes - -- 6ee8222: prevent processing the same block twice -- Updated dependencies [ab9d743] -- Updated dependencies [282eabf] -- Updated dependencies [81b9536] -- Updated dependencies [14ba562] -- Updated dependencies [6b06e04] -- Updated dependencies [c8e8d15] - - @penumbra-zone/types@7.1.0 - - @penumbra-zone/protobuf@4.1.0 - - @penumbra-zone/wasm@7.1.0 - - @penumbra-zone/getters@6.1.0 - - @penumbra-zone/crypto-web@3.0.10 - -## 4.0.2 - -### Patch Changes - -- Updated dependencies [8fe4de6] - - @penumbra-zone/protobuf@4.0.0 - - @penumbra-zone/bech32m@5.0.0 - - @penumbra-zone/getters@6.0.0 - - @penumbra-zone/wasm@7.0.0 - - @penumbra-zone/types@7.0.1 - - @penumbra-zone/crypto-web@3.0.9 - -## 4.0.1 - -### Patch Changes - -- Updated dependencies [bb5f621] -- Updated dependencies [8b121ec] - - @penumbra-zone/types@7.0.0 - - @penumbra-zone/protobuf@3.0.0 - - @penumbra-zone/bech32m@4.0.0 - - @penumbra-zone/getters@5.0.0 - - @penumbra-zone/wasm@6.0.0 - - @penumbra-zone/crypto-web@3.0.8 - -## 4.0.0 - -### Major Changes - -- 029eebb: use service definitions from protobuf collection package - -### Minor Changes - -- 3ea1e6c: update buf types dependencies - -### Patch Changes - -- Updated dependencies [120b654] -- Updated dependencies [4f8c150] -- Updated dependencies [029eebb] -- Updated dependencies [029eebb] -- Updated dependencies [e86448e] -- Updated dependencies [3ea1e6c] - - @penumbra-zone/getters@4.1.0 - - @penumbra-zone/protobuf@2.1.0 - - @penumbra-zone/types@6.0.0 - - @penumbra-zone/wasm@5.1.0 - - @penumbra-zone/bech32m@3.2.0 - - @penumbra-zone/crypto-web@3.0.7 - -## 3.2.1 - -### Patch Changes - -- @penumbra-zone/wasm@5.0.1 - -## 3.2.0 - -### Minor Changes - -- e4c9fce: Add features to handle auction withdrawals - -### Patch Changes - -- e35c6f7: Deps bumped to latest -- Updated dependencies [146b48d] -- Updated dependencies [65677c1] -- Updated dependencies [8ccaf30] -- Updated dependencies [8ccaf30] -- Updated dependencies [e35c6f7] -- Updated dependencies [cf63b30] -- Updated dependencies [99feb9d] -- Updated dependencies [e4c9fce] -- Updated dependencies [8ccaf30] - - @penumbra-zone/getters@4.0.0 - - @penumbra-zone/types@5.0.0 - - @penumbra-zone/wasm@5.0.0 - - @penumbra-zone/bech32m@3.1.1 - - @penumbra-zone/crypto-web@3.0.6 - -## 3.1.0 - -### Minor Changes - -- v8.0.0 versioning and manifest - -### Patch Changes - -- Updated dependencies - - @penumbra-zone/bech32m@3.1.0 - - @penumbra-zone/types@4.1.0 - - @penumbra-zone/wasm@4.0.4 - - @penumbra-zone/getters@3.0.2 - - @penumbra-zone/crypto-web@3.0.5 - -## 3.0.2 - -### Patch Changes - -- Updated dependencies [8410d2f] - - @penumbra-zone/bech32m@3.0.1 - - @penumbra-zone/getters@3.0.1 - - @penumbra-zone/types@4.0.1 - - @penumbra-zone/wasm@4.0.3 - - @penumbra-zone/crypto-web@3.0.4 - -## 3.0.1 - -### Patch Changes - -- Updated dependencies [6fb898a] - - @penumbra-zone/types@4.0.0 - - @penumbra-zone/crypto-web@3.0.3 - - @penumbra-zone/wasm@4.0.2 - -## 3.0.0 - -### Major Changes - -- 3148375: remove `/src/` path segment from exports - -### Minor Changes - -- 55f31c9: Save sct positions of swaps - -### Patch Changes - -- Updated dependencies [3148375] -- Updated dependencies [fdd4303] - - @penumbra-zone/constants@4.0.0 - - @penumbra-zone/polyfills@3.0.0 - - @penumbra-zone/getters@3.0.0 - - @penumbra-zone/types@3.0.0 - - @penumbra-zone/bech32m@3.0.0 - - @penumbra-zone/crypto-web@3.0.2 - - @penumbra-zone/wasm@4.0.1 - -## 2.0.3 - -### Patch Changes - -- Updated dependencies [78ab976] -- Updated dependencies [862283c] - - @penumbra-zone/wasm@4.0.0 - - @penumbra-zone/constants@3.0.0 - - @penumbra-zone/getters@2.0.1 - - @penumbra-zone/types@2.0.1 - - @penumbra-zone/crypto-web@3.0.1 - -## 2.0.2 - -### Patch Changes - -- Updated dependencies [b4082b7] - - @penumbra-zone/crypto-web@3.0.0 - -## 2.0.1 - -### Patch Changes - -- Updated dependencies [66c2407] - - @penumbra-zone/wasm@3.0.0 - -## 2.0.0 - -### Major Changes - -- 929d278: barrel imports to facilitate better tree shaking - -### Patch Changes - -- 8933117: Account for changes to core -- Updated dependencies [8933117] -- Updated dependencies [929d278] - - @penumbra-zone/wasm@2.0.0 - - @penumbra-zone/constants@2.0.0 - - @penumbra-zone/getters@2.0.0 - - @penumbra-zone/bech32@2.0.0 - - @penumbra-zone/crypto-web@2.0.0 - - @penumbra-zone/types@2.0.0 - - @penumbra-zone/polyfills@2.0.0 - -## 1.0.2 - -### Patch Changes - -- Updated dependencies - - @penumbra-zone/constants@1.1.0 - - @penumbra-zone/types@1.1.0 - - @penumbra-zone/crypto-web@1.0.1 - - @penumbra-zone/wasm@1.0.2 diff --git a/packages/query/eslint.config.mjs b/packages/query/eslint.config.mjs deleted file mode 100644 index a53ed8e5..00000000 --- a/packages/query/eslint.config.mjs +++ /dev/null @@ -1,13 +0,0 @@ -import { penumbraEslintConfig } from '@penumbra-zone/eslint-config'; -import { config, parser } from 'typescript-eslint'; - -export default config({ - ...penumbraEslintConfig, - languageOptions: { - parser, - parserOptions: { - project: true, - tsconfigRootDir: import.meta.dirname, - }, - }, -}); diff --git a/packages/query/package.json b/packages/query/package.json deleted file mode 100644 index 83a01984..00000000 --- a/packages/query/package.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "name": "@penumbra-zone/query", - "version": "4.1.0", - "private": true, - "license": "(MIT OR Apache-2.0)", - "type": "module", - "scripts": { - "lint": "eslint src", - "test": "vitest run" - }, - "exports": { - "./*": "./src/*.ts" - }, - "dependencies": { - "@penumbra-zone/bech32m": "workspace:*", - "@penumbra-zone/crypto-web": "workspace:*", - "@penumbra-zone/getters": "workspace:*", - "@penumbra-zone/protobuf": "workspace:*", - "@penumbra-zone/types": "workspace:*", - "@penumbra-zone/wasm": "workspace:*", - "exponential-backoff": "^3.1.1" - }, - "devDependencies": { - "@buf/cosmos_ibc.bufbuild_es": "1.9.0-20240530142100-ad4444393387.1", - "@buf/penumbra-zone_penumbra.bufbuild_es": "1.9.0-20240528180215-8fe1c79485f8.1", - "@bufbuild/protobuf": "^1.10.0", - "@connectrpc/connect": "^1.4.0", - "@connectrpc/connect-web": "^1.4.0" - }, - "peerDependencies": { - "@buf/cosmos_ibc.bufbuild_es": "1.9.0-20240530142100-ad4444393387.1", - "@buf/penumbra-zone_penumbra.bufbuild_es": "1.9.0-20240528180215-8fe1c79485f8.1", - "@bufbuild/protobuf": "^1.10.0", - "@connectrpc/connect": "^1.4.0", - "@connectrpc/connect-web": "^1.4.0" - } -} diff --git a/packages/query/src/block-processor.ts b/packages/query/src/block-processor.ts deleted file mode 100644 index 5af75348..00000000 --- a/packages/query/src/block-processor.ts +++ /dev/null @@ -1,607 +0,0 @@ -import { RootQuerier } from './root-querier'; -import { sha256Hash } from '@penumbra-zone/crypto-web/sha256'; -import { computePositionId, getLpNftMetadata } from '@penumbra-zone/wasm/dex'; - -import { - getExchangeRateFromValidatorInfoResponse, - getIdentityKeyFromValidatorInfoResponse, -} from '@penumbra-zone/getters/validator-info-response'; -import { - PositionState, - PositionState_PositionStateEnum, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/dex/v1/dex_pb'; -import { - CommitmentSource, - Nullifier, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/sct/v1/sct_pb'; -import { - Action, - Transaction, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/transaction/v1/transaction_pb'; -import { TransactionId } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/txhash/v1/txhash_pb'; -import { StateCommitment } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/crypto/tct/v1/tct_pb'; -import { - SpendableNoteRecord, - SwapRecord, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; -import { backOff } from 'exponential-backoff'; -import type { BlockProcessorInterface } from '@penumbra-zone/types/block-processor'; -import type { IndexedDbInterface } from '@penumbra-zone/types/indexed-db'; -import type { ViewServerInterface } from '@penumbra-zone/types/servers'; -import { customizeSymbol } from '@penumbra-zone/wasm/metadata'; -import { updatePricesFromSwaps } from './price-indexer'; -import { - AssetId, - Metadata, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; -import { bech32mIdentityKey } from '@penumbra-zone/bech32m/penumbravalid'; -import { getAssetId } from '@penumbra-zone/getters/metadata'; -import { PRICE_RELEVANCE_THRESHOLDS, assetPatterns } from '@penumbra-zone/types/assets'; -import { toDecimalExchangeRate } from '@penumbra-zone/types/amount'; -import { ValidatorInfoResponse } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/stake/v1/stake_pb'; -import { uint8ArrayToHex } from '@penumbra-zone/types/hex'; -import { AuctionId } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/auction/v1/auction_pb'; -import { auctionIdFromBech32 } from '@penumbra-zone/bech32m/pauctid'; -import { ScanBlockResult } from '@penumbra-zone/types/state-commitment-tree'; -import { processActionDutchAuctionEnd } from './helpers/process-action-dutch-auction-end'; -import { processActionDutchAuctionSchedule } from './helpers/process-action-dutch-auction-schedule'; -import { processActionDutchAuctionWithdraw } from './helpers/process-action-dutch-auction-withdraw'; - -declare global { - // `var` required for global declaration (as let/const are block scoped) - // eslint-disable-next-line no-var - var ASSERT_ROOT_VALID: boolean | undefined; -} - -interface QueryClientProps { - querier: RootQuerier; - indexedDb: IndexedDbInterface; - viewServer: ViewServerInterface; - numeraires: AssetId[]; - stakingTokenMetadata: Metadata; -} - -const BLANK_TX_SOURCE = new CommitmentSource({ - source: { case: 'transaction', value: { id: new Uint8Array() } }, -}); - -const POSITION_STATES: PositionState[] = [ - new PositionState({ state: PositionState_PositionStateEnum.OPENED }), - new PositionState({ state: PositionState_PositionStateEnum.CLOSED }), - new PositionState({ state: PositionState_PositionStateEnum.WITHDRAWN, sequence: 0n }), -]; - -export class BlockProcessor implements BlockProcessorInterface { - private readonly querier: RootQuerier; - private readonly indexedDb: IndexedDbInterface; - private readonly viewServer: ViewServerInterface; - private readonly abortController: AbortController = new AbortController(); - private numeraires: AssetId[]; - private readonly stakingTokenMetadata: Metadata; - private syncPromise: Promise | undefined; - - constructor({ - indexedDb, - viewServer, - querier, - numeraires, - stakingTokenMetadata, - }: QueryClientProps) { - this.indexedDb = indexedDb; - this.viewServer = viewServer; - this.querier = querier; - this.numeraires = numeraires; - this.stakingTokenMetadata = stakingTokenMetadata; - } - - // If sync() is called multiple times concurrently, they'll all wait for - // the same promise rather than each starting their own sync process. - public sync = (): Promise => - (this.syncPromise ??= backOff(() => this.syncAndStore(), { - delayFirstAttempt: false, - startingDelay: 5_000, // 5 seconds - numOfAttempts: Infinity, - maxDelay: 20_000, // 20 seconds - retry: async (e, attemptNumber) => { - if (process.env['NODE_ENV'] === 'development') - console.debug('Sync failure', attemptNumber, e); - await this.viewServer.resetTreeToStored(); - return !this.abortController.signal.aborted; - }, - })).finally( - // if the above promise completes, exponential backoff has ended (aborted). - // reset the rejected promise to allow for a new sync to be started. - () => (this.syncPromise = undefined), - ); - - public stop = (r: string) => this.abortController.abort(`Sync stop ${r}`); - - setNumeraires(numeraires: AssetId[]): void { - this.numeraires = numeraires; - } - - private async syncAndStore() { - // start at next block, or genesis if height is undefined - let currentHeight = (await this.indexedDb.getFullSyncHeight()) ?? -1n; - - // this is the first network query of the block processor. use backoff to - // delay until network is available - let latestKnownBlockHeight = await backOff( - async () => { - const latest = await this.querier.tendermint.latestBlockHeight(); - if (!latest) throw new Error('Unknown latest block height'); - return latest; - }, - { retry: () => true }, - ); - - if (currentHeight === -1n) { - // In the `for` loop below, we only update validator infos once we've - // reached the latest known epoch. This means that, if a user is syncing - // for the first time, they could experience a broken UI until the latest - // known epoch is reached, since they may have delegation tokens but no - // validator info to go with them. So we'll update validator infos at the - // beginning of sync as well, and force the rest of sync to wait until - // it's done. - await this.updateValidatorInfos(0n); - } - - // this is an indefinite stream of the (compact) chain from the network - // intended to run continuously - for await (const compactBlock of this.querier.compactBlock.compactBlockRange({ - startHeight: currentHeight + 1n, - keepAlive: true, - abortSignal: this.abortController.signal, - })) { - // confirm block height to prevent corruption of local state - if (compactBlock.height === currentHeight + 1n) { - currentHeight = compactBlock.height; - } else { - throw new Error(`Unexpected block height: ${compactBlock.height} at ${currentHeight}`); - } - - if (compactBlock.appParametersUpdated) { - await this.indexedDb.saveAppParams(await this.querier.app.appParams()); - } - if (compactBlock.fmdParameters) { - await this.indexedDb.saveFmdParams(compactBlock.fmdParameters); - } - if (compactBlock.gasPrices) { - await this.indexedDb.saveGasPrices(compactBlock.gasPrices); - } - - // wasm view server scan - // - decrypts new notes - // - decrypts new swaps - // - updates idb with advice - const scannerWantsFlush = await this.viewServer.scanBlock(compactBlock); - - // flushing is slow, avoid it until - // - wasm says - // - every 1000th block - // - every block at tip - const flushReasons = { - scannerWantsFlush, - interval: compactBlock.height % 1000n === 0n, - new: compactBlock.height > latestKnownBlockHeight, - }; - - const recordsByCommitment = new Map(); - let flush: ScanBlockResult | undefined; - if (Object.values(flushReasons).some(Boolean)) { - flush = this.viewServer.flushUpdates(); - - // in an atomic query, this - // - saves 'sctUpdates' - // - saves new decrypted notes - // - saves new decrypted swaps - // - updates last block synced - await this.indexedDb.saveScanResult(flush); - - // - detect unknown asset types - // - shielded pool for asset metadata - // - or, generate default fallback metadata - // - update idb - await this.identifyNewAssets(flush.newNotes); - - for (const spendableNoteRecord of flush.newNotes) - recordsByCommitment.set(spendableNoteRecord.noteCommitment!, spendableNoteRecord); - for (const swapRecord of flush.newSwaps) - recordsByCommitment.set(swapRecord.swapCommitment!, swapRecord); - } - - // nullifiers on this block may match notes or swaps from db - // - update idb, mark as spent/claimed - // - return nullifiers used in this way - const spentNullifiers = await this.resolveNullifiers( - compactBlock.nullifiers, - compactBlock.height, - ); - - // if a new record involves a state commitment, scan all block tx - if (spentNullifiers.size || recordsByCommitment.size) { - // this is a network query - const blockTx = await this.querier.app.txsByHeight(compactBlock.height); - - // identify tx that involve a new record - // - compare nullifiers - // - compare state commitments - // - collect relevant tx for info generation later - // - if matched by commitment, collect record with recovered source - const { relevantTx, recordsWithSources } = await this.identifyTransactions( - spentNullifiers, - recordsByCommitment, - blockTx, - ); - - // this simply stores the new records with 'rehydrated' sources to idb - // TODO: this is the second time we save these records, after "saveScanResult" - await this.saveRecoveredCommitmentSources(recordsWithSources); - - await this.processTransactions(blockTx); - - // at this point txinfo can be generated and saved. this will resolve - // pending broadcasts, and populate the transaction list. - // - calls wasm for each relevant tx - // - saves to idb - await this.saveTransactions(compactBlock.height, relevantTx); - } - - /** - * This... really isn't great. - * - * You can see above that we're already iterating over flush.newNotes. So - * why don't we put this call to - * `this.maybeUpsertAuctionWithNoteCommitment()` inside that earlier `for` - * loop? - * - * The problem is, we need to call `this.processTransactions()` before - * calling `this.maybeUpsertAuctionWithNoteCommitment()`, because - * `this.processTransactions()` is what saves the auction NFT metadata to - * the database. `this.maybeUpsertAuctionWithNoteCommitment()` depends on - * that auction NFT metadata being saved already to be able to detect - * whether a given note is for an auction NFT; only then will it save the - * note's commitment to the `AUCTIONS` table. - * - * "So why not just move `this.processTransactions()` to before the block - * where we handle `flush.newNotes`?" Because `this.processTransactions()` - * should only run after we've handled `flush.newNotes`, since we depend - * on the result of the flush to determine whether there are transactions - * to process in the first place. It's a catch-22. - * - * This isn't a problem in core because core isn't going back and forth - * between Rust and TypeScript like we are. If and when we move the block - * processor into Rust, this issue should be resolved. - */ - for (const spendableNoteRecord of flush?.newNotes ?? []) { - await this.maybeUpsertAuctionWithNoteCommitment(spendableNoteRecord); - } - - // We do not store historical prices, - // so there is no point in saving prices that would already be considered obsolete at the time of saving - const blockInPriceRelevanceThreshold = - compactBlock.height >= latestKnownBlockHeight - BigInt(PRICE_RELEVANCE_THRESHOLDS.default); - - // we can't use third-party price oracles for privacy reasons, - // so we have to get asset prices from swap results during block scans - // and store them locally in indexed-db. - if (blockInPriceRelevanceThreshold && compactBlock.swapOutputs.length) { - await updatePricesFromSwaps( - this.indexedDb, - this.numeraires, - compactBlock.swapOutputs, - compactBlock.height, - ); - } - - // We only query Tendermint for the latest known block height once, when - // the block processor starts running. Once we're caught up, though, the - // chain will of course continue adding blocks, and we'll keep processing - // them. So, we need to update `latestKnownBlockHeight` once we've passed - // it. - if (compactBlock.height > latestKnownBlockHeight) { - latestKnownBlockHeight = compactBlock.height; - } - - const isLastBlockOfEpoch = !!compactBlock.epochRoot; - if (isLastBlockOfEpoch) { - await this.handleEpochTransition(compactBlock.height, latestKnownBlockHeight); - } - - if (globalThis.ASSERT_ROOT_VALID) { - await this.assertRootValid(compactBlock.height); - } - } - } - - private async saveRecoveredCommitmentSources(recovered: (SpendableNoteRecord | SwapRecord)[]) { - for (const record of recovered) - if (record instanceof SpendableNoteRecord) await this.indexedDb.saveSpendableNote(record); - else if (record instanceof SwapRecord) await this.indexedDb.saveSwap(record); - else throw new Error('Unexpected record type'); - } - - private async identifyNewAssets(notes: SpendableNoteRecord[]) { - for (const note of notes) { - const assetId = note.note?.value?.assetId; - if (!assetId) continue; - - await this.saveAndReturnMetadata(assetId); - } - } - - private async identifyTransactions( - spentNullifiers: Set, - commitmentRecordsByStateCommitment: Map, - blockTx: Transaction[], - ) { - const relevantTx = new Map(); - const recordsWithSources = new Array(); - for (const tx of blockTx) { - let txId: TransactionId | undefined; - - const txCommitments = (tx.body?.actions ?? []).flatMap(({ action }) => { - switch (action.case) { - case 'output': - return action.value.body?.notePayload?.noteCommitment; - case 'swap': - return action.value.body?.payload?.commitment; - case 'swapClaim': - return [action.value.body?.output1Commitment, action.value.body?.output2Commitment]; - default: // TODO: what other actions have commitments? - return; - } - }); - - const txNullifiers = (tx.body?.actions ?? []).map(({ action }) => { - switch (action.case) { - case 'spend': - case 'swapClaim': - return action.value.body?.nullifier; - default: // TODO: what other actions have nullifiers? - return; - } - }); - - for (const spentNullifier of spentNullifiers) { - if (txNullifiers.some(txNullifier => spentNullifier.equals(txNullifier))) { - txId = new TransactionId({ inner: await sha256Hash(tx.toBinary()) }); - relevantTx.set(txId, tx); - spentNullifiers.delete(spentNullifier); - } - } - - for (const [stateCommitment, spendableNoteRecord] of commitmentRecordsByStateCommitment) { - if (txCommitments.some(txCommitment => stateCommitment.equals(txCommitment))) { - txId ??= new TransactionId({ inner: await sha256Hash(tx.toBinary()) }); - relevantTx.set(txId, tx); - if (BLANK_TX_SOURCE.equals(spendableNoteRecord.source)) { - spendableNoteRecord.source = new CommitmentSource({ - source: { case: 'transaction', value: { id: txId.inner } }, - }); - recordsWithSources.push(spendableNoteRecord); - } - commitmentRecordsByStateCommitment.delete(stateCommitment); - } - } - } - return { relevantTx, recordsWithSources }; - } - - private async saveAndReturnMetadata(assetId: AssetId): Promise { - const metadataAlreadyInDb = await this.indexedDb.getAssetsMetadata(assetId); - if (metadataAlreadyInDb) return metadataAlreadyInDb; - - const metadataFromNode = await this.querier.shieldedPool.assetMetadataById(assetId); - - //do not save IBC token metadata that are not in the prax registry - const isIbcAsset = metadataFromNode && assetPatterns.ibc.matches(metadataFromNode.display); - - if (metadataFromNode && !isIbcAsset) { - await this.indexedDb.saveAssetsMetadata(customizeSymbol(metadataFromNode)); - return metadataFromNode; - } - - return undefined; - } - - // Nullifier is published in network when a note is spent or swap is claimed. - private async resolveNullifiers(nullifiers: Nullifier[], height: bigint) { - const spentNullifiers = new Set(); - - for (const nullifier of nullifiers) { - const record = - (await this.indexedDb.getSpendableNoteByNullifier(nullifier)) ?? - (await this.indexedDb.getSwapByNullifier(nullifier)); - if (!record) continue; - - spentNullifiers.add(nullifier); - - if (record instanceof SpendableNoteRecord) { - record.heightSpent = height; - await this.indexedDb.saveSpendableNote(record); - } else if (record instanceof SwapRecord) { - record.heightClaimed = height; - await this.indexedDb.saveSwap(record); - } - } - - return spentNullifiers; - } - - /** - * Identify various pieces of data from the transaction that we need to save, - * such as metadata, liquidity positions, etc. - */ - private async processTransactions(txs: Transaction[]) { - for (const tx of txs) { - for (const { action } of tx.body?.actions ?? []) { - await Promise.all([this.identifyAuctionNfts(action), this.identifyLpNftPositions(action)]); - } - } - } - - /** - * during wasm tx info generation later, wasm independently queries idb for - * asset metadata, so we have to pre-populate. Auction NFTs aren't known by - * the chain so aren't populated by identifyNewAssets. - */ - private async identifyAuctionNfts(action: Action['action']) { - if (action.case === 'actionDutchAuctionSchedule' && action.value.description) { - await processActionDutchAuctionSchedule(action.value.description, this.indexedDb); - } else if (action.case === 'actionDutchAuctionEnd' && action.value.auctionId) { - await processActionDutchAuctionEnd(action.value, this.querier.auction, this.indexedDb); - } else if (action.case === 'actionDutchAuctionWithdraw' && action.value.auctionId) { - await processActionDutchAuctionWithdraw( - action.value.auctionId, - action.value.seq, - this.indexedDb, - ); - } - } - - /** - * during wasm tx info generation later, wasm independently queries idb for - * asset metadata, so we have to pre-populate. LpNft position states aren't - * known by the chain so aren't populated by identifyNewAssets - * - detect LpNft position opens - * - generate all possible position state metadata - * - update idb - */ - private async identifyLpNftPositions(action: Action['action']) { - if (action.case === 'positionOpen' && action.value.position) { - for (const state of POSITION_STATES) { - const metadata = getLpNftMetadata(computePositionId(action.value.position), state); - await this.indexedDb.saveAssetsMetadata(metadata); - } - // to optimize on-chain storage PositionId is not written in the positionOpen action, - // but can be computed via hashing of immutable position fields - await this.indexedDb.addPosition( - computePositionId(action.value.position), - action.value.position, - ); - } - if (action.case === 'positionClose' && action.value.positionId) { - await this.indexedDb.updatePosition( - action.value.positionId, - new PositionState({ state: PositionState_PositionStateEnum.CLOSED }), - ); - } - if (action.case === 'positionWithdraw' && action.value.positionId) { - // Record the LPNFT for the current sequence number. - const positionState = new PositionState({ - state: PositionState_PositionStateEnum.WITHDRAWN, - sequence: action.value.sequence, - }); - const metadata = getLpNftMetadata(action.value.positionId, positionState); - await this.indexedDb.saveAssetsMetadata(metadata); - - await this.indexedDb.updatePosition(action.value.positionId, positionState); - } - } - - private async maybeUpsertAuctionWithNoteCommitment(spendableNoteRecord: SpendableNoteRecord) { - const assetId = spendableNoteRecord.note?.value?.assetId; - if (!assetId) return; - - const metadata = await this.indexedDb.getAssetsMetadata(assetId); - const captureGroups = assetPatterns.auctionNft.capture(metadata?.display ?? ''); - if (!captureGroups) return; - - const auctionId = new AuctionId(auctionIdFromBech32(captureGroups.auctionId)); - - await this.indexedDb.upsertAuction(auctionId, { - noteCommitment: spendableNoteRecord.noteCommitment, - }); - } - - private async saveTransactions(height: bigint, relevantTx: Map) { - for (const [id, transaction] of relevantTx) { - await this.indexedDb.saveTransaction(id, height, transaction); - } - } - - /* - * Compares the locally stored, filtered TCT root with the actual one on chain. They should match. - * This is expensive to do every block, so should only be done in development for debugging purposes. - * Note: In order for this to run, you must do this in the service worker console: - * globalThis.ASSERT_ROOT_VALID = true - */ - private async assertRootValid(blockHeight: bigint): Promise { - const remoteRoot = await this.querier.cnidarium.fetchRemoteRoot(blockHeight); - const inMemoryRoot = this.viewServer.getSctRoot(); - - if (remoteRoot.equals(inMemoryRoot)) { - console.log( - `Block height: ${blockHeight} root matches remote ✅ \n`, - `Hash: ${uint8ArrayToHex(inMemoryRoot.inner)}`, - ); - } else { - console.log( - `Block height: ${blockHeight} root does not match remote ❌ \n`, - `Local hash: ${uint8ArrayToHex(inMemoryRoot.inner)} \n`, - `Remote hash: ${uint8ArrayToHex(remoteRoot.inner)}`, - ); - } - } - - private async handleEpochTransition( - endHeightOfPreviousEpoch: bigint, - latestKnownBlockHeight: bigint, - ): Promise { - const nextEpochStartHeight = endHeightOfPreviousEpoch + 1n; - await this.indexedDb.addEpoch(nextEpochStartHeight); - - const { sctParams } = (await this.indexedDb.getAppParams()) ?? {}; - const nextEpochIsLatestKnownEpoch = - sctParams && latestKnownBlockHeight - nextEpochStartHeight < sctParams.epochDuration; - - // If we're doing a full sync from block 0, there could be hundreds or even - // thousands of epoch transitions in the chain already. If we update - // validator infos on every epoch transition, we'd be making tons of - // unnecessary calls to the RPC node for validator infos. Instead, we'll - // only get updated validator infos once we're within the latest known - // epoch. - if (nextEpochIsLatestKnownEpoch) void this.updateValidatorInfos(nextEpochStartHeight); - } - - private async updateValidatorInfos(nextEpochStartHeight: bigint): Promise { - for await (const validatorInfoResponse of this.querier.stake.allValidatorInfos()) { - if (!validatorInfoResponse.validatorInfo) continue; - - // Await the upsert. This makes it possible for users of this method to - // await the entire method, if they want to block all other code until all - // validator infos have been upserted. - await this.indexedDb.upsertValidatorInfo(validatorInfoResponse.validatorInfo); - - // Don't await this, though -- price equivalents for delegation tokens are - // non-critical, and shouldn't block the rest of the block processor. - void this.updatePriceForValidatorDelegationToken(validatorInfoResponse, nextEpochStartHeight); - } - } - - private async updatePriceForValidatorDelegationToken( - validatorInfoResponse: ValidatorInfoResponse, - nextEpochStartHeight: bigint, - ) { - const identityKey = getIdentityKeyFromValidatorInfoResponse(validatorInfoResponse); - const delegationTokenAssetId = new AssetId({ - altBaseDenom: `udelegation_${bech32mIdentityKey(identityKey)}`, - }); - - const metadata = await this.saveAndReturnMetadata(delegationTokenAssetId); - - if (metadata) { - const assetId = getAssetId(metadata); - const stakingAssetId = getAssetId(this.stakingTokenMetadata); - const exchangeRate = getExchangeRateFromValidatorInfoResponse(validatorInfoResponse); - - await this.indexedDb.updatePrice( - assetId, - stakingAssetId, - toDecimalExchangeRate(exchangeRate), - nextEpochStartHeight, - ); - } - } -} diff --git a/packages/query/src/helpers/process-action-dutch-auction-end.test.ts b/packages/query/src/helpers/process-action-dutch-auction-end.test.ts deleted file mode 100644 index d55a53e5..00000000 --- a/packages/query/src/helpers/process-action-dutch-auction-end.test.ts +++ /dev/null @@ -1,114 +0,0 @@ -import { Mock, beforeEach, describe, expect, it, vi } from 'vitest'; -import { processActionDutchAuctionEnd } from './process-action-dutch-auction-end'; -import { - AssetId, - Metadata, - Value, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; -import { - ActionDutchAuctionEnd, - AuctionId, - DutchAuction, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/auction/v1/auction_pb'; -import { IndexedDbInterface } from '@penumbra-zone/types/indexed-db'; - -vi.mock('@penumbra-zone/wasm/auction', () => ({ - getAuctionNftMetadata: () => new Metadata({ display: 'penumbra' }), -})); - -describe('processActionDutchAuctionEnd()', () => { - let auctionQuerier: { auctionStateById: Mock }; - let indexedDb: { - saveAssetsMetadata: Mock; - upsertAuction: Mock; - addAuctionOutstandingReserves: Mock; - }; - const auctionId = new AuctionId({ inner: new Uint8Array([0, 1, 2, 3]) }); - const action = new ActionDutchAuctionEnd({ auctionId }); - - beforeEach(() => { - auctionQuerier = { - auctionStateById: vi.fn(), - }; - indexedDb = { - saveAssetsMetadata: vi.fn(), - upsertAuction: vi.fn(), - addAuctionOutstandingReserves: vi.fn(), - }; - }); - - it('saves metadata for the ended auction NFT', async () => { - await processActionDutchAuctionEnd( - action, - auctionQuerier, - indexedDb as unknown as IndexedDbInterface, - ); - - expect(indexedDb.saveAssetsMetadata).toHaveBeenCalledWith( - expect.objectContaining({ display: 'penumbra' }), - ); - }); - - it('upserts the auction with the sequence number', async () => { - const inputAssetId = new AssetId({ inner: new Uint8Array([0, 1, 2, 3]) }); - const outputAssetId = new AssetId({ inner: new Uint8Array([4, 5, 6, 7]) }); - - auctionQuerier.auctionStateById.mockResolvedValueOnce( - new DutchAuction({ - state: { - inputReserves: { hi: 0n, lo: 1234n }, - outputReserves: { hi: 0n, lo: 5678n }, - }, - description: { - input: { - amount: { hi: 0n, lo: 6912n }, - assetId: inputAssetId, - }, - outputId: outputAssetId, - }, - }), - ); - - await processActionDutchAuctionEnd( - action, - auctionQuerier, - indexedDb as unknown as IndexedDbInterface, - ); - - expect(indexedDb.upsertAuction).toHaveBeenCalledWith(auctionId, { - seqNum: 1n, - }); - }); - - it('adds the auction reserves', async () => { - const inputAssetId = new AssetId({ inner: new Uint8Array([0, 1, 2, 3]) }); - const outputAssetId = new AssetId({ inner: new Uint8Array([4, 5, 6, 7]) }); - - auctionQuerier.auctionStateById.mockResolvedValueOnce( - new DutchAuction({ - state: { - inputReserves: { hi: 0n, lo: 1234n }, - outputReserves: { hi: 0n, lo: 5678n }, - }, - description: { - input: { - amount: { hi: 0n, lo: 6912n }, - assetId: inputAssetId, - }, - outputId: outputAssetId, - }, - }), - ); - - await processActionDutchAuctionEnd( - action, - auctionQuerier, - indexedDb as unknown as IndexedDbInterface, - ); - - expect(indexedDb.addAuctionOutstandingReserves).toHaveBeenCalledWith(auctionId, { - input: new Value({ amount: { hi: 0n, lo: 1234n }, assetId: inputAssetId }), - output: new Value({ amount: { hi: 0n, lo: 5678n }, assetId: outputAssetId }), - }); - }); -}); diff --git a/packages/query/src/helpers/process-action-dutch-auction-end.ts b/packages/query/src/helpers/process-action-dutch-auction-end.ts deleted file mode 100644 index f02aadf8..00000000 --- a/packages/query/src/helpers/process-action-dutch-auction-end.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { Value } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; -import { - ActionDutchAuctionEnd, - DutchAuction, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/auction/v1/auction_pb'; -import { IndexedDbInterface } from '@penumbra-zone/types/indexed-db'; -import { AuctionQuerierInterface } from '@penumbra-zone/types/querier'; -import { getAuctionNftMetadata } from '@penumbra-zone/wasm/auction'; - -const getInputValue = (auction?: DutchAuction) => - new Value({ - amount: auction?.state?.inputReserves, - assetId: auction?.description?.input?.assetId, - }); - -const getOutputValue = (auction?: DutchAuction) => - new Value({ - amount: auction?.state?.outputReserves, - assetId: auction?.description?.outputId, - }); - -export const processActionDutchAuctionEnd = async ( - action: ActionDutchAuctionEnd, - auctionQuerier: AuctionQuerierInterface, - indexedDb: IndexedDbInterface, -) => { - if (!action.auctionId) return; - - // Always a sequence number of 1 when ending a Dutch auction - const seqNum = 1n; - - const metadata = getAuctionNftMetadata(action.auctionId, seqNum); - const auction = await auctionQuerier.auctionStateById(action.auctionId); - - const outstandingReserves = { - input: getInputValue(auction), - output: getOutputValue(auction), - }; - - await Promise.all([ - indexedDb.saveAssetsMetadata(metadata), - indexedDb.upsertAuction(action.auctionId, { seqNum }), - indexedDb.addAuctionOutstandingReserves(action.auctionId, outstandingReserves), - ]); -}; diff --git a/packages/query/src/helpers/process-action-dutch-auction-schedule.ts b/packages/query/src/helpers/process-action-dutch-auction-schedule.ts deleted file mode 100644 index 382c60ff..00000000 --- a/packages/query/src/helpers/process-action-dutch-auction-schedule.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { DutchAuctionDescription } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/auction/v1/auction_pb'; -import { IndexedDbInterface } from '@penumbra-zone/types/indexed-db'; -import { getAuctionId, getAuctionNftMetadata } from '@penumbra-zone/wasm/auction'; - -export const processActionDutchAuctionSchedule = async ( - description: DutchAuctionDescription, - indexedDb: IndexedDbInterface, -) => { - const auctionId = getAuctionId(description); - - // Always a sequence number of 0 when starting a Dutch auction - const seqNum = 0n; - - const metadata = getAuctionNftMetadata(auctionId, seqNum); - - await Promise.all([ - indexedDb.saveAssetsMetadata(metadata), - indexedDb.upsertAuction(auctionId, { - auction: description, - seqNum, - }), - ]); -}; diff --git a/packages/query/src/helpers/process-action-dutch-auction-withdraw.ts b/packages/query/src/helpers/process-action-dutch-auction-withdraw.ts deleted file mode 100644 index 520c42a9..00000000 --- a/packages/query/src/helpers/process-action-dutch-auction-withdraw.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { AuctionId } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/auction/v1/auction_pb'; -import { IndexedDbInterface } from '@penumbra-zone/types/indexed-db'; -import { getAuctionNftMetadata } from '@penumbra-zone/wasm/auction'; - -export const processActionDutchAuctionWithdraw = async ( - auctionId: AuctionId, - seqNum: bigint, - indexedDb: IndexedDbInterface, -) => { - const metadata = getAuctionNftMetadata(auctionId, seqNum); - - await Promise.all([ - indexedDb.saveAssetsMetadata(metadata), - indexedDb.upsertAuction(auctionId, { - seqNum, - }), - indexedDb.deleteAuctionOutstandingReserves(auctionId), - ]); -}; diff --git a/packages/query/src/price-indexer.test.ts b/packages/query/src/price-indexer.test.ts deleted file mode 100644 index afd77cf9..00000000 --- a/packages/query/src/price-indexer.test.ts +++ /dev/null @@ -1,115 +0,0 @@ -import { deriveAndSavePriceFromBSOD } from './price-indexer'; -import { BatchSwapOutputData } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/dex/v1/dex_pb'; -import { beforeEach, describe, expect, it, Mock, vi } from 'vitest'; -import { IndexedDbInterface } from '@penumbra-zone/types/indexed-db'; -import { AssetId } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; -import { base64ToUint8Array } from '@penumbra-zone/types/base64'; - -describe('updatePricesFromSwaps()', () => { - let indexedDbMock: IndexedDbInterface; - const updatePriceMock: Mock = vi.fn(); - const height = 123n; - const numeraireAssetId = new AssetId({ - inner: base64ToUint8Array('reum7wQmk/owgvGMWMZn/6RFPV24zIKq3W6In/WwZgg='), - }); - - beforeEach(() => { - vi.clearAllMocks(); - - indexedDbMock = { - updatePrice: updatePriceMock, - } as unknown as IndexedDbInterface; - }); - - it('should update prices correctly for a swapOutput with NUMERAIRE as swapAsset2', async () => { - const asset1 = new AssetId({ inner: new Uint8Array(12) }); - const swapOutputs: BatchSwapOutputData[] = [ - new BatchSwapOutputData({ - tradingPair: { - asset1: asset1, - asset2: numeraireAssetId, - }, - delta1: { lo: 250n }, - lambda2: { lo: 1200n }, - unfilled1: { lo: 0n }, - }), - ]; - - await deriveAndSavePriceFromBSOD(indexedDbMock, numeraireAssetId, swapOutputs, height); - expect(updatePriceMock).toBeCalledTimes(1); - expect(updatePriceMock).toBeCalledWith(asset1, numeraireAssetId, 4.8, height); - }); - - it('should update prices correctly for a swapOutput with NUMERAIRE as swapAsset1', async () => { - const asset1 = new AssetId({ inner: new Uint8Array(12) }); - const swapOutputs: BatchSwapOutputData[] = [ - new BatchSwapOutputData({ - tradingPair: { - asset1: numeraireAssetId, - asset2: asset1, - }, - delta2: { lo: 40n }, - lambda1: { lo: 12740n }, - unfilled2: { lo: 0n }, - }), - ]; - - await deriveAndSavePriceFromBSOD(indexedDbMock, numeraireAssetId, swapOutputs, height); - expect(updatePriceMock).toBeCalledTimes(1); - expect(updatePriceMock).toBeCalledWith(asset1, numeraireAssetId, 318.5, height); - }); - - it('should not update prices if delta is zero', async () => { - const asset1 = new AssetId({ inner: new Uint8Array(12) }); - const swapOutputs: BatchSwapOutputData[] = [ - new BatchSwapOutputData({ - tradingPair: { - asset1: numeraireAssetId, - asset2: asset1, - }, - delta2: { lo: 0n }, - lambda1: { lo: 12740n }, - unfilled2: { lo: 0n }, - }), - ]; - - await deriveAndSavePriceFromBSOD(indexedDbMock, numeraireAssetId, swapOutputs, height); - expect(updatePriceMock).toBeCalledTimes(0); - }); - - it('should update prices correctly for partially filled', async () => { - const asset1 = new AssetId({ inner: new Uint8Array(12) }); - const swapOutputs: BatchSwapOutputData[] = [ - new BatchSwapOutputData({ - tradingPair: { - asset1: asset1, - asset2: numeraireAssetId, - }, - delta1: { lo: 250n }, - lambda2: { lo: 1200n }, - unfilled1: { lo: 100n }, - }), - ]; - await deriveAndSavePriceFromBSOD(indexedDbMock, numeraireAssetId, swapOutputs, height); - expect(updatePriceMock).toBeCalledTimes(1); - expect(updatePriceMock).toBeCalledWith(asset1, numeraireAssetId, 8, height); - }); - - it('should not update prices if swap is fully unfilled', async () => { - const asset1 = new AssetId({ inner: new Uint8Array(12) }); - const swapOutputs: BatchSwapOutputData[] = [ - new BatchSwapOutputData({ - tradingPair: { - asset1: numeraireAssetId, - asset2: asset1, - }, - delta2: { lo: 100n }, - lambda1: { lo: 12740n }, - unfilled2: { lo: 100n }, - }), - ]; - - await deriveAndSavePriceFromBSOD(indexedDbMock, numeraireAssetId, swapOutputs, height); - expect(updatePriceMock).toBeCalledTimes(0); - }); -}); diff --git a/packages/query/src/price-indexer.ts b/packages/query/src/price-indexer.ts deleted file mode 100644 index 0ce4f4d6..00000000 --- a/packages/query/src/price-indexer.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { BatchSwapOutputData } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/dex/v1/dex_pb'; -import { IndexedDbInterface } from '@penumbra-zone/types/indexed-db'; -import { divideAmounts, isZero, subtractAmounts } from '@penumbra-zone/types/amount'; -import { AssetId } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; -import { Amount } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/num/v1/num_pb'; -import { - getDelta1Amount, - getDelta2Amount, - getLambda1Amount, - getLambda2Amount, - getSwapAsset1, - getSwapAsset2, - getUnfilled1Amount, - getUnfilled2Amount, -} from '@penumbra-zone/getters/batch-swap-output-data'; - -/** - * - * @param delta - total amount of 'pricedAsset' that was input to the batch swap - * @param unfilled - total amount of 'pricedAsset' that was returned unfilled - * @param lambda - total amount of 'numeraire' that was output from the batch swap - * Price formula: - * price = (lambda)/(delta - unfilled) - * The price cannot be calculated if - * - lambda is zero - * - delta is zero - * - (delta - unfilled) is zero - * @return 0 if the price cannot be calculated and some positive number if the price has been calculated. - */ -export const calculatePrice = (delta: Amount, unfilled: Amount, lambda: Amount): number => { - const filledAmount = subtractAmounts(delta, unfilled); - - return isZero(delta) || isZero(lambda) || isZero(filledAmount) - ? 0 - : divideAmounts(lambda, filledAmount).toNumber(); -}; - -export const updatePricesFromSwaps = async ( - indexedDb: IndexedDbInterface, - numeraires: AssetId[], - swapOutputs: BatchSwapOutputData[], - height: bigint, -) => { - for (const numeraireAssetId of numeraires) { - await deriveAndSavePriceFromBSOD(indexedDb, numeraireAssetId, swapOutputs, height); - } -}; - -/** - * Each 'BatchSwapOutputData' (BSOD) can generate up to two prices - * Each BSOD in block has a unique trading pair - * Trading pair has a canonical ordering, there's only one trading pair per pair of assets - * Each BSOD can generate up to two prices - * 1. pricedAsset -> numeraire (selling price) - * 2. numeraire -> pricedAsset (buying price) - * This function processes only (1) price and ignores (2) price - * We can get a BSOD with zero deltas(inputs), and we shouldn't save the price in that case - */ -export const deriveAndSavePriceFromBSOD = async ( - indexedDb: IndexedDbInterface, - numeraireAssetId: AssetId, - swapOutputs: BatchSwapOutputData[], - height: bigint, -) => { - for (const swapOutput of swapOutputs) { - const swapAsset1 = getSwapAsset1(swapOutput); - const swapAsset2 = getSwapAsset2(swapOutput); - - let numerairePerUnit = 0; - let pricedAsset: AssetId | undefined = undefined; - - // case for trading pair - if (swapAsset2.equals(numeraireAssetId)) { - pricedAsset = swapAsset1; - // numerairePerUnit = lambda2/(delta1-unfilled1) - numerairePerUnit = calculatePrice( - getDelta1Amount(swapOutput), - getUnfilled1Amount(swapOutput), - getLambda2Amount(swapOutput), - ); - } - // case for trading pair - else if (swapAsset1.equals(numeraireAssetId)) { - pricedAsset = swapAsset2; - // numerairePerUnit = lambda1/(delta2-unfilled2) - numerairePerUnit = calculatePrice( - getDelta2Amount(swapOutput), - getUnfilled2Amount(swapOutput), - getLambda1Amount(swapOutput), - ); - } - - if (pricedAsset === undefined || numerairePerUnit === 0) continue; - - await indexedDb.updatePrice(pricedAsset, numeraireAssetId, numerairePerUnit, height); - } -}; diff --git a/packages/query/src/queriers/app.ts b/packages/query/src/queriers/app.ts deleted file mode 100644 index e9103346..00000000 --- a/packages/query/src/queriers/app.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { PromiseClient } from '@connectrpc/connect'; -import { createClient } from './utils'; -import { AppParameters } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/app/v1/app_pb'; -import { Transaction } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/transaction/v1/transaction_pb'; -import { AppService } from '@penumbra-zone/protobuf'; -import type { AppQuerierInterface } from '@penumbra-zone/types/querier'; - -export class AppQuerier implements AppQuerierInterface { - private readonly client: PromiseClient; - - constructor({ grpcEndpoint }: { grpcEndpoint: string }) { - this.client = createClient(grpcEndpoint, AppService); - } - - async appParams(): Promise { - const { appParameters } = await this.client.appParameters({}); - if (!appParameters) throw new Error('no app parameters in response'); - return appParameters; - } - - async txsByHeight(blockHeight: bigint): Promise { - const { blockHeight: responseHeight, transactions } = await this.client.transactionsByHeight({ - blockHeight, - }); - if (responseHeight !== blockHeight) - throw new Error( - `block height mismatch: requested ${blockHeight}, received ${responseHeight}`, - ); - return transactions; - } -} diff --git a/packages/query/src/queriers/auction.ts b/packages/query/src/queriers/auction.ts deleted file mode 100644 index 2caa0b9b..00000000 --- a/packages/query/src/queriers/auction.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { AuctionQuerierInterface } from '@penumbra-zone/types/querier'; -import { AuctionService } from '@penumbra-zone/protobuf'; -import { PromiseClient } from '@connectrpc/connect'; -import { createClient } from './utils'; -import { - AuctionId, - DutchAuction, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/auction/v1/auction_pb'; -import { typeUrlMatchesTypeName } from '@penumbra-zone/types/protobuf'; - -export class AuctionQuerier implements AuctionQuerierInterface { - private readonly client: PromiseClient; - - constructor({ grpcEndpoint }: { grpcEndpoint: string }) { - this.client = createClient(grpcEndpoint, AuctionService); - } - - async auctionStateById(id: AuctionId): Promise< - // Add more auction types to this union type as they are created. - DutchAuction | undefined - > { - const result = await this.client.auctionStateById({ id }); - - // As more auction types are created, handle them here. - if (typeUrlMatchesTypeName(result.auction?.typeUrl, DutchAuction.typeName)) { - return DutchAuction.fromBinary(result.auction.value); - } - - return undefined; - } -} diff --git a/packages/query/src/queriers/cnidarium.ts b/packages/query/src/queriers/cnidarium.ts deleted file mode 100644 index d45eebfb..00000000 --- a/packages/query/src/queriers/cnidarium.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { PromiseClient } from '@connectrpc/connect'; -import { createClient } from './utils'; -import { CnidariumService } from '@penumbra-zone/protobuf'; -import { KeyValueRequest } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/cnidarium/v1/cnidarium_pb'; -import { CnidariumQuerierInterface } from '@penumbra-zone/types/querier'; -import { MerkleRoot } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/crypto/tct/v1/tct_pb'; - -export class CnidariumQuerier implements CnidariumQuerierInterface { - private readonly client: PromiseClient; - - constructor({ grpcEndpoint }: { grpcEndpoint: string }) { - this.client = createClient(grpcEndpoint, CnidariumService); - } - - async fetchRemoteRoot(blockHeight: bigint): Promise { - const keyValueRequest = new KeyValueRequest({ - key: `sct/tree/anchor_by_height/${blockHeight}`, - }); - const keyValue = await this.client.keyValue(keyValueRequest); - if (!keyValue.value) throw new Error('no value in KeyValueResponse'); - - return MerkleRoot.fromBinary(keyValue.value.value); - } -} diff --git a/packages/query/src/queriers/compact-block.ts b/packages/query/src/queriers/compact-block.ts deleted file mode 100644 index 8ba92f0c..00000000 --- a/packages/query/src/queriers/compact-block.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { PromiseClient } from '@connectrpc/connect'; -import { - CompactBlock, - CompactBlockRangeRequest, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/compact_block/v1/compact_block_pb'; -import { CompactBlockService } from '@penumbra-zone/protobuf'; -import { createClient } from './utils'; -import type { - CompactBlockQuerierInterface, - CompactBlockRangeParams, -} from '@penumbra-zone/types/querier'; - -export class CompactBlockQuerier implements CompactBlockQuerierInterface { - private readonly client: PromiseClient; - - constructor({ grpcEndpoint }: { grpcEndpoint: string }) { - this.client = createClient(grpcEndpoint, CompactBlockService); - } - - async *compactBlockRange({ - startHeight, - keepAlive, - abortSignal, - }: CompactBlockRangeParams): AsyncIterable { - const req = new CompactBlockRangeRequest({ keepAlive, startHeight }); - const iterable = this.client.compactBlockRange(req, { signal: abortSignal }); - for await (const res of iterable) { - if (!res.compactBlock) throw new Error('No block in response'); - yield res.compactBlock; - } - } -} diff --git a/packages/query/src/queriers/ibc-client.ts b/packages/query/src/queriers/ibc-client.ts deleted file mode 100644 index 7e94c852..00000000 --- a/packages/query/src/queriers/ibc-client.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { PromiseClient } from '@connectrpc/connect'; -import { createClient } from './utils'; -import { IbcClientService } from '@penumbra-zone/protobuf'; -import { - QueryClientStatesRequest, - QueryClientStatesResponse, -} from '@buf/cosmos_ibc.bufbuild_es/ibc/core/client/v1/query_pb'; -import type { IbcClientQuerierInterface } from '@penumbra-zone/types/querier'; - -export class IbcClientQuerier implements IbcClientQuerierInterface { - private readonly client: PromiseClient; - - constructor({ grpcEndpoint }: { grpcEndpoint: string }) { - this.client = createClient(grpcEndpoint, IbcClientService); - } - - async ibcClientStates(req: QueryClientStatesRequest): Promise { - return await this.client.clientStates(req); - } -} diff --git a/packages/query/src/queriers/shielded-pool.ts b/packages/query/src/queriers/shielded-pool.ts deleted file mode 100644 index 2b513eff..00000000 --- a/packages/query/src/queriers/shielded-pool.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { PromiseClient } from '@connectrpc/connect'; -import { createClient } from './utils'; -import { ShieldedPoolService } from '@penumbra-zone/protobuf'; -import { - AssetId, - Metadata, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; -import type { ShieldedPoolQuerierInterface } from '@penumbra-zone/types/querier'; - -export class ShieldedPoolQuerier implements ShieldedPoolQuerierInterface { - private readonly client: PromiseClient; - - constructor({ grpcEndpoint }: { grpcEndpoint: string }) { - this.client = createClient(grpcEndpoint, ShieldedPoolService); - } - - async assetMetadataById(assetId: AssetId): Promise { - try { - const { denomMetadata } = await this.client.assetMetadataById({ assetId }); - return denomMetadata; - } catch (e) { - if (process.env['NODE_ENV'] === 'development') console.debug(e); - return undefined; - } - } -} diff --git a/packages/query/src/queriers/staking.ts b/packages/query/src/queriers/staking.ts deleted file mode 100644 index bb97bd00..00000000 --- a/packages/query/src/queriers/staking.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { PromiseClient } from '@connectrpc/connect'; -import { createClient } from './utils'; -import { StakeService } from '@penumbra-zone/protobuf'; -import { - ValidatorInfoResponse, - ValidatorPenaltyRequest, - ValidatorPenaltyResponse, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/stake/v1/stake_pb'; -import { StakeQuerierInterface } from '@penumbra-zone/types/querier'; - -export class StakeQuerier implements StakeQuerierInterface { - private readonly client: PromiseClient; - - constructor({ grpcEndpoint }: { grpcEndpoint: string }) { - this.client = createClient(grpcEndpoint, StakeService); - } - - allValidatorInfos(): AsyncIterable { - /** - * Include inactive validators when saving to our local database, since we - * serve the `ValidatorInfo` RPC method from the extension, and may receive - * requests for inactive validators. - */ - return this.client.validatorInfo({ showInactive: true }); - } - - validatorPenalty(req: ValidatorPenaltyRequest): Promise { - return this.client.validatorPenalty(req); - } -} diff --git a/packages/query/src/queriers/tendermint.ts b/packages/query/src/queriers/tendermint.ts deleted file mode 100644 index 28658c39..00000000 --- a/packages/query/src/queriers/tendermint.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { PromiseClient } from '@connectrpc/connect'; -import { createClient } from './utils'; -import { TendermintProxyService } from '@penumbra-zone/protobuf'; -import { TransactionId } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/txhash/v1/txhash_pb'; -import { Transaction } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/transaction/v1/transaction_pb'; -import type { TendermintQuerierInterface } from '@penumbra-zone/types/querier'; - -export class TendermintQuerier implements TendermintQuerierInterface { - private readonly client: PromiseClient; - - constructor({ grpcEndpoint }: { grpcEndpoint: string }) { - this.client = createClient(grpcEndpoint, TendermintProxyService); - } - - async latestBlockHeight() { - try { - const { syncInfo } = await this.client.getStatus({}); - return syncInfo?.latestBlockHeight; - } catch (e) { - if (process.env['NODE_ENV'] === 'development') console.debug(e); - return undefined; - } - } - - async broadcastTx(tx: Transaction) { - const params = tx.toBinary(); - // Note that "synchronous" here means "wait for the tx to be accepted by - // the fullnode", not "wait for the tx to be included on chain. - const { hash, log, code } = await this.client.broadcastTxSync({ params }); - - if (code !== 0n) { - throw new Error(`Tendermint error ${code.toString()}: ${log}`); - } - - return new TransactionId({ inner: hash }); - } - - async getTransaction(txId: TransactionId): Promise<{ height: bigint; transaction: Transaction }> { - const res = await this.client.getTx({ hash: txId.inner }); - const transaction = Transaction.fromBinary(res.tx); - return { height: res.height, transaction }; - } -} diff --git a/packages/query/src/queriers/utils.ts b/packages/query/src/queriers/utils.ts deleted file mode 100644 index 20d4a7ef..00000000 --- a/packages/query/src/queriers/utils.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { createPromiseClient, PromiseClient } from '@connectrpc/connect'; -import { createGrpcWebTransport } from '@connectrpc/connect-web'; -import { ServiceType } from '@bufbuild/protobuf'; - -export const createClient = ( - grpcEndpoint: string, - serviceType: T, -): PromiseClient => { - const transport = createGrpcWebTransport({ - baseUrl: grpcEndpoint, - }); - return createPromiseClient(serviceType, transport); -}; diff --git a/packages/query/src/root-querier.ts b/packages/query/src/root-querier.ts deleted file mode 100644 index 11ce23b2..00000000 --- a/packages/query/src/root-querier.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { CompactBlockQuerier } from './queriers/compact-block'; -import { AppQuerier } from './queriers/app'; -import { TendermintQuerier } from './queriers/tendermint'; -import { ShieldedPoolQuerier } from './queriers/shielded-pool'; -import { IbcClientQuerier } from './queriers/ibc-client'; -import { CnidariumQuerier } from './queriers/cnidarium'; -import { StakeQuerier } from './queriers/staking'; -import type { RootQuerierInterface } from '@penumbra-zone/types/querier'; -import { AuctionQuerier } from './queriers/auction'; - -// Given the amount of query services, this root querier aggregates them all -// to make it easier for consumers -export class RootQuerier implements RootQuerierInterface { - readonly app: AppQuerier; - readonly compactBlock: CompactBlockQuerier; - readonly tendermint: TendermintQuerier; - readonly shieldedPool: ShieldedPoolQuerier; - readonly ibcClient: IbcClientQuerier; - readonly stake: StakeQuerier; - readonly cnidarium: CnidariumQuerier; - readonly auction: AuctionQuerier; - - constructor({ grpcEndpoint }: { grpcEndpoint: string }) { - this.app = new AppQuerier({ grpcEndpoint }); - this.compactBlock = new CompactBlockQuerier({ grpcEndpoint }); - this.tendermint = new TendermintQuerier({ grpcEndpoint }); - this.shieldedPool = new ShieldedPoolQuerier({ grpcEndpoint }); - this.ibcClient = new IbcClientQuerier({ grpcEndpoint }); - this.stake = new StakeQuerier({ grpcEndpoint }); - this.cnidarium = new CnidariumQuerier({ grpcEndpoint }); - this.auction = new AuctionQuerier({ grpcEndpoint }); - } -} diff --git a/packages/services-context/eslint.config.mjs b/packages/services-context/eslint.config.mjs deleted file mode 100644 index a53ed8e5..00000000 --- a/packages/services-context/eslint.config.mjs +++ /dev/null @@ -1,13 +0,0 @@ -import { penumbraEslintConfig } from '@penumbra-zone/eslint-config'; -import { config, parser } from 'typescript-eslint'; - -export default config({ - ...penumbraEslintConfig, - languageOptions: { - parser, - parserOptions: { - project: true, - tsconfigRootDir: import.meta.dirname, - }, - }, -}); diff --git a/packages/services-context/package.json b/packages/services-context/package.json deleted file mode 100644 index b66254b1..00000000 --- a/packages/services-context/package.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "name": "@penumbra-zone/services-context", - "version": "3.3.0", - "private": true, - "license": "(MIT OR Apache-2.0)", - "type": "module", - "scripts": { - "lint": "eslint \"**/*.ts*\"" - }, - "files": [ - "src/", - "*.md" - ], - "exports": { - ".": "./src/index.ts" - }, - "dependencies": { - "@penumbra-labs/registry": "8.0.1", - "@penumbra-zone/query": "workspace:*", - "@penumbra-zone/storage": "workspace:*", - "@penumbra-zone/types": "workspace:*", - "@penumbra-zone/wasm": "workspace:*", - "exponential-backoff": "^3.1.1" - }, - "devDependencies": { - "@buf/penumbra-zone_penumbra.bufbuild_es": "1.9.0-20240528180215-8fe1c79485f8.1", - "@bufbuild/protobuf": "^1.10.0" - }, - "peerDependencies": { - "@buf/penumbra-zone_penumbra.bufbuild_es": "1.9.0-20240528180215-8fe1c79485f8.1", - "@bufbuild/protobuf": "^1.10.0" - } -} diff --git a/packages/services-context/tsconfig.json b/packages/services-context/tsconfig.json deleted file mode 100644 index 61a00fa2..00000000 --- a/packages/services-context/tsconfig.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "extends": "tsconfig/base.json", - "include": ["."], - "exclude": ["node_modules"] -} diff --git a/packages/services/CHANGELOG.md b/packages/services/CHANGELOG.md deleted file mode 100644 index 2dbb79e8..00000000 --- a/packages/services/CHANGELOG.md +++ /dev/null @@ -1,294 +0,0 @@ -# @penumbra-zone/router - -## 4.1.0 - -### Minor Changes - -- ab9d743: decouple service/rpc init - -### Patch Changes - -- Updated dependencies [4012c48] -- Updated dependencies [adf3a28] -- Updated dependencies [ab9d743] -- Updated dependencies [282eabf] -- Updated dependencies [81b9536] -- Updated dependencies [14ba562] -- Updated dependencies [6b06e04] -- Updated dependencies [c8e8d15] -- Updated dependencies [6ee8222] -- Updated dependencies [e7d7ffc] - - @penumbra-zone/storage@4.0.0 - - @penumbra-zone/services-context@3.3.0 - - @penumbra-zone/query@4.1.0 - - @penumbra-zone/types@7.1.0 - - @penumbra-zone/protobuf@4.1.0 - - @penumbra-zone/wasm@7.1.0 - - @penumbra-zone/getters@6.1.0 - - @penumbra-zone/crypto-web@3.0.10 - - @penumbra-zone/perspective@4.0.1 - -## 4.0.3 - -### Patch Changes - -- Updated dependencies [8fe4de6] - - @penumbra-zone/transport-dom@6.0.0 - - @penumbra-zone/perspective@4.0.0 - - @penumbra-zone/protobuf@4.0.0 - - @penumbra-zone/bech32m@5.0.0 - - @penumbra-zone/getters@6.0.0 - - @penumbra-zone/wasm@7.0.0 - - @penumbra-zone/query@4.0.2 - - @penumbra-zone/storage@3.4.3 - - @penumbra-zone/types@7.0.1 - - @penumbra-zone/services-context@3.2.3 - - @penumbra-zone/crypto-web@3.0.9 - -## 4.0.2 - -### Patch Changes - -- Updated dependencies [bb5f621] -- Updated dependencies [8b121ec] - - @penumbra-zone/types@7.0.0 - - @penumbra-zone/transport-dom@5.0.0 - - @penumbra-zone/perspective@3.0.0 - - @penumbra-zone/protobuf@3.0.0 - - @penumbra-zone/bech32m@4.0.0 - - @penumbra-zone/getters@5.0.0 - - @penumbra-zone/wasm@6.0.0 - - @penumbra-zone/crypto-web@3.0.8 - - @penumbra-zone/query@4.0.1 - - @penumbra-zone/services-context@3.2.2 - - @penumbra-zone/storage@3.4.2 - -## 4.0.1 - -### Patch Changes - -- Updated dependencies [a22d3a8] - - @penumbra-zone/services-context@3.2.1 - - @penumbra-zone/storage@3.4.1 - -## 4.0.0 - -### Major Changes - -- 029eebb: use service definitions from protobuf collection package - -### Minor Changes - -- 3ea1e6c: update buf types dependencies - -### Patch Changes - -- Updated dependencies [120b654] -- Updated dependencies [4f8c150] -- Updated dependencies [029eebb] -- Updated dependencies [029eebb] -- Updated dependencies [e86448e] -- Updated dependencies [3ea1e6c] - - @penumbra-zone/getters@4.1.0 - - @penumbra-zone/protobuf@2.1.0 - - @penumbra-zone/query@4.0.0 - - @penumbra-zone/types@6.0.0 - - @penumbra-zone/wasm@5.1.0 - - @penumbra-zone/services-context@3.2.0 - - @penumbra-zone/transport-dom@4.1.0 - - @penumbra-zone/perspective@2.1.0 - - @penumbra-zone/bech32m@3.2.0 - - @penumbra-zone/storage@3.4.0 - - @penumbra-zone/crypto-web@3.0.7 - -## 3.2.1 - -### Patch Changes - -- @penumbra-zone/wasm@5.0.1 -- @penumbra-zone/perspective@2.0.1 -- @penumbra-zone/query@3.2.1 -- @penumbra-zone/services-context@3.1.1 -- @penumbra-zone/storage@3.3.0 - -## 3.2.0 - -### Minor Changes - -- e4c9fce: Add features to handle auction withdrawals - -### Patch Changes - -- e35c6f7: Deps bumped to latest -- Updated dependencies [e47a04e] -- Updated dependencies [146b48d] -- Updated dependencies [65677c1] -- Updated dependencies [8ccaf30] -- Updated dependencies [8ccaf30] -- Updated dependencies [e35c6f7] -- Updated dependencies [cf63b30] -- Updated dependencies [99feb9d] -- Updated dependencies [e4c9fce] -- Updated dependencies [d6b8a23] -- Updated dependencies [8ccaf30] - - @penumbra-zone/services-context@3.1.0 - - @penumbra-zone/storage@3.3.0 - - @penumbra-zone/getters@4.0.0 - - @penumbra-zone/types@5.0.0 - - @penumbra-zone/wasm@5.0.0 - - @penumbra-zone/perspective@2.0.0 - - @penumbra-zone/bech32m@3.1.1 - - @penumbra-zone/query@3.2.0 - - @penumbra-zone/crypto-web@3.0.6 - -## 3.1.0 - -### Minor Changes - -- v8.0.0 versioning and manifest - -### Patch Changes - -- Updated dependencies -- Updated dependencies [610a445] - - @penumbra-zone/bech32m@3.1.0 - - @penumbra-zone/query@3.1.0 - - @penumbra-zone/storage@3.2.0 - - @penumbra-zone/types@4.1.0 - - @penumbra-zone/wasm@4.0.4 - - @penumbra-zone/services-context@3.0.4 - - @penumbra-zone/getters@3.0.2 - - @penumbra-zone/perspective@1.0.6 - - @penumbra-zone/crypto-web@3.0.5 - -## 3.0.3 - -### Patch Changes - -- Updated dependencies [8410d2f] - - @penumbra-zone/bech32m@3.0.1 - - @penumbra-zone/getters@3.0.1 - - @penumbra-zone/perspective@1.0.5 - - @penumbra-zone/query@3.0.2 - - @penumbra-zone/storage@3.1.2 - - @penumbra-zone/types@4.0.1 - - @penumbra-zone/wasm@4.0.3 - - @penumbra-zone/services-context@3.0.3 - - @penumbra-zone/crypto-web@3.0.4 - -## 3.0.2 - -### Patch Changes - -- Updated dependencies [423e1d2] -- Updated dependencies [fc500af] -- Updated dependencies [6fb898a] - - @penumbra-zone/polyfills@4.0.0 - - @penumbra-zone/transport-dom@4.0.0 - - @penumbra-zone/types@4.0.0 - - @penumbra-zone/storage@3.1.1 - - @penumbra-zone/crypto-web@3.0.3 - - @penumbra-zone/perspective@1.0.4 - - @penumbra-zone/query@3.0.1 - - @penumbra-zone/services-context@3.0.2 - - @penumbra-zone/wasm@4.0.2 - -## 3.0.1 - -### Patch Changes - -- Updated dependencies [3148375] -- Updated dependencies [55f31c9] -- Updated dependencies [55f31c9] -- Updated dependencies [fdd4303] - - @penumbra-zone/transport-dom@3.0.0 - - @penumbra-zone/constants@4.0.0 - - @penumbra-zone/polyfills@3.0.0 - - @penumbra-zone/getters@3.0.0 - - @penumbra-zone/query@3.0.0 - - @penumbra-zone/types@3.0.0 - - @penumbra-zone/storage@3.1.0 - - @penumbra-zone/bech32m@3.0.0 - - @penumbra-zone/services-context@3.0.1 - - @penumbra-zone/crypto-web@3.0.2 - - @penumbra-zone/perspective@1.0.3 - - @penumbra-zone/wasm@4.0.1 - -## 3.0.0 - -### Major Changes - -- 9f4c112: Drop /src/ requirement for imports and renaming - -### Patch Changes - -- Updated dependencies [78ab976] -- Updated dependencies [862283c] -- Updated dependencies [9f4c112] - - @penumbra-zone/wasm@4.0.0 - - @penumbra-zone/constants@3.0.0 - - @penumbra-zone/services-context@3.0.0 - - @penumbra-zone/perspective@1.0.2 - - @penumbra-zone/query@2.0.3 - - @penumbra-zone/getters@2.0.1 - - @penumbra-zone/storage@3.0.1 - - @penumbra-zone/types@2.0.1 - - @penumbra-zone/crypto-web@3.0.1 - -## 2.0.2 - -### Patch Changes - -- Updated dependencies [76302da] - - @penumbra-zone/storage@3.0.0 - - @penumbra-zone/query@2.0.2 - -## 2.0.1 - -### Patch Changes - -- Updated dependencies [66c2407] - - @penumbra-zone/wasm@3.0.0 - - @penumbra-zone/storage@2.0.1 - - @penumbra-zone/perspective@1.0.1 - - @penumbra-zone/query@2.0.1 - - @penumbra-zone/services@2.0.1 - -## 2.0.0 - -### Major Changes - -- 929d278: barrel imports to facilitate better tree shaking - -### Patch Changes - -- Updated dependencies [8933117] -- Updated dependencies [929d278] - - @penumbra-zone/wasm@2.0.0 - - @penumbra-zone/constants@2.0.0 - - @penumbra-zone/storage@2.0.0 - - @penumbra-zone/query@2.0.0 - - @penumbra-zone/perspective@1.0.0 - - @penumbra-zone/services@2.0.0 - - @penumbra-zone/getters@2.0.0 - - @penumbra-zone/bech32@2.0.0 - - @penumbra-zone/crypto-web@2.0.0 - - @penumbra-zone/types@2.0.0 - - @penumbra-zone/polyfills@2.0.0 - - @penumbra-zone/transport-dom@2.0.0 - -## 1.0.2 - -### Patch Changes - -- Updated dependencies - - @penumbra-zone/constants@1.1.0 - - @penumbra-zone/getters@1.1.0 - - @penumbra-zone/polyfills@1.1.0 - - @penumbra-zone/transport-dom@1.1.0 - - @penumbra-zone/types@1.1.0 - - @penumbra-zone/query@1.0.2 - - @penumbra-zone/services@1.0.2 - - @penumbra-zone/storage@1.0.2 - - @penumbra-zone/crypto-web@1.0.1 - - @penumbra-zone/wasm@1.0.2 diff --git a/packages/services/eslint.config.mjs b/packages/services/eslint.config.mjs deleted file mode 100644 index a53ed8e5..00000000 --- a/packages/services/eslint.config.mjs +++ /dev/null @@ -1,13 +0,0 @@ -import { penumbraEslintConfig } from '@penumbra-zone/eslint-config'; -import { config, parser } from 'typescript-eslint'; - -export default config({ - ...penumbraEslintConfig, - languageOptions: { - parser, - parserOptions: { - project: true, - tsconfigRootDir: import.meta.dirname, - }, - }, -}); diff --git a/packages/services/package.json b/packages/services/package.json deleted file mode 100644 index 03b69f00..00000000 --- a/packages/services/package.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "name": "@penumbra-zone/services", - "version": "4.1.0", - "private": true, - "license": "(MIT OR Apache-2.0)", - "type": "module", - "scripts": { - "lint": "eslint src", - "test": "vitest run" - }, - "files": [ - "src/", - "*.md", - "!**/*.test.ts", - "!test-utils.ts" - ], - "exports": { - "./ctx/*": "./src/ctx/*.ts", - "./*": "./src/*/index.ts" - }, - "dependencies": { - "@penumbra-zone/bech32m": "workspace:*", - "@penumbra-zone/crypto-web": "workspace:*", - "@penumbra-zone/getters": "workspace:*", - "@penumbra-zone/perspective": "workspace:*", - "@penumbra-zone/polyfills": "workspace:*", - "@penumbra-zone/protobuf": "workspace:*", - "@penumbra-zone/query": "workspace:*", - "@penumbra-zone/services-context": "workspace:*", - "@penumbra-zone/storage": "workspace:*", - "@penumbra-zone/transport-dom": "workspace:*", - "@penumbra-zone/types": "workspace:*", - "@penumbra-zone/wasm": "workspace:*" - }, - "devDependencies": { - "@buf/penumbra-zone_penumbra.bufbuild_es": "1.9.0-20240528180215-8fe1c79485f8.1", - "@bufbuild/protobuf": "^1.10.0", - "@connectrpc/connect": "^1.4.0" - }, - "peerDependencies": { - "@buf/penumbra-zone_penumbra.bufbuild_es": "1.9.0-20240528180215-8fe1c79485f8.1", - "@bufbuild/protobuf": "^1.10.0", - "@connectrpc/connect": "^1.4.0" - } -} diff --git a/packages/services/src/ctx/approver.ts b/packages/services/src/ctx/approver.ts deleted file mode 100644 index 1fe0c805..00000000 --- a/packages/services/src/ctx/approver.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { AuthorizeRequest } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/custody/v1/custody_pb'; -import { Code, ConnectError, createContextKey } from '@connectrpc/connect'; -import { PartialMessage } from '@bufbuild/protobuf'; -import { UserChoice } from '@penumbra-zone/types/user-choice'; - -export type TxApprovalFn = ( - authorizeRequest: PartialMessage, -) => Promise; -export const approverCtx = createContextKey(() => - Promise.reject(new ConnectError('No user approval method available', Code.FailedPrecondition)), -); diff --git a/packages/services/src/ctx/custody-client.ts b/packages/services/src/ctx/custody-client.ts deleted file mode 100644 index 39ddf91a..00000000 --- a/packages/services/src/ctx/custody-client.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { ContextKey, createContextKey, PromiseClient } from '@connectrpc/connect'; -import type { CustodyService } from '@penumbra-zone/protobuf'; - -export const custodyClientCtx: ContextKey | undefined> = - createContextKey(undefined); diff --git a/packages/services/src/ctx/full-viewing-key.ts b/packages/services/src/ctx/full-viewing-key.ts deleted file mode 100644 index 444f82cf..00000000 --- a/packages/services/src/ctx/full-viewing-key.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { Code, ConnectError, createContextKey } from '@connectrpc/connect'; -import { FullViewingKey } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb'; - -export const fvkCtx = createContextKey<() => Promise>(() => - Promise.reject(new ConnectError('No full viewing key available', Code.FailedPrecondition)), -); diff --git a/packages/services/src/ctx/prax.ts b/packages/services/src/ctx/prax.ts deleted file mode 100644 index 0fd3df57..00000000 --- a/packages/services/src/ctx/prax.ts +++ /dev/null @@ -1,11 +0,0 @@ -/** - * The context keys in this file are very Prax-specific and, in the interest of - * portable service implementations, should eventually be refactored. - */ - -import { ConnectError, createContextKey } from '@connectrpc/connect'; -import type { ServicesInterface } from '@penumbra-zone/types/services'; - -export const servicesCtx = createContextKey<() => Promise>(() => - Promise.reject(new ConnectError('No prax services interface available')), -); diff --git a/packages/services/src/ctx/spend-key.ts b/packages/services/src/ctx/spend-key.ts deleted file mode 100644 index 4f993870..00000000 --- a/packages/services/src/ctx/spend-key.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { Code, ConnectError, createContextKey } from '@connectrpc/connect'; -import { SpendKey } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb'; - -export const skCtx = createContextKey<() => Promise>(() => - Promise.reject(new ConnectError('No spend key available', Code.FailedPrecondition)), -); diff --git a/packages/services/src/ctx/stake-client.ts b/packages/services/src/ctx/stake-client.ts deleted file mode 100644 index d80e652e..00000000 --- a/packages/services/src/ctx/stake-client.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { ContextKey, createContextKey, PromiseClient } from '@connectrpc/connect'; -import type { StakeService } from '@penumbra-zone/protobuf'; - -export const stakeClientCtx: ContextKey | undefined> = - createContextKey(undefined); diff --git a/packages/services/src/ctx/wallet-id.ts b/packages/services/src/ctx/wallet-id.ts deleted file mode 100644 index 4c53d460..00000000 --- a/packages/services/src/ctx/wallet-id.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { ConnectError, createContextKey } from '@connectrpc/connect'; -import { WalletId } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb'; - -export const walletIdCtx = createContextKey<() => Promise>(() => - Promise.reject(new ConnectError('No wallet id available')), -); diff --git a/packages/services/src/custody-service/authorize.test.ts b/packages/services/src/custody-service/authorize.test.ts deleted file mode 100644 index 9d12210e..00000000 --- a/packages/services/src/custody-service/authorize.test.ts +++ /dev/null @@ -1,249 +0,0 @@ -import { beforeEach, describe, expect, Mock, test, vi } from 'vitest'; -import { createContextValues, createHandlerContext, HandlerContext } from '@connectrpc/connect'; -import { approverCtx } from '../ctx/approver'; -import { servicesCtx } from '../ctx/prax'; -import { testFullViewingKey, testSpendKey } from '../test-utils'; -import { authorize } from './authorize'; -import { AuthorizeRequest } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/custody/v1/custody_pb'; -import { CustodyService } from '@penumbra-zone/protobuf'; -import { - AuthorizationData, - TransactionPlan, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/transaction/v1/transaction_pb'; -import type { ServicesInterface } from '@penumbra-zone/types/services'; -import { Metadata } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; -import { UserChoice } from '@penumbra-zone/types/user-choice'; -import { fvkCtx } from '../ctx/full-viewing-key'; -import { skCtx } from '../ctx/spend-key'; - -describe('Authorize request handler', () => { - let req: AuthorizeRequest; - - const mockApproverCtx = vi.fn(() => Promise.resolve(UserChoice.Approved)); - const mockFullViewingKeyCtx = vi.fn(() => Promise.resolve(testFullViewingKey)); - const mockSpendKeyCtx = vi.fn(() => Promise.resolve(testSpendKey)); - const mockServicesCtx: Mock<[], Promise> = vi.fn(); - - const handlerContextInit = { - service: CustodyService, - method: CustodyService.methods.authorize, - protocolName: 'mock', - requestMethod: 'MOCK', - url: '/mock', - }; - - const contextValues = createContextValues() - .set(approverCtx, mockApproverCtx as unknown) - .set(servicesCtx, mockServicesCtx) - .set(fvkCtx, mockFullViewingKeyCtx) - .set(skCtx, mockSpendKeyCtx); - - const mockCtx: HandlerContext = createHandlerContext({ - ...handlerContextInit, - contextValues, - }); - - beforeEach(() => { - const mockIterateMetadata = { - next: vi.fn(), - [Symbol.asyncIterator]: () => mockIterateMetadata, - }; - - mockServicesCtx.mockResolvedValue({ - getWalletServices: () => - Promise.resolve({ - indexedDb: { - iterateAssetsMetadata: () => mockIterateMetadata, - }, - }), - } as unknown as ServicesInterface); - - for (const record of testAssetsMetadata) { - mockIterateMetadata.next.mockResolvedValue({ - value: record, - }); - } - mockIterateMetadata.next.mockResolvedValue({ - done: true, - }); - - req = new AuthorizeRequest({ plan: testTxPlanData }); - }); - - test('should successfully authorize request', async () => { - const authData = authorize(req, mockCtx); - await expect(authData).resolves.toHaveProperty('data'); - const { data } = await authData; - expect(data).toBeInstanceOf(AuthorizationData); - }); - - test('should fail if user denies request', async () => { - mockApproverCtx.mockResolvedValueOnce(UserChoice.Denied); - await expect(authorize(req, mockCtx)).rejects.toThrow(); - }); - - test('should fail if plan is missing in request', async () => { - await expect(authorize(new AuthorizeRequest(), mockCtx)).rejects.toThrow( - 'No plan included in request', - ); - }); - - test('should fail if fullViewingKey context is not configured', async () => { - const ctxWithoutFullViewingKey = createHandlerContext({ - ...handlerContextInit, - contextValues: createContextValues() - .set(approverCtx, mockApproverCtx as unknown) - .set(servicesCtx, mockServicesCtx) - .set(skCtx, mockSpendKeyCtx), - }); - await expect(authorize(req, ctxWithoutFullViewingKey)).rejects.toThrow('[failed_precondition]'); - }); - - test('should fail if spendKey context is not configured', async () => { - const ctxWithoutSpendKey = createHandlerContext({ - ...handlerContextInit, - contextValues: createContextValues() - .set(approverCtx, mockApproverCtx as unknown) - .set(servicesCtx, mockServicesCtx) - .set(fvkCtx, mockFullViewingKeyCtx), - }); - await expect(authorize(req, ctxWithoutSpendKey)).rejects.toThrow('[failed_precondition]'); - }); - - test('should fail if approver context is not configured', async () => { - const ctxWithoutApprover = createHandlerContext({ - ...handlerContextInit, - contextValues: createContextValues() - .set(servicesCtx, mockServicesCtx) - .set(fvkCtx, mockFullViewingKeyCtx) - .set(skCtx, mockSpendKeyCtx), - }); - await expect(authorize(req, ctxWithoutApprover)).rejects.toThrow('[failed_precondition]'); - }); - - test('should fail with reason if spendKey is not available', async () => { - mockSpendKeyCtx.mockRejectedValueOnce(new Error('some reason')); - await expect(authorize(req, mockCtx)).rejects.toThrow('some reason'); - }); -}); - -const testTxPlanData = TransactionPlan.fromJson({ - actions: [ - { - output: { - value: { - amount: { - lo: '2000000', - }, - assetId: { - inner: 'KeqcLzNx9qSH5+lcJHBB9KNW+YPrBk5dKzvPMiypahA=', - }, - }, - destAddress: { - inner: - '0AI1VPl2Z2iM62nnBX+o00kL3Fcvcqm8zgp0ErDpw4hT2syB5TeaGJM8B+5KV+/3CS78toGM3WleoNgPh/7L9bKNOrmq7UEqBmfAb7MDI+w=', - }, - rseed: 'BULXqsGKMksW5MfrJAuWWWaEHJw36avj90y+/TzDspk=', - valueBlinding: 'DMAmhhWllwK84CFBGY5OPkkCLP1pRNhyK0OzotdAnwE=', - proofBlindingR: 'doF1SnSllGyEqWWsmEIiHlCnDG9M083qjeyFNHW9agc=', - proofBlindingS: 'uRcVB0ZoUWPDrNA0wfznHJ6Wfn3usDCgazIDkLmZIQE=', - }, - }, - { - spend: { - note: { - value: { - amount: { - lo: '999970000000', - }, - assetId: { - inner: 'KeqcLzNx9qSH5+lcJHBB9KNW+YPrBk5dKzvPMiypahA=', - }, - }, - rseed: 's8BBrPg6NNLttLZfg7Ban2LOyqyt3IxpBFK9MmpHvKQ=', - address: { - inner: - 'H54tVYCe2KONaws0+4Qt8jHSup2InYWauNEGtLa7+yQ8ssaP1Qc2bjsB7uyfQl3QKMXzfm3u70/CbK9tOiSXjDtDzx3AtQw2wKCeuht3Ono=', - }, - }, - position: '34395652097', - randomizer: '6cyFYGqAzvV4mMwsmZBAwELPUv1ZGFcY8f+X07zgtgI=', - valueBlinding: '7EMBCEOyvPGDAuqRqivIdVVPgIV2NCLwin3n5pQqXgA=', - proofBlindingR: '5lN3tTp7HwVcMwftb/YPIv5zfVP6CdmjlCEjQcPzGQo=', - proofBlindingS: 'JFvqR0FInc0EqgmnhZmUVbsbnxz6dKoSkgheGAjZYQI=', - }, - }, - { - output: { - value: { - amount: { - lo: '999968000000', - }, - assetId: { - inner: 'KeqcLzNx9qSH5+lcJHBB9KNW+YPrBk5dKzvPMiypahA=', - }, - }, - destAddress: { - inner: - 'H54tVYCe2KONaws0+4Qt8jHSup2InYWauNEGtLa7+yQ8ssaP1Qc2bjsB7uyfQl3QKMXzfm3u70/CbK9tOiSXjDtDzx3AtQw2wKCeuht3Ono=', - }, - rseed: 'gYyyrY8TsRvUNKIdP1YCpJp/Eu/s0e07zCtn7hN5GEU=', - valueBlinding: 'X+GBy22M8nw96admaf73HSHfwQV6kY1h+hwtxyv43gM=', - proofBlindingR: 'x8nvKsa9z4sLwwvPTsJPzeUGXjYc+io6jlj9sHCAIQ4=', - proofBlindingS: 'cwonvYBvfGCke2uMZOCOqFXQ1xWGdQxmGmnUyRSa0wk=', - }, - }, - ], - transactionParameters: { - chainId: 'penumbra-testnet-deimos-4-a9b11fc4', - fee: { - amount: {}, - }, - }, - detectionData: { - cluePlans: [ - { - address: { - inner: - '0AI1VPl2Z2iM62nnBX+o00kL3Fcvcqm8zgp0ErDpw4hT2syB5TeaGJM8B+5KV+/3CS78toGM3WleoNgPh/7L9bKNOrmq7UEqBmfAb7MDI+w=', - }, - rseed: '2lahgt65yDWXPfLS/rvs8pdvLVQ8czd3XBYmJTIWsCg=', - }, - { - address: { - inner: - 'H54tVYCe2KONaws0+4Qt8jHSup2InYWauNEGtLa7+yQ8ssaP1Qc2bjsB7uyfQl3QKMXzfm3u70/CbK9tOiSXjDtDzx3AtQw2wKCeuht3Ono=', - }, - rseed: 'IG3MCsS8gtTOrqaOTWxkAKHAnFTgYEKsd9rsvsUuGFQ=', - }, - ], - }, - memo: { - plaintext: { - returnAddress: { - inner: - 'H54tVYCe2KONaws0+4Qt8jHSup2InYWauNEGtLa7+yQ8ssaP1Qc2bjsB7uyfQl3QKMXzfm3u70/CbK9tOiSXjDtDzx3AtQw2wKCeuht3Ono=', - }, - text: 'Authorize test', - }, - key: 'oEBs1HP1bMgskLja5CAuFMpRM1Xw6IScIbBXJKzRJgc=', - }, -}); - -const testAssetsMetadata = [ - Metadata.fromJson({ - description: '', - denomUnits: [ - { denom: 'penumbra', exponent: 6, aliases: [] }, - { denom: 'mpenumbra', exponent: 3, aliases: [] }, - { denom: 'upenumbra', exponent: 0, aliases: [] }, - ], - base: 'upenumbra', - display: 'penumbra', - name: '', - symbol: '', - penumbraAssetId: { - inner: 'KeqcLzNx9qSH5+lcJHBB9KNW+YPrBk5dKzvPMiypahA=', - }, - }), -]; diff --git a/packages/services/src/custody-service/authorize.ts b/packages/services/src/custody-service/authorize.ts deleted file mode 100644 index d44d242c..00000000 --- a/packages/services/src/custody-service/authorize.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { Impl } from '.'; -import { approverCtx } from '../ctx/approver'; -import { authorizePlan } from '@penumbra-zone/wasm/build'; -import { Code, ConnectError } from '@connectrpc/connect'; -import { UserChoice } from '@penumbra-zone/types/user-choice'; -import { fvkCtx } from '../ctx/full-viewing-key'; -import { skCtx } from '../ctx/spend-key'; -import { assertValidAuthorizeRequest } from './validation/authorize'; - -export const authorize: Impl['authorize'] = async (req, ctx) => { - if (!req.plan) throw new ConnectError('No plan included in request', Code.InvalidArgument); - - const fullViewingKey = await ctx.values.get(fvkCtx)(); - assertValidAuthorizeRequest(req, fullViewingKey); - - const choice = await ctx.values.get(approverCtx)(req); - if (choice !== UserChoice.Approved) - throw new ConnectError('Transaction was not approved', Code.PermissionDenied); - - const spendKey = await ctx.values.get(skCtx)(); - - const data = authorizePlan(spendKey, req.plan); - return { data }; -}; diff --git a/packages/services/src/custody-service/index.ts b/packages/services/src/custody-service/index.ts deleted file mode 100644 index 35f66f30..00000000 --- a/packages/services/src/custody-service/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { CustodyService } from '@penumbra-zone/protobuf'; -import type { ServiceImpl } from '@connectrpc/connect'; -import { authorize } from './authorize'; - -export type Impl = ServiceImpl; - -export const custodyImpl: Omit< - Impl, - | 'confirmAddress' - | 'exportFullViewingKey' - | 'authorizeValidatorVote' - | 'authorizeValidatorDefinition' -> = { - authorize, -}; diff --git a/packages/services/src/custody-service/validation/assert-swap-claim-addresses-belong-to-current-user.test.ts b/packages/services/src/custody-service/validation/assert-swap-claim-addresses-belong-to-current-user.test.ts deleted file mode 100644 index 52b6f396..00000000 --- a/packages/services/src/custody-service/validation/assert-swap-claim-addresses-belong-to-current-user.test.ts +++ /dev/null @@ -1,123 +0,0 @@ -import { describe, expect, it } from 'vitest'; -import { assertSwapClaimAddressesBelongToCurrentUser } from './assert-swap-claim-addresses-belong-to-current-user'; -import { - ActionPlan, - TransactionPlan, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/transaction/v1/transaction_pb'; -import { Code, ConnectError } from '@connectrpc/connect'; -import { Address } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb'; - -const currentUserAddress1 = new Address({ - inner: new Uint8Array([1, 2, 3]), -}); - -const currentUserAddress2 = new Address({ - inner: new Uint8Array([4, 5, 6]), -}); - -const otherUserAddress = new Address({ - inner: new Uint8Array([7, 8, 9]), -}); - -const swapWithCurrentUserAddress1 = new ActionPlan({ - action: { - case: 'swap', - value: { - swapPlaintext: { - claimAddress: currentUserAddress1, - }, - }, - }, -}); - -const swapWithCurrentUserAddress2 = new ActionPlan({ - action: { - case: 'swap', - value: { - swapPlaintext: { - claimAddress: currentUserAddress2, - }, - }, - }, -}); - -const swapWithOtherUserAddress = new ActionPlan({ - action: { - case: 'swap', - value: { - swapPlaintext: { - claimAddress: otherUserAddress, - }, - }, - }, -}); - -const swapWithUndefinedAddress = new ActionPlan({ - action: { - case: 'swap', - value: { - swapPlaintext: {}, - }, - }, -}); - -const mockIsControlledAddress = (address?: Address) => - !!address && [currentUserAddress1, currentUserAddress2].includes(address); - -describe('assertSwapClaimAddressesBelongToCurrentUser()', () => { - describe('when the transaction plan has no swaps', () => { - it('does not throw', () => { - expect(() => - assertSwapClaimAddressesBelongToCurrentUser(new TransactionPlan(), mockIsControlledAddress), - ).not.toThrow(); - }); - }); - - describe('when the transaction plan has swaps', () => { - describe("when all of the swaps' `claimAddress`es belong to the current user", () => { - it('does not throw', () => { - const plan = new TransactionPlan({ - actions: [swapWithCurrentUserAddress1, swapWithCurrentUserAddress2], - }); - - expect(() => - assertSwapClaimAddressesBelongToCurrentUser(plan, mockIsControlledAddress), - ).not.toThrow(); - }); - }); - - describe("when any of the swaps' `claimAddress`es do not belong to the current user", () => { - it('throws a `ConnectError` with the `PermissionDenied` code', () => { - const plan = new TransactionPlan({ - actions: [swapWithCurrentUserAddress1, swapWithOtherUserAddress], - }); - - expect.assertions(2); - - try { - assertSwapClaimAddressesBelongToCurrentUser(plan, mockIsControlledAddress); - } catch (error) { - expect(error).toBeInstanceOf(ConnectError); - expect((error as ConnectError).code).toBe(Code.PermissionDenied); - } - }); - }); - - describe("when any of the swaps' `claimAddress`es are empty", () => { - it('throws a `ConnectError` with the `PermissionDenied` code', () => { - const plan = new TransactionPlan({ - actions: [swapWithUndefinedAddress], - }); - - expect.assertions(2); - - try { - assertSwapClaimAddressesBelongToCurrentUser(plan, mockIsControlledAddress); - } catch (error) { - expect(error).toBeInstanceOf(ConnectError); - expect((error as ConnectError).code).toBe(Code.PermissionDenied); - } - }); - }); - }); -}); diff --git a/packages/services/src/custody-service/validation/assert-swap-claim-addresses-belong-to-current-user.ts b/packages/services/src/custody-service/validation/assert-swap-claim-addresses-belong-to-current-user.ts deleted file mode 100644 index 03f305f3..00000000 --- a/packages/services/src/custody-service/validation/assert-swap-claim-addresses-belong-to-current-user.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Address } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb'; -import { TransactionPlan } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/transaction/v1/transaction_pb'; -import { Code, ConnectError } from '@connectrpc/connect'; - -export const assertSwapClaimAddressesBelongToCurrentUser = ( - plan: TransactionPlan, - isControlledAddress: (address?: Address) => boolean, -): void => { - plan.actions.forEach(action => { - if (action.action.case !== 'swap') return; - - if (!isControlledAddress(action.action.value.swapPlaintext?.claimAddress)) { - throw new ConnectError( - "Tried to initiate a swap with a claim address belonging to a different user. This means that, when the swap is claimed, the funds would go to someone else's address, not yours. This should never happen. The website you are using may be trying to steal your funds!", - Code.PermissionDenied, - ); - } - }); -}; diff --git a/packages/services/src/custody-service/validation/authorize.ts b/packages/services/src/custody-service/validation/authorize.ts deleted file mode 100644 index ee501354..00000000 --- a/packages/services/src/custody-service/validation/authorize.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { assertSwapClaimAddressesBelongToCurrentUser } from './assert-swap-claim-addresses-belong-to-current-user'; -import { isControlledAddress } from '@penumbra-zone/wasm/address'; -import { AuthorizeRequest } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/custody/v1/custody_pb'; -import { FullViewingKey } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb'; - -/** - * Makes a series of assertions that ensure the validity of the request, - * throwing an error if any of them fail. - * - * Assertions should be related to _security_ -- that is, this is the place to - * catch issues with the transaction that have security implications if left - * uncaught. For example, this is where to ensure that a swap transaction's - * claim address actually belongs to the current user. (If such an assertion - * were placed in e.g., the `transactionPlanner` implementation, malicious - * websites could get around it by planning the transaction themselves, rather - * than calling the `transactionPlanner` method. But there is no way for - * malicious websites to avoid calling `authorize`, so putting the assertion - * here is an absolute roadblock to such behavior.) - * - * Add more assertions to this function as needed. - */ -export const assertValidAuthorizeRequest = (req: AuthorizeRequest, fvk: FullViewingKey): void => - assertSwapClaimAddressesBelongToCurrentUser(req.plan!, address => - isControlledAddress(fvk, address), - ); diff --git a/packages/services/src/offscreen-client.ts b/packages/services/src/offscreen-client.ts deleted file mode 100644 index 307ecdb2..00000000 --- a/packages/services/src/offscreen-client.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { FullViewingKey } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb'; -import { - Action, - TransactionPlan, - WitnessData, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/transaction/v1/transaction_pb'; -import { ConnectError } from '@connectrpc/connect'; -import { errorFromJson } from '@connectrpc/connect/protocol-connect'; -import { ActionBuildMessage, OffscreenMessage } from '@penumbra-zone/types/internal-msg/offscreen'; -import { InternalRequest, InternalResponse } from '@penumbra-zone/types/internal-msg/shared'; -import type { Jsonified } from '@penumbra-zone/types/jsonified'; - -const OFFSCREEN_DOCUMENT_PATH = '/offscreen.html'; - -let active = 0; - -const activateOffscreen = async () => { - const noOffscreen = chrome.runtime - .getContexts({ - contextTypes: [chrome.runtime.ContextType.OFFSCREEN_DOCUMENT], - }) - .then(offscreenContexts => !offscreenContexts.length); - - if (!active++ || (await noOffscreen)) - await chrome.offscreen - .createDocument({ - url: chrome.runtime.getURL(OFFSCREEN_DOCUMENT_PATH), - reasons: [chrome.offscreen.Reason.WORKERS], - justification: 'Manages Penumbra transaction WASM workers', - }) - .catch((e: unknown) => { - // the offscreen window might have been created since we checked - // TODO: other failures? - console.warn('Failed to create offscreen window', e); - }); -}; - -/** - * Decrement and close if there is no remaining activity. - */ -const releaseOffscreen = async () => { - if (!--active) await chrome.offscreen.closeDocument(); -}; - -const sendOffscreenMessage = async (req: InternalRequest) => - chrome.runtime.sendMessage, InternalResponse>(req).then(res => { - if ('error' in res) throw errorFromJson(res.error, undefined, ConnectError.from(res)); - return res.data; - }); - -/** - * Build actions in parallel, in an offscreen window where we can run wasm. - * @param cancel Promise that rejects if the build should be cancelled, usually auth denial. - * @returns An independently-promised list of action build results. - */ -const buildActions = ( - transactionPlan: TransactionPlan, - witness: WitnessData, - fullViewingKey: FullViewingKey, - cancel: PromiseLike, -): Promise[] => { - const activation = activateOffscreen(); - - // this json serialization involves a lot of binary -> base64 which is slow, - // so just do it once and reuse - const partialRequest = { - transactionPlan: transactionPlan.toJson() as Jsonified, - witness: witness.toJson() as Jsonified, - fullViewingKey: fullViewingKey.toJson() as Jsonified, - }; - - const buildTasks = transactionPlan.actions.map(async (_, actionPlanIndex) => { - const buildReq: InternalRequest = { - type: 'BUILD_ACTION', - request: { - ...partialRequest, - actionPlanIndex, - }, - }; - - // wait for offscreen to finish standing up - await activation; - - const buildRes = await sendOffscreenMessage(buildReq); - return Action.fromJson(buildRes); - }); - - void Promise.race([Promise.all(buildTasks), cancel]) - // suppress 'unhandled promise' logs - real failures are already conveyed by the individual promises. - .catch() - // this build is done with offscreen. it may shut down - .finally(() => void releaseOffscreen()); - - return buildTasks; -}; - -export const offscreenClient = { buildActions }; diff --git a/packages/services/src/sct-service/epoch-by-height.test.ts b/packages/services/src/sct-service/epoch-by-height.test.ts deleted file mode 100644 index 09e818cf..00000000 --- a/packages/services/src/sct-service/epoch-by-height.test.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { beforeEach, describe, expect, it, vi } from 'vitest'; -import { epochByHeight } from './epoch-by-height'; -import { IndexedDbMock, MockServices } from '../test-utils'; -import { createContextValues, createHandlerContext, HandlerContext } from '@connectrpc/connect'; -import { SctService } from '@penumbra-zone/protobuf'; -import { servicesCtx } from '../ctx/prax'; -import { - Epoch, - EpochByHeightRequest, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/sct/v1/sct_pb'; -import type { ServicesInterface } from '@penumbra-zone/types/services'; - -describe('EpochByHeight request handler', () => { - let mockServices: MockServices; - let mockIndexedDb: IndexedDbMock; - let mockCtx: HandlerContext; - - beforeEach(() => { - vi.resetAllMocks(); - - mockIndexedDb = { - getEpochByHeight: vi.fn(), - }; - mockServices = { - getWalletServices: vi.fn(() => - Promise.resolve({ indexedDb: mockIndexedDb }), - ) as MockServices['getWalletServices'], - }; - mockCtx = createHandlerContext({ - service: SctService, - method: SctService.methods.epochByHeight, - protocolName: 'mock', - requestMethod: 'MOCK', - url: '/mock', - contextValues: createContextValues().set(servicesCtx, () => - Promise.resolve(mockServices as unknown as ServicesInterface), - ), - }); - }); - - it('returns an `EpochByHeightResponse` with the result of the database query', async () => { - const expected = new Epoch({ startHeight: 0n, index: 0n }); - - mockIndexedDb.getEpochByHeight?.mockResolvedValue(expected); - const req = new EpochByHeightRequest({ height: 0n }); - - const result = await epochByHeight(req, mockCtx); - - expect(result.epoch).toBeInstanceOf(Epoch); - expect((result.epoch as Epoch).toJson()).toEqual(expected.toJson()); - }); -}); diff --git a/packages/services/src/sct-service/epoch-by-height.ts b/packages/services/src/sct-service/epoch-by-height.ts deleted file mode 100644 index 81643150..00000000 --- a/packages/services/src/sct-service/epoch-by-height.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { EpochByHeightResponse } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/sct/v1/sct_pb'; -import { Impl } from '.'; -import { servicesCtx } from '../ctx/prax'; - -export const epochByHeight: Impl['epochByHeight'] = async (req, ctx) => { - const { height } = req; - - const services = await ctx.values.get(servicesCtx)(); - const { indexedDb } = await services.getWalletServices(); - - const epoch = await indexedDb.getEpochByHeight(height); - - return new EpochByHeightResponse({ epoch }); -}; diff --git a/packages/services/src/sct-service/index.ts b/packages/services/src/sct-service/index.ts deleted file mode 100644 index cbd56706..00000000 --- a/packages/services/src/sct-service/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -import type { ServiceImpl } from '@connectrpc/connect'; -import type { SctService } from '@penumbra-zone/protobuf'; -import { epochByHeight } from './epoch-by-height'; - -export type Impl = ServiceImpl; - -export const sctImpl: Omit = { - epochByHeight, -}; diff --git a/packages/services/src/stake-service/get-validator-info.test.ts b/packages/services/src/stake-service/get-validator-info.test.ts deleted file mode 100644 index 8a564a15..00000000 --- a/packages/services/src/stake-service/get-validator-info.test.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { beforeEach, describe, expect, it, vi } from 'vitest'; -import { IndexedDbMock, MockServices } from '../test-utils'; -import { createContextValues, createHandlerContext, HandlerContext } from '@connectrpc/connect'; -import { StakeService } from '@penumbra-zone/protobuf'; -import { servicesCtx } from '../ctx/prax'; -import { - GetValidatorInfoRequest, - GetValidatorInfoResponse, - ValidatorState_ValidatorStateEnum, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/stake/v1/stake_pb'; -import type { ServicesInterface } from '@penumbra-zone/types/services'; -import { getValidatorInfo } from './get-validator-info'; - -describe('GetValidatorInfo request handler', () => { - let mockServices: MockServices; - let mockIndexedDb: IndexedDbMock; - let mockCtx: HandlerContext; - let req: GetValidatorInfoRequest; - const mockGetValidatorInfoResponse = new GetValidatorInfoResponse({ - validatorInfo: { - validator: { name: 'Validator 1', identityKey: { ik: new Uint8Array(32) } }, - status: { state: { state: ValidatorState_ValidatorStateEnum.ACTIVE } }, - }, - }); - - beforeEach(() => { - vi.resetAllMocks(); - - mockIndexedDb = { - getValidatorInfo: vi.fn(), - }; - mockServices = { - getWalletServices: vi.fn(() => - Promise.resolve({ indexedDb: mockIndexedDb }), - ) as MockServices['getWalletServices'], - }; - mockCtx = createHandlerContext({ - service: StakeService, - method: StakeService.methods.validatorInfo, - protocolName: 'mock', - requestMethod: 'MOCK', - url: '/mock', - contextValues: createContextValues().set(servicesCtx, () => - Promise.resolve(mockServices as unknown as ServicesInterface), - ), - }); - - req = new GetValidatorInfoRequest({ - identityKey: mockGetValidatorInfoResponse.validatorInfo?.validator?.identityKey, - }); - }); - - it('should successfully get validator info when idb has them', async () => { - mockIndexedDb.getValidatorInfo?.mockResolvedValueOnce( - mockGetValidatorInfoResponse.validatorInfo, - ); - - const validatorInfoResponse = await getValidatorInfo(req, mockCtx); - expect(validatorInfoResponse.validatorInfo).toEqual(mockGetValidatorInfoResponse.validatorInfo); - }); - - it('should fail to get validator info when idb has none', async () => { - await expect(getValidatorInfo(req, mockCtx)).rejects.toThrow('No found validator info'); - }); - - it('should fail to get validator info if identity key is not passed', async () => { - await expect(getValidatorInfo(new GetValidatorInfoRequest(), mockCtx)).rejects.toThrow( - 'Missing identityKey in request', - ); - }); -}); diff --git a/packages/services/src/stake-service/get-validator-info.ts b/packages/services/src/stake-service/get-validator-info.ts deleted file mode 100644 index c4cbbdde..00000000 --- a/packages/services/src/stake-service/get-validator-info.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Impl } from '.'; -import { servicesCtx } from '../ctx/prax'; -import { Code, ConnectError } from '@connectrpc/connect'; - -export const getValidatorInfo: Impl['getValidatorInfo'] = async (req, ctx) => { - if (!req.identityKey) { - throw new ConnectError('Missing identityKey in request', Code.InvalidArgument); - } - const services = await ctx.values.get(servicesCtx)(); - const { indexedDb } = await services.getWalletServices(); - - const validatorInfo = await indexedDb.getValidatorInfo(req.identityKey); - - if (!validatorInfo) { - throw new ConnectError('No found validator info', Code.NotFound); - } - return { validatorInfo }; -}; diff --git a/packages/services/src/stake-service/index.ts b/packages/services/src/stake-service/index.ts deleted file mode 100644 index 76f2f89a..00000000 --- a/packages/services/src/stake-service/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { ServiceImpl } from '@connectrpc/connect'; -import type { StakeService } from '@penumbra-zone/protobuf'; -import { getValidatorInfo } from './get-validator-info'; -import { validatorInfo } from './validator-info'; -import { validatorPenalty } from './validator-penalty'; - -export type Impl = ServiceImpl; - -export const stakeImpl: Omit = - { - getValidatorInfo, - validatorInfo, - validatorPenalty, - }; diff --git a/packages/services/src/stake-service/validator-info.test.ts b/packages/services/src/stake-service/validator-info.test.ts deleted file mode 100644 index 4134f263..00000000 --- a/packages/services/src/stake-service/validator-info.test.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { beforeEach, describe, expect, it, vi } from 'vitest'; -import { validatorInfo } from './validator-info'; -import { IndexedDbMock, MockServices } from '../test-utils'; -import { createContextValues, createHandlerContext, HandlerContext } from '@connectrpc/connect'; -import { StakeService } from '@penumbra-zone/protobuf'; -import { servicesCtx } from '../ctx/prax'; -import { - ValidatorInfoRequest, - ValidatorInfoResponse, - ValidatorState_ValidatorStateEnum, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/stake/v1/stake_pb'; -import { PartialMessage } from '@bufbuild/protobuf'; -import type { ServicesInterface } from '@penumbra-zone/types/services'; - -describe('ValidatorInfo request handler', () => { - let mockServices: MockServices; - let mockIndexedDb: IndexedDbMock; - let mockCtx: HandlerContext; - const mockValidatorInfoResponse1 = new ValidatorInfoResponse({ - validatorInfo: { - validator: { name: 'Validator 1' }, - status: { state: { state: ValidatorState_ValidatorStateEnum.ACTIVE } }, - }, - }); - const mockValidatorInfoResponse2 = new ValidatorInfoResponse({ - validatorInfo: { - validator: { name: 'Validator 2' }, - status: { state: { state: ValidatorState_ValidatorStateEnum.INACTIVE } }, - }, - }); - - beforeEach(() => { - vi.resetAllMocks(); - - const mockIterateValidatorInfos = { - next: vi.fn(), - [Symbol.asyncIterator]: () => mockIterateValidatorInfos, - }; - mockIterateValidatorInfos.next.mockResolvedValueOnce({ - value: mockValidatorInfoResponse1.validatorInfo, - }); - mockIterateValidatorInfos.next.mockResolvedValueOnce({ - value: mockValidatorInfoResponse2.validatorInfo, - }); - mockIterateValidatorInfos.next.mockResolvedValueOnce({ done: true }); - - mockIndexedDb = { - iterateValidatorInfos: () => mockIterateValidatorInfos, - }; - mockServices = { - getWalletServices: vi.fn(() => - Promise.resolve({ indexedDb: mockIndexedDb }), - ) as MockServices['getWalletServices'], - }; - mockCtx = createHandlerContext({ - service: StakeService, - method: StakeService.methods.validatorInfo, - protocolName: 'mock', - requestMethod: 'MOCK', - url: '/mock', - contextValues: createContextValues().set(servicesCtx, () => - Promise.resolve(mockServices as unknown as ServicesInterface), - ), - }); - }); - - it('streams `ValidatorInfoResponse`s from the results of the database query', async () => { - const req = new ValidatorInfoRequest({ showInactive: true }); - - const results: (ValidatorInfoResponse | PartialMessage)[] = []; - for await (const result of validatorInfo(req, mockCtx)) { - results.push(result); - } - - expect(results).toEqual([mockValidatorInfoResponse1, mockValidatorInfoResponse2]); - }); - - it('does not include inactive validators by default', async () => { - const req = new ValidatorInfoRequest(); - - const results: (ValidatorInfoResponse | PartialMessage)[] = []; - for await (const result of validatorInfo(req, mockCtx)) { - results.push(result); - } - - expect(results).toEqual([mockValidatorInfoResponse1]); - }); -}); diff --git a/packages/services/src/stake-service/validator-info.ts b/packages/services/src/stake-service/validator-info.ts deleted file mode 100644 index 92621513..00000000 --- a/packages/services/src/stake-service/validator-info.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Impl } from '.'; -import { servicesCtx } from '../ctx/prax'; -import { - ValidatorInfoResponse, - ValidatorState_ValidatorStateEnum, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/stake/v1/stake_pb'; -import { getStateEnumFromValidatorInfo } from '@penumbra-zone/getters/validator-info'; - -export const validatorInfo: Impl['validatorInfo'] = async function* (req, ctx) { - const services = await ctx.values.get(servicesCtx)(); - const { indexedDb } = await services.getWalletServices(); - - for await (const validatorInfo of indexedDb.iterateValidatorInfos()) { - if ( - !req.showInactive && - getStateEnumFromValidatorInfo(validatorInfo) === ValidatorState_ValidatorStateEnum.INACTIVE - ) - continue; - - yield new ValidatorInfoResponse({ validatorInfo }); - } -}; diff --git a/packages/services/src/stake-service/validator-penalty.test.ts b/packages/services/src/stake-service/validator-penalty.test.ts deleted file mode 100644 index 09e0d36c..00000000 --- a/packages/services/src/stake-service/validator-penalty.test.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { beforeEach, describe, expect, it, Mock, vi } from 'vitest'; -import { validatorPenalty } from './validator-penalty'; -import { MockServices } from '../test-utils'; -import { createContextValues, createHandlerContext, HandlerContext } from '@connectrpc/connect'; -import { StakeService } from '@penumbra-zone/protobuf'; -import { servicesCtx } from '../ctx/prax'; -import { - ValidatorPenaltyRequest, - ValidatorPenaltyResponse, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/stake/v1/stake_pb'; -import type { ServicesInterface } from '@penumbra-zone/types/services'; - -describe('ValidatorPenalty request handler', () => { - let mockServices: MockServices; - let mockStakingQuerierValidatorPenalty: Mock; - let mockCtx: HandlerContext; - const mockValidatorPenaltyResponse = new ValidatorPenaltyResponse({ - penalty: { inner: new Uint8Array([0, 1, 2, 3]) }, - }); - - beforeEach(() => { - vi.resetAllMocks(); - - mockStakingQuerierValidatorPenalty = vi.fn().mockResolvedValue(mockValidatorPenaltyResponse); - - mockServices = { - getWalletServices: vi.fn(() => - Promise.resolve({ - querier: { - stake: { validatorPenalty: mockStakingQuerierValidatorPenalty }, - }, - }), - ) as MockServices['getWalletServices'], - } satisfies MockServices; - - mockCtx = createHandlerContext({ - service: StakeService, - method: StakeService.methods.validatorInfo, - protocolName: 'mock', - requestMethod: 'MOCK', - url: '/mock', - contextValues: createContextValues().set(servicesCtx, () => - Promise.resolve(mockServices as unknown as ServicesInterface), - ), - }); - }); - - it("returns the response from the staking querier's `validatorPenalty` method", async () => { - const req = new ValidatorPenaltyRequest(); - const result = await validatorPenalty(req, mockCtx); - - expect(mockStakingQuerierValidatorPenalty).toHaveBeenCalledWith(req); - expect(result as ValidatorPenaltyResponse).toEqual(mockValidatorPenaltyResponse); - }); -}); diff --git a/packages/services/src/stake-service/validator-penalty.ts b/packages/services/src/stake-service/validator-penalty.ts deleted file mode 100644 index 9ca331db..00000000 --- a/packages/services/src/stake-service/validator-penalty.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Impl } from '.'; -import { servicesCtx } from '../ctx/prax'; - -export const validatorPenalty: Impl['validatorPenalty'] = async (req, ctx) => { - const services = await ctx.values.get(servicesCtx)(); - const { querier } = await services.getWalletServices(); - return querier.stake.validatorPenalty(req); -}; diff --git a/packages/services/src/test-utils.ts b/packages/services/src/test-utils.ts deleted file mode 100644 index d16f3f23..00000000 --- a/packages/services/src/test-utils.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { Mock } from 'vitest'; -import { - FullViewingKey, - SpendKey, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb'; -import { fullViewingKeyFromBech32m } from '@penumbra-zone/bech32m/penumbrafullviewingkey'; - -export interface IndexedDbMock { - constants?: Mock; - getAppParams?: Mock; - getAssetsMetadata?: Mock; - getGasPrices?: Mock; - getFmdParams?: Mock; - getFullSyncHeight?: Mock; - getNotesForVoting?: Mock; - getOwnedPositionIds?: () => Partial>; - getSpendableNoteByCommitment?: Mock; - getSpendableNoteByNullifier?: Mock; - getStateCommitmentTree?: Mock; - getSwapByNullifier?: Mock; - getTransaction?: Mock; - iterateAssetsMetadata?: () => Partial>; - iterateSpendableNotes?: () => Partial>; - iterateSwaps?: () => Partial>; - iterateTransactions?: () => Partial>; - iterateValidatorInfos?: () => Partial>; - getValidatorInfo?: Mock; - subscribe?: (table: string) => Partial>; - getSwapByCommitment?: Mock; - getEpochByHeight?: Mock; - saveAssetsMetadata?: Mock; - getPricesForAsset?: Mock; - getAuction?: Mock; - getAuctionOutstandingReserves?: Mock; -} - -export interface AuctionMock { - auctionStateById: Mock; -} - -export interface TendermintMock { - broadcastTx?: Mock; - getTransaction?: Mock; - latestBlockHeight?: Mock; -} - -export interface ShieldedPoolMock { - assetMetadataById: Mock; -} - -export interface ViewServerMock { - fullViewingKey?: FullViewingKey; -} - -export interface MockQuerier { - auction?: AuctionMock; - tendermint?: TendermintMock; - shieldedPool?: ShieldedPoolMock; - stake?: StakeMock; -} - -export interface StakeMock { - validatorPenalty?: Mock; -} - -interface MockServicesInner { - indexedDb?: IndexedDbMock; - viewServer?: ViewServerMock; - querier?: MockQuerier; -} - -export interface MockServices { - getWalletServices?: Mock<[], Promise>; -} - -export interface MockApproverCtx { - get: Mock; -} - -export const testFullViewingKey = new FullViewingKey( - fullViewingKeyFromBech32m( - 'penumbrafullviewingkey1vzfytwlvq067g2kz095vn7sgcft47hga40atrg5zu2crskm6tyyjysm28qg5nth2fqmdf5n0q530jreumjlsrcxjwtfv6zdmfpe5kqsa5lg09', - ), -); - -export const testSpendKey = new SpendKey({ - inner: new Uint8Array([ - 204, 36, 107, 26, 105, 251, 139, 204, 14, 247, 98, 33, 115, 24, 32, 181, 165, 4, 171, 182, 171, - 238, 171, 186, 29, 152, 153, 61, 26, 149, 83, 166, - ]), -}); diff --git a/packages/services/src/view-service/address-by-index.test.ts b/packages/services/src/view-service/address-by-index.test.ts deleted file mode 100644 index 33c176a9..00000000 --- a/packages/services/src/view-service/address-by-index.test.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { beforeEach, describe, expect, test } from 'vitest'; -import { - AddressByIndexRequest, - AddressByIndexResponse, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; -import { createContextValues, createHandlerContext, HandlerContext } from '@connectrpc/connect'; -import { ViewService } from '@penumbra-zone/protobuf'; -import { addressByIndex } from './address-by-index'; -import { Address } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb'; -import { testFullViewingKey } from '../test-utils'; -import { fvkCtx } from '../ctx/full-viewing-key'; - -describe('AddressByIndex request handler', () => { - let mockCtx: HandlerContext; - - beforeEach(() => { - mockCtx = createHandlerContext({ - service: ViewService, - method: ViewService.methods.addressByIndex, - protocolName: 'mock', - requestMethod: 'MOCK', - url: '/mock', - contextValues: createContextValues().set(fvkCtx, () => Promise.resolve(testFullViewingKey)), - }); - }); - - test('should successfully get AddressByIndex with 0 index', async () => { - const addressByIndexResponse = await addressByIndex( - new AddressByIndexRequest({ addressIndex: { account: 0 } }), - mockCtx, - ); - expect(addressByIndexResponse.address).toBeInstanceOf(Address); - }); - - test('should successfully get AddressByIndex with no index', async () => { - const addressByIndexResponse = await addressByIndex(new AddressByIndexRequest(), mockCtx); - expect(addressByIndexResponse.address).toBeInstanceOf(Address); - }); - - test('addresses with different indexes should be different', async () => { - const index0Response = new AddressByIndexResponse( - await addressByIndex(new AddressByIndexRequest({ addressIndex: { account: 0 } }), mockCtx), - ); - const index1Response = new AddressByIndexResponse( - await addressByIndex(new AddressByIndexRequest({ addressIndex: { account: 1 } }), mockCtx), - ); - expect(index0Response.address?.equals(index1Response.address)).toBeFalsy(); - }); -}); diff --git a/packages/services/src/view-service/address-by-index.ts b/packages/services/src/view-service/address-by-index.ts deleted file mode 100644 index 3ab8dae3..00000000 --- a/packages/services/src/view-service/address-by-index.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type { Impl } from '.'; - -import { getAddressByIndex } from '@penumbra-zone/wasm/keys'; -import { fvkCtx } from '../ctx/full-viewing-key'; - -export const addressByIndex: Impl['addressByIndex'] = async (req, ctx) => { - const fvk = ctx.values.get(fvkCtx); - const address = getAddressByIndex(await fvk(), req.addressIndex?.account ?? 0); - return { address }; -}; diff --git a/packages/services/src/view-service/app-parameters.test.ts b/packages/services/src/view-service/app-parameters.test.ts deleted file mode 100644 index d82eb800..00000000 --- a/packages/services/src/view-service/app-parameters.test.ts +++ /dev/null @@ -1,110 +0,0 @@ -import { Mock, beforeEach, describe, expect, test, vi } from 'vitest'; -import { - AppParametersRequest, - AppParametersResponse, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; -import { createContextValues, createHandlerContext, HandlerContext } from '@connectrpc/connect'; -import { ViewService } from '@penumbra-zone/protobuf'; -import { servicesCtx } from '../ctx/prax'; -import { AppParameters } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/app/v1/app_pb'; -import { appParameters } from './app-parameters'; -import { IndexedDbMock, MockServices } from '../test-utils'; -import type { ServicesInterface } from '@penumbra-zone/types/services'; - -describe('AppParameters request handler', () => { - let mockServices: MockServices; - let mockIndexedDb: IndexedDbMock; - let mockCtx: HandlerContext; - let apSubNext: Mock; - - beforeEach(() => { - vi.resetAllMocks(); - - apSubNext = vi.fn(); - - const mockAppParametersSubscription = { - next: apSubNext, - [Symbol.asyncIterator]: () => mockAppParametersSubscription, - }; - - mockIndexedDb = { - getAppParams: vi.fn(), - subscribe: (table: string) => { - if (table === 'APP_PARAMETERS') return mockAppParametersSubscription; - throw new Error('Table not supported'); - }, - }; - - mockServices = { - getWalletServices: vi.fn(() => - Promise.resolve({ indexedDb: mockIndexedDb }), - ) as MockServices['getWalletServices'], - }; - mockCtx = createHandlerContext({ - service: ViewService, - method: ViewService.methods.appParameters, - protocolName: 'mock', - requestMethod: 'MOCK', - url: '/mock', - contextValues: createContextValues().set(servicesCtx, () => - Promise.resolve(mockServices as unknown as ServicesInterface), - ), - }); - }); - - test('should successfully get appParameters when idb has them', async () => { - mockIndexedDb.getAppParams?.mockResolvedValue(testData); - const appParameterResponse = new AppParametersResponse( - await appParameters(new AppParametersRequest(), mockCtx), - ); - expect(appParameterResponse.parameters?.equals(testData)).toBeTruthy(); - }); - - test('should wait for appParameters when idb has none', async () => { - mockIndexedDb.getAppParams?.mockResolvedValue(undefined); - apSubNext.mockResolvedValueOnce({ - value: { value: new AppParametersRequest(), table: 'APP_PARAMETERS' }, - }); - await expect(appParameters(new AppParametersRequest(), mockCtx)).resolves.toBeTruthy(); - }); -}); - -const testData = new AppParameters({ - chainId: 'penumbra-testnet-titan', - sctParams: { - epochDuration: 719n, - }, - shieldedPoolParams: { - fixedFmdParams: { asOfBlockHeight: 1n, precisionBits: 0 }, - }, - communityPoolParams: { - communityPoolSpendProposalsEnabled: true, - }, - governanceParams: { - proposalVotingBlocks: 17280n, - proposalDepositAmount: { - lo: 10000000n, - }, - proposalValidQuorum: '40/100', - proposalPassThreshold: '50/100', - proposalSlashThreshold: '80/100', - }, - ibcParams: { - ibcEnabled: true, - inboundIcs20TransfersEnabled: true, - outboundIcs20TransfersEnabled: true, - }, - stakeParams: { - unbondingEpochs: 2n, - activeValidatorLimit: 80n, - baseRewardRate: 30000n, - slashingPenaltyMisbehavior: 10000000n, - slashingPenaltyDowntime: 10000n, - signedBlocksWindowLen: 10000n, - missedBlocksMaximum: 9500n, - }, - feeParams: {}, - distributionsParams: { - stakingIssuancePerBlock: 1n, - }, -}); diff --git a/packages/services/src/view-service/app-parameters.ts b/packages/services/src/view-service/app-parameters.ts deleted file mode 100644 index 692406e2..00000000 --- a/packages/services/src/view-service/app-parameters.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { AppParameters } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/app/v1/app_pb'; -import type { Impl } from '.'; -import { servicesCtx } from '../ctx/prax'; - -export const appParameters: Impl['appParameters'] = async (_, ctx) => { - const services = await ctx.values.get(servicesCtx)(); - const { indexedDb } = await services.getWalletServices(); - - const subscription = indexedDb.subscribe('APP_PARAMETERS'); - const parameters = await indexedDb.getAppParams(); - if (parameters) return { parameters }; - for await (const update of subscription) - return { parameters: AppParameters.fromJson(update.value) }; - - throw new Error('App parameters not available'); -}; diff --git a/packages/services/src/view-service/asset-metadata-by-id.test.ts b/packages/services/src/view-service/asset-metadata-by-id.test.ts deleted file mode 100644 index 0a3794ce..00000000 --- a/packages/services/src/view-service/asset-metadata-by-id.test.ts +++ /dev/null @@ -1,126 +0,0 @@ -import { beforeEach, describe, expect, test, vi } from 'vitest'; -import { - AssetMetadataByIdRequest, - AssetMetadataByIdResponse, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; -import { createContextValues, createHandlerContext, HandlerContext } from '@connectrpc/connect'; -import { ViewService } from '@penumbra-zone/protobuf'; -import { servicesCtx } from '../ctx/prax'; -import { IndexedDbMock, MockServices, ShieldedPoolMock } from '../test-utils'; -import { - AssetId, - Metadata, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; -import { assetMetadataById } from './asset-metadata-by-id'; -import type { ServicesInterface } from '@penumbra-zone/types/services'; - -describe('AssetMetadataById request handler', () => { - let mockServices: MockServices; - let mockIndexedDb: IndexedDbMock; - let mockCtx: HandlerContext; - let mockShieldedPool: ShieldedPoolMock; - let request: AssetMetadataByIdRequest; - - beforeEach(() => { - vi.resetAllMocks(); - - mockIndexedDb = { - getAssetsMetadata: vi.fn(), - saveAssetsMetadata: vi.fn(), - }; - mockShieldedPool = { - assetMetadataById: vi.fn(), - }; - mockServices = { - getWalletServices: vi.fn(() => - Promise.resolve({ - indexedDb: mockIndexedDb, - querier: { - shieldedPool: mockShieldedPool, - }, - }), - ) as MockServices['getWalletServices'], - }; - mockCtx = createHandlerContext({ - service: ViewService, - method: ViewService.methods.assetMetadataById, - protocolName: 'mock', - requestMethod: 'MOCK', - url: '/mock', - contextValues: createContextValues().set(servicesCtx, () => - Promise.resolve(mockServices as unknown as ServicesInterface), - ), - }); - - request = new AssetMetadataByIdRequest({ - assetId: assetId, - }); - }); - - test('should successfully respond with metadata when idb record is present', async () => { - mockIndexedDb.getAssetsMetadata?.mockResolvedValue(metadataFromIdb); - const metadataByIdResponse = new AssetMetadataByIdResponse( - await assetMetadataById(request, mockCtx), - ); - expect(metadataByIdResponse.equals({ denomMetadata: metadataFromIdb })).toBeTruthy(); - }); - - test('should successfully respond with metadata when idb record is absent, but metadata is available from remote rpc', async () => { - mockIndexedDb.getAssetsMetadata?.mockResolvedValue(undefined); - mockShieldedPool.assetMetadataById.mockResolvedValueOnce(metadataFromNode); - const metadataByIdResponse = new AssetMetadataByIdResponse( - await assetMetadataById(request, mockCtx), - ); - expect(metadataByIdResponse.equals({ denomMetadata: metadataFromNode })).toBeTruthy(); - }); - - test('should successfully respond even when no metadata is available', async () => { - mockIndexedDb.getAssetsMetadata?.mockResolvedValue(undefined); - mockShieldedPool.assetMetadataById.mockResolvedValueOnce(undefined); - const metadataByIdResponse = new AssetMetadataByIdResponse( - await assetMetadataById(request, mockCtx), - ); - expect(metadataByIdResponse.equals({})).toBeTruthy(); - }); - - test('should fail if assetId is missing in request', async () => { - await expect(assetMetadataById(new AssetMetadataByIdRequest(), mockCtx)).rejects.toThrow( - 'No asset id passed in request', - ); - }); -}); - -const assetId = AssetId.fromJson({ - inner: 'nwPDkQq3OvLnBwGTD+nmv1Ifb2GEmFCgNHrU++9BsRE=', -}); - -const metadataFromNode = Metadata.fromJson({ - description: '', - denomUnits: [ - { denom: 'gm', exponent: 9, aliases: [] }, - { denom: 'mgm', exponent: 3, aliases: [] }, - { denom: 'ugm', exponent: 0, aliases: [] }, - ], - base: 'ugm', - display: 'gm', - name: '', - symbol: '', - penumbraAssetId: { - inner: 'nwPDkQq3OvLnBwGTD+nmv1Ifb2GEmFCgNHrU++9BsRE=', - }, -}); -const metadataFromIdb = Metadata.fromJson({ - description: '', - denomUnits: [ - { denom: 'gn', exponent: 6, aliases: [] }, - { denom: 'mgn', exponent: 3, aliases: [] }, - { denom: 'ugn', exponent: 0, aliases: [] }, - ], - base: 'ugn', - display: 'gn', - name: '', - symbol: '', - penumbraAssetId: { - inner: 'nwPDkQq3OvLnBwGTD+nmv1Ifb2GEmFCgNHrU++9BsRE=', - }, -}); diff --git a/packages/services/src/view-service/asset-metadata-by-id.ts b/packages/services/src/view-service/asset-metadata-by-id.ts deleted file mode 100644 index 32405825..00000000 --- a/packages/services/src/view-service/asset-metadata-by-id.ts +++ /dev/null @@ -1,29 +0,0 @@ -import type { Impl } from '.'; -import { servicesCtx } from '../ctx/prax'; -import { assetPatterns } from '@penumbra-zone/types/assets'; - -export const assetMetadataById: Impl['assetMetadataById'] = async ({ assetId }, ctx) => { - if (!assetId) throw new Error('No asset id passed in request'); - - if (!assetId.altBaseDenom && !assetId.altBech32m && !assetId.inner.length) - throw new Error( - 'Either `inner`, `altBaseDenom`, or `altBech32m` must be set on the asset ID passed in the `assetMetadataById` request', - ); - - const services = await ctx.values.get(servicesCtx)(); - const { indexedDb, querier } = await services.getWalletServices(); - - const localMetadata = await indexedDb.getAssetsMetadata(assetId); - if (localMetadata) return { denomMetadata: localMetadata }; - - const remoteMetadata = await querier.shieldedPool.assetMetadataById(assetId); - - const isIbcAsset = remoteMetadata && assetPatterns.ibc.matches(remoteMetadata.display); - - if (remoteMetadata && !isIbcAsset) { - void indexedDb.saveAssetsMetadata(remoteMetadata); - return { denomMetadata: remoteMetadata }; - } - - return { denomMetadata: undefined }; -}; diff --git a/packages/services/src/view-service/assets.test.ts b/packages/services/src/view-service/assets.test.ts deleted file mode 100644 index dce61453..00000000 --- a/packages/services/src/view-service/assets.test.ts +++ /dev/null @@ -1,290 +0,0 @@ -import { - Denom, - Metadata, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; -import { - AssetsRequest, - AssetsResponse, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; -import { ViewService } from '@penumbra-zone/protobuf'; -import { createContextValues, createHandlerContext, HandlerContext } from '@connectrpc/connect'; -import { beforeEach, describe, expect, test, vi } from 'vitest'; -import { servicesCtx } from '../ctx/prax'; -import { assets } from './assets'; -import { IndexedDbMock, MockServices } from '../test-utils'; -import type { ServicesInterface } from '@penumbra-zone/types/services'; - -describe('Assets request handler', () => { - let req: AssetsRequest; - let mockServices: MockServices; - let mockCtx: HandlerContext; - - beforeEach(() => { - vi.resetAllMocks(); - - const mockIterateMetadata = { - next: vi.fn(), - [Symbol.asyncIterator]: () => mockIterateMetadata, - }; - - const mockIndexedDb: IndexedDbMock = { - iterateAssetsMetadata: () => mockIterateMetadata, - }; - - mockServices = { - getWalletServices: vi.fn(() => - Promise.resolve({ indexedDb: mockIndexedDb }), - ) as MockServices['getWalletServices'], - }; - - mockCtx = createHandlerContext({ - service: ViewService, - method: ViewService.methods.assets, - protocolName: 'mock', - requestMethod: 'MOCK', - url: '/mock', - contextValues: createContextValues().set(servicesCtx, () => - Promise.resolve(mockServices as unknown as ServicesInterface), - ), - }); - - for (const record of testData) { - mockIterateMetadata.next.mockResolvedValueOnce({ - value: record, - }); - } - mockIterateMetadata.next.mockResolvedValueOnce({ - done: true, - }); - req = new AssetsRequest({}); - }); - - test('empty req return all asset', async () => { - const responses: AssetsResponse[] = []; - for await (const res of assets(req, mockCtx)) { - responses.push(new AssetsResponse(res)); - } - expect(responses.length).toBe(8); - }); - - test('req with filtered as false return all asset', async () => { - const responses: AssetsResponse[] = []; - const req = new AssetsRequest({ - filtered: false, - }); - for await (const res of assets(req, mockCtx)) { - responses.push(new AssetsResponse(res)); - } - expect(responses.length).toBe(8); - }); - - test('returns only matching denominations when `filtered` is `true`', async () => { - const responses: AssetsResponse[] = []; - const req = new AssetsRequest({ - filtered: true, - includeLpNfts: true, - }); - for await (const res of assets(req, mockCtx)) { - responses.push(new AssetsResponse(res)); - } - expect(responses.length).toBe(4); - }); - - test('req with filtered as false and includeLpNfts as true returns all assets', async () => { - const responses: AssetsResponse[] = []; - const req = new AssetsRequest({ - filtered: false, - includeLpNfts: true, - }); - for await (const res of assets(req, mockCtx)) { - responses.push(new AssetsResponse(res)); - } - expect(responses.length).toBe(8); - }); - - test('includeLpNfts as true returns all LpNfts assets', async () => { - const responses: AssetsResponse[] = []; - const req = new AssetsRequest({ - filtered: true, - includeLpNfts: true, - }); - for await (const res of assets(req, mockCtx)) { - responses.push(new AssetsResponse(res)); - } - expect(responses.length).toBe(4); - }); - - test('includeDelegationTokens as true returns all Delegation Tokens', async () => { - const responses: AssetsResponse[] = []; - const req = new AssetsRequest({ - filtered: true, - includeDelegationTokens: true, - }); - for await (const res of assets(req, mockCtx)) { - responses.push(new AssetsResponse(res)); - } - expect(responses.length).toBe(1); - }); - - test('includeSpecificDenominations include penumbra return only penumbra asset', async () => { - const responses: AssetsResponse[] = []; - const req = new AssetsRequest({ - filtered: true, - includeSpecificDenominations: [ - new Denom({ - denom: 'penumbra', - }), - ], - }); - for await (const res of assets(req, mockCtx)) { - responses.push(new AssetsResponse(res)); - } - expect(responses.length).toBe(1); - }); -}); - -const testData = [ - Metadata.fromJson({ - description: '', - denomUnits: [ - { - denom: 'lpnft_closed_plpid1fkf3tlv500vgzwc6dkc7g9wnuv6rzezhefefdywq5tt4lyl97rgsd6j689', - exponent: 0, - aliases: [], - }, - ], - base: 'lpnft_closed_plpid1fkf3tlv500vgzwc6dkc7g9wnuv6rzezhefefdywq5tt4lyl97rgsd6j689', - display: 'lpnft_closed_plpid1fkf3tlv500vgzwc6dkc7g9wnuv6rzezhefefdywq5tt4lyl97rgsd6j689', - name: '', - symbol: '', - penumbraAssetId: { - inner: '+q9m+F1um57vD6mtzpp4zsr4uY6llawZK4osfpNimQc=', - }, - }), - Metadata.fromJson({ - description: '', - denomUnits: [ - { denom: 'gm', exponent: 6, aliases: [] }, - { denom: 'mgm', exponent: 3, aliases: [] }, - { denom: 'ugm', exponent: 0, aliases: [] }, - ], - base: 'ugm', - display: 'gm', - name: '', - symbol: '', - penumbraAssetId: { - inner: 'HW2Eq3UZVSBttoUwUi/MUtE7rr2UU7/UH500byp7OAc=', - }, - }), - Metadata.fromJson({ - description: '', - denomUnits: [ - { - denom: 'lpnft_withdrawn_plpid1fkf3tlv500vgzwc6dkc7g9wnuv6rzezhefefdywq5tt4lyl97rgsd6j689', - exponent: 0, - aliases: [], - }, - ], - base: 'lpnft_withdrawn_plpid1fkf3tlv500vgzwc6dkc7g9wnuv6rzezhefefdywq5tt4lyl97rgsd6j689', - display: 'lpnft_withdrawn_plpid1fkf3tlv500vgzwc6dkc7g9wnuv6rzezhefefdywq5tt4lyl97rgsd6j689', - name: '', - symbol: '', - penumbraAssetId: { - inner: 'IYAlwlH0ld1wsRLlnYyl4ItsVeukLp4e7/U/Z+6opxA=', - }, - }), - Metadata.fromJson({ - description: '', - denomUnits: [ - { denom: 'penumbra', exponent: 6, aliases: [] }, - { denom: 'mpenumbra', exponent: 3, aliases: [] }, - { denom: 'upenumbra', exponent: 0, aliases: [] }, - ], - base: 'upenumbra', - display: 'penumbra', - name: '', - symbol: '', - penumbraAssetId: { - inner: 'KeqcLzNx9qSH5+lcJHBB9KNW+YPrBk5dKzvPMiypahA=', - }, - }), - Metadata.fromJson({ - description: '', - denomUnits: [ - { - denom: 'lpnft_opened_plpid1fkf3tlv500vgzwc6dkc7g9wnuv6rzezhefefdywq5tt4lyl97rgsd6j689', - exponent: 0, - aliases: [], - }, - ], - base: 'lpnft_opened_plpid1fkf3tlv500vgzwc6dkc7g9wnuv6rzezhefefdywq5tt4lyl97rgsd6j689', - display: 'lpnft_opened_plpid1fkf3tlv500vgzwc6dkc7g9wnuv6rzezhefefdywq5tt4lyl97rgsd6j689', - name: '', - symbol: '', - penumbraAssetId: { - inner: 'ZagbowbVlBeZi5bMUZ3jCf5KDaOipWMSP7iVM/O+PQc=', - }, - }), - Metadata.fromJson({ - description: '', - denomUnits: [ - { - denom: - 'delegation_penumbravalid1grwuc89mjkjfjnpey0qaxt0kzy70mhqf5enwzr5tp77jy6mrxy9swy78ph', - exponent: 6, - aliases: [], - }, - { - denom: - 'mdelegation_penumbravalid1grwuc89mjkjfjnpey0qaxt0kzy70mhqf5enwzr5tp77jy6mrxy9swy78ph', - exponent: 3, - aliases: [], - }, - { - denom: - 'udelegation_penumbravalid1grwuc89mjkjfjnpey0qaxt0kzy70mhqf5enwzr5tp77jy6mrxy9swy78ph', - exponent: 0, - aliases: [], - }, - ], - base: 'udelegation_penumbravalid1grwuc89mjkjfjnpey0qaxt0kzy70mhqf5enwzr5tp77jy6mrxy9swy78ph', - display: 'delegation_penumbravalid1grwuc89mjkjfjnpey0qaxt0kzy70mhqf5enwzr5tp77jy6mrxy9swy78ph', - name: '', - symbol: '', - penumbraAssetId: { - inner: 'hByoL6SVVg9HOwBcMy3TiiJ3Z+OTjhQVi5APR020BAM=', - }, - }), - Metadata.fromJson({ - description: '', - denomUnits: [ - { - denom: 'lpnft_claimed_plpid1fkf3tlv500vgzwc6dkc7g9wnuv6rzezhefefdywq5tt4lyl97rgsd6j689', - exponent: 0, - aliases: [], - }, - ], - base: 'lpnft_claimed_plpid1fkf3tlv500vgzwc6dkc7g9wnuv6rzezhefefdywq5tt4lyl97rgsd6j689', - display: 'lpnft_claimed_plpid1fkf3tlv500vgzwc6dkc7g9wnuv6rzezhefefdywq5tt4lyl97rgsd6j689', - name: '', - symbol: '', - penumbraAssetId: { - inner: 'mNS0j9YDbrEsQLitqlA9aDJq1NHFJRgYQQCZMgBjlgM=', - }, - }), - Metadata.fromJson({ - description: '', - denomUnits: [ - { denom: 'gn', exponent: 6, aliases: [] }, - { denom: 'mgn', exponent: 3, aliases: [] }, - { denom: 'ugn', exponent: 0, aliases: [] }, - ], - base: 'ugn', - display: 'gn', - name: '', - symbol: '', - penumbraAssetId: { - inner: 'nwPDkQq3OvLnBwGTD+nmv1Ifb2GEmFCgNHrU++9BsRE=', - }, - }), -]; diff --git a/packages/services/src/view-service/assets.ts b/packages/services/src/view-service/assets.ts deleted file mode 100644 index 8e6bfaef..00000000 --- a/packages/services/src/view-service/assets.ts +++ /dev/null @@ -1,53 +0,0 @@ -import type { Impl } from '.'; -import { servicesCtx } from '../ctx/prax'; -import { assetPatterns, RegexMatcher } from '@penumbra-zone/types/assets'; - -export const assets: Impl['assets'] = async function* (req, ctx) { - const services = await ctx.values.get(servicesCtx)(); - const { indexedDb } = await services.getWalletServices(); - - const { - filtered, - includeLpNfts, - includeProposalNfts, - includeDelegationTokens, - includeUnbondingTokens, - includeVotingReceiptTokens, - includeSpecificDenominations, - } = req; - - const patterns: { - includeReq: boolean; - pattern: RegexMatcher; - }[] = [ - { - includeReq: includeLpNfts, - pattern: assetPatterns.lpNft, - }, - { - includeReq: includeDelegationTokens, - pattern: assetPatterns.delegationToken, - }, - { - includeReq: includeProposalNfts, - pattern: assetPatterns.proposalNft, - }, - { - includeReq: includeUnbondingTokens, - pattern: assetPatterns.unbondingToken, - }, - { - includeReq: includeVotingReceiptTokens, - pattern: assetPatterns.votingReceipt, - }, - ...includeSpecificDenominations.map(d => ({ - includeReq: true, - pattern: new RegexMatcher(new RegExp(`^${d.denom}$`)), - })), - ].filter(i => i.includeReq); - - for await (const metadata of indexedDb.iterateAssetsMetadata()) { - if (filtered && !patterns.find(p => p.pattern.matches(metadata.display))) continue; - yield { denomMetadata: metadata }; - } -}; diff --git a/packages/services/src/view-service/auctions.test.ts b/packages/services/src/view-service/auctions.test.ts deleted file mode 100644 index be7c673a..00000000 --- a/packages/services/src/view-service/auctions.test.ts +++ /dev/null @@ -1,251 +0,0 @@ -import Array from '@penumbra-zone/polyfills/Array.fromAsync'; -import { beforeEach, describe, expect, it, vi } from 'vitest'; -import { auctions } from './auctions'; -import { - AuctionsRequest, - AuctionsResponse, - BalancesResponse, - SpendableNoteRecord, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; -import { - AuctionId, - DutchAuction, - DutchAuctionDescription, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/auction/v1/auction_pb'; -import { bech32mAuctionId } from '@penumbra-zone/bech32m/pauctid'; -import { ViewService } from '@penumbra-zone/protobuf'; -import { ServicesInterface } from '@penumbra-zone/types/services'; -import { HandlerContext, createContextValues, createHandlerContext } from '@connectrpc/connect'; -import { servicesCtx } from '../ctx/prax'; -import { IndexedDbMock, MockQuerier, MockServices } from '../test-utils'; -import { StateCommitment } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/crypto/tct/v1/tct_pb'; -import { Value } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; -import { Amount } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/num/v1/num_pb'; - -const AUCTION_ID_1 = new AuctionId({ inner: new Uint8Array(Array(32).fill(1)) }); -const BECH32M_AUCTION_ID_1 = bech32mAuctionId(AUCTION_ID_1); -const MOCK_AUCTION_1 = new DutchAuctionDescription({ - startHeight: 0n, - endHeight: 120n, -}); - -const AUCTION_ID_2 = new AuctionId({ inner: new Uint8Array(Array(32).fill(2)) }); -const BECH32M_AUCTION_ID_2 = bech32mAuctionId(AUCTION_ID_2); -const MOCK_AUCTION_2 = new DutchAuctionDescription({ - startHeight: 120n, - endHeight: 240n, -}); - -const AUCTION_ID_3 = new AuctionId({ inner: new Uint8Array(Array(32).fill(3)) }); -const BECH32M_AUCTION_ID_3 = bech32mAuctionId(AUCTION_ID_3); -const MOCK_AUCTION_3 = new DutchAuctionDescription({ - startHeight: 240n, - endHeight: 360n, -}); - -const AUCTION_ID_4 = new AuctionId({ inner: new Uint8Array(Array(32).fill(4)) }); -const MOCK_AUCTION_4 = new DutchAuctionDescription({ - startHeight: 360n, - endHeight: 480n, -}); - -const MOCK_SPENDABLE_NOTE_RECORD = new SpendableNoteRecord({ - heightCreated: 1234n, -}); - -vi.mock('./balances', () => ({ - *balances() { - const auctionsThisUserControls = [ - BECH32M_AUCTION_ID_1, - BECH32M_AUCTION_ID_2, - BECH32M_AUCTION_ID_3, - ]; - for (const bech32mAuctionId of auctionsThisUserControls) { - yield new BalancesResponse({ - balanceView: { - valueView: { - case: 'knownAssetId', - value: { - amount: { hi: 0n, lo: 1n }, - metadata: { - base: `auctionnft_0_${bech32mAuctionId}`, - display: `auctionnft_0_${bech32mAuctionId}`, - denomUnits: [{ denom: `auctionnft_0_${bech32mAuctionId}`, exponent: 0 }], - penumbraAssetId: { inner: new Uint8Array([0, 1, 2, 3]) }, - symbol: 'auction(abcd1234...)', - }, - }, - }, - }, - }); - } - }, -})); - -const TEST_DATA = [ - { - id: AUCTION_ID_1, - value: { - auction: MOCK_AUCTION_1, - noteCommitment: new StateCommitment({ inner: new Uint8Array([0, 1, 2, 3]) }), - seqNum: 0n, - }, - }, - { - id: AUCTION_ID_2, - value: { - auction: MOCK_AUCTION_2, - noteCommitment: new StateCommitment({ inner: new Uint8Array([0, 1, 2, 3]) }), - seqNum: 1n, - }, - }, - { - id: AUCTION_ID_3, - value: { - auction: MOCK_AUCTION_3, - noteCommitment: new StateCommitment({ inner: new Uint8Array([0, 1, 2, 3]) }), - seqNum: 2n, - }, - }, - { - id: AUCTION_ID_4, - value: { - auction: MOCK_AUCTION_4, - noteCommitment: new StateCommitment({ inner: new Uint8Array([0, 1, 2, 3]) }), - seqNum: 0n, - }, - }, -]; - -describe('Auctions request handler', () => { - let mockCtx: HandlerContext; - let mockIndexedDb: IndexedDbMock; - let mockQuerier: MockQuerier; - - beforeEach(() => { - vi.resetAllMocks(); - - mockIndexedDb = { - getAuction: vi.fn((auctionId: AuctionId) => - Promise.resolve(TEST_DATA.find(({ id }) => id.equals(auctionId))?.value), - ), - getSpendableNoteByCommitment: vi.fn().mockResolvedValue(MOCK_SPENDABLE_NOTE_RECORD), - getAuctionOutstandingReserves: vi.fn().mockResolvedValue(undefined), - }; - - mockQuerier = { - auction: { - auctionStateById: vi.fn().mockResolvedValue(new DutchAuction({ state: { seq: 1234n } })), - }, - }; - - const mockServices = () => - Promise.resolve({ - getWalletServices: vi.fn(() => - Promise.resolve({ - indexedDb: mockIndexedDb, - querier: mockQuerier, - }), - ) as MockServices['getWalletServices'], - } as unknown as ServicesInterface); - - mockCtx = createHandlerContext({ - service: ViewService, - method: ViewService.methods.auctions, - protocolName: 'mock', - requestMethod: 'MOCK', - url: '/mock', - contextValues: createContextValues().set(servicesCtx, mockServices), - }); - }); - - it('returns auctions', async () => { - const req = new AuctionsRequest(); - const results = await Array.fromAsync(auctions(req, mockCtx)); - - expect(results[0]).toEqual( - new AuctionsResponse({ - id: AUCTION_ID_1, - auction: { - typeUrl: DutchAuction.typeName, - value: new DutchAuction({ description: MOCK_AUCTION_1, state: { seq: 0n } }).toBinary(), - }, - noteRecord: MOCK_SPENDABLE_NOTE_RECORD, - }), - ); - }); - - it('excludes auctions not controlled by the current user', async () => { - const req = new AuctionsRequest(); - const results = await Array.fromAsync(auctions(req, mockCtx)); - - results.forEach(result => { - expect(result).not.toEqual( - expect.objectContaining({ - // Auction 4 is included in the response from IndexedDB, but not in - // the user's balances - id: AUCTION_ID_4, - }), - ); - }); - }); - - it('excludes inactive auctions by default', async () => { - const req = new AuctionsRequest(); - const results = await Array.fromAsync(auctions(req, mockCtx)); - - expect(results.some(result => new AuctionId(result.id).equals(AUCTION_ID_2))).toBe(false); - expect(results.some(result => new AuctionId(result.id).equals(AUCTION_ID_3))).toBe(false); - }); - - it('includes inactive auctions if `includeInactive` is `true`', async () => { - const req = new AuctionsRequest({ includeInactive: true }); - const results = await Array.fromAsync(auctions(req, mockCtx)); - - expect(results.some(result => new AuctionId(result.id).equals(AUCTION_ID_2))).toBe(true); - expect(results.some(result => new AuctionId(result.id).equals(AUCTION_ID_3))).toBe(true); - }); - - it('includes the latest state from the fullnode if `queryLatestState` is `true`', async () => { - expect.hasAssertions(); - - const req = new AuctionsRequest({ queryLatestState: true }); - const results = await Array.fromAsync(auctions(req, mockCtx)); - - results.forEach(result => { - const dutchAuction = DutchAuction.fromBinary(result.auction!.value!); - - expect(dutchAuction.state?.seq).toBe(1234n); - }); - }); - - it('includes the outstanding reserves if any exist in the database (i.e., for an ended auction)', async () => { - expect.hasAssertions(); - - mockIndexedDb.getAuctionOutstandingReserves?.mockImplementation((auctionId: AuctionId) => { - if (auctionId.equals(AUCTION_ID_2)) { - return { - input: new Value({ amount: { hi: 0n, lo: 1234n } }), - output: new Value({ amount: { hi: 0n, lo: 5678n } }), - }; - } - - return undefined; - }); - - const req = new AuctionsRequest({ includeInactive: true }); - const results = await Array.fromAsync(auctions(req, mockCtx)); - - results.forEach(result => { - const dutchAuction = DutchAuction.fromBinary(result.auction!.value!); - - if (AUCTION_ID_2.equals(new AuctionId(result.id))) { - expect(dutchAuction.state?.inputReserves).toEqual(new Amount({ hi: 0n, lo: 1234n })); - expect(dutchAuction.state?.outputReserves).toEqual(new Amount({ hi: 0n, lo: 5678n })); - } else { - expect(dutchAuction.state?.inputReserves).toBeUndefined(); - expect(dutchAuction.state?.outputReserves).toBeUndefined(); - } - }); - }); -}); diff --git a/packages/services/src/view-service/auctions.ts b/packages/services/src/view-service/auctions.ts deleted file mode 100644 index b96e6d81..00000000 --- a/packages/services/src/view-service/auctions.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { - AuctionsResponse, - BalancesRequest, - BalancesResponse, - SpendableNoteRecord, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; -import { Impl } from '.'; -import { - AuctionId, - DutchAuction, - DutchAuctionState, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/auction/v1/auction_pb'; -import { balances } from './balances'; -import { getDisplayDenomFromView } from '@penumbra-zone/getters/value-view'; -import { ValueView } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; -import { assetPatterns } from '@penumbra-zone/types/assets'; -import { Any, PartialMessage } from '@bufbuild/protobuf'; -import { servicesCtx } from '../ctx/prax'; -import { auctionIdFromBech32 } from '@penumbra-zone/bech32m/pauctid'; -import { HandlerContext } from '@connectrpc/connect'; -import { AddressIndex } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb'; - -const getBech32mAuctionId = ( - balancesResponse: PartialMessage, -): string | undefined => { - if (!balancesResponse.balanceView) return; - - const captureGroups = assetPatterns.auctionNft.capture( - getDisplayDenomFromView(new ValueView(balancesResponse.balanceView)), - ); - - if (!captureGroups) return; - - return captureGroups.auctionId; -}; - -const isInactive = (seqNum?: bigint) => (seqNum === undefined ? false : seqNum > 0n); - -const iterateAuctionsThisUserControls = async function* ( - ctx: HandlerContext, - accountFilter?: AddressIndex, -) { - for await (const balancesResponse of balances(new BalancesRequest({ accountFilter }), ctx)) { - const auctionId = getBech32mAuctionId(balancesResponse); - if (auctionId) yield auctionId; - } -}; - -export const auctions: Impl['auctions'] = async function* (req, ctx) { - const { includeInactive, queryLatestState, accountFilter } = req; - - const services = await ctx.values.get(servicesCtx)(); - const { indexedDb, querier } = await services.getWalletServices(); - - for await (const auctionId of iterateAuctionsThisUserControls(ctx, accountFilter)) { - const id = new AuctionId(auctionIdFromBech32(auctionId)); - const value = await indexedDb.getAuction(id); - if (!includeInactive && isInactive(value.seqNum)) continue; - - let noteRecord: SpendableNoteRecord | undefined; - if (value.noteCommitment) { - noteRecord = await indexedDb.getSpendableNoteByCommitment(value.noteCommitment); - } - - let state: DutchAuctionState | undefined; - if (queryLatestState) { - const auction = await querier.auction.auctionStateById(id); - state = auction?.state; - } - - let auction: Any | undefined; - if (!!value.auction || state) { - const outstandingReserves = await indexedDb.getAuctionOutstandingReserves(id); - auction = new Any({ - typeUrl: DutchAuction.typeName, - value: new DutchAuction({ - state: state ?? { - seq: value.seqNum, - inputReserves: outstandingReserves?.input.amount, - outputReserves: outstandingReserves?.output.amount, - }, - description: value.auction, - }).toBinary(), - }); - } - - yield new AuctionsResponse({ - id, - auction, - noteRecord, - }); - } -}; diff --git a/packages/services/src/view-service/authorize-and-build.ts b/packages/services/src/view-service/authorize-and-build.ts deleted file mode 100644 index 1bf8bd34..00000000 --- a/packages/services/src/view-service/authorize-and-build.ts +++ /dev/null @@ -1,28 +0,0 @@ -import type { Impl } from '.'; -import { servicesCtx } from '../ctx/prax'; -import { optimisticBuild } from './util/build-tx'; -import { custodyAuthorize } from './util/custody-authorize'; -import { getWitness } from '@penumbra-zone/wasm/build'; -import { Code, ConnectError } from '@connectrpc/connect'; -import { fvkCtx } from '../ctx/full-viewing-key'; - -export const authorizeAndBuild: Impl['authorizeAndBuild'] = async function* ( - { transactionPlan }, - ctx, -) { - const services = await ctx.values.get(servicesCtx)(); - if (!transactionPlan) throw new ConnectError('No tx plan in request', Code.InvalidArgument); - - const { indexedDb } = await services.getWalletServices(); - const fvk = ctx.values.get(fvkCtx); - - const sct = await indexedDb.getStateCommitmentTree(); - const witnessData = getWitness(transactionPlan, sct); - - yield* optimisticBuild( - transactionPlan, - witnessData, - custodyAuthorize(ctx, transactionPlan), - await fvk(), - ); -}; diff --git a/packages/services/src/view-service/balances.test.ts b/packages/services/src/view-service/balances.test.ts deleted file mode 100644 index 8c24aaac..00000000 --- a/packages/services/src/view-service/balances.test.ts +++ /dev/null @@ -1,410 +0,0 @@ -import { servicesCtx } from '../ctx/prax'; -import { balances } from './balances'; - -import { ViewService } from '@penumbra-zone/protobuf'; - -import { AddressIndex } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb'; -import { - BalancesRequest, - BalancesResponse, - SpendableNoteRecord, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; - -import { createContextValues, createHandlerContext, HandlerContext } from '@connectrpc/connect'; -import { beforeEach, describe, expect, test, vi } from 'vitest'; -import type { ServicesInterface } from '@penumbra-zone/types/services'; -import { IndexedDbMock, MockServices, TendermintMock, testFullViewingKey } from '../test-utils'; -import { - AssetId, - EquivalentValue, - EstimatedPrice, - Metadata, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; -import { - getAmount, - getAssetIdFromValueView, - getEquivalentValues, - getMetadata, -} from '@penumbra-zone/getters/value-view'; -import { getAddressIndex } from '@penumbra-zone/getters/address-view'; -import { base64ToUint8Array } from '@penumbra-zone/types/base64'; -import { multiplyAmountByNumber } from '@penumbra-zone/types/amount'; -import { fvkCtx } from '../ctx/full-viewing-key'; - -const assertOnlyUniqueAssetIds = (responses: BalancesResponse[], accountId: number) => { - const account0Res = responses.filter( - r => getAddressIndex(r.accountAddress).account === accountId, - ); - const uniqueAssetIds = account0Res.reduce((collection, res) => { - collection.add(getAssetIdFromValueView(res.balanceView)); - return collection; - }, new Set()); - - expect(account0Res.length).toBe(uniqueAssetIds.size); -}; - -describe('Balances request handler', () => { - let req: BalancesRequest; - let mockServices: MockServices; - let mockCtx: HandlerContext; - let mockIndexedDb: IndexedDbMock; - let mockTendermint: TendermintMock; - - beforeEach(() => { - vi.resetAllMocks(); - - const mockIterateSpendableNotes = { - next: vi.fn(), - [Symbol.asyncIterator]: () => mockIterateSpendableNotes, - }; - - mockIndexedDb = { - getAssetsMetadata: vi.fn(), - getPricesForAsset: vi.fn(), - getFullSyncHeight: vi.fn(() => Promise.resolve()), - iterateSpendableNotes: () => mockIterateSpendableNotes, - }; - - const mockShieldedPool = { - assetMetadata: vi.fn(), - }; - - mockTendermint = { - latestBlockHeight: vi.fn(() => Promise.resolve()), - }; - - mockServices = { - // @ts-expect-error TODO: Improve mocking types - getWalletServices: vi.fn(() => - Promise.resolve({ - indexedDb: mockIndexedDb, - querier: { - shieldedPool: mockShieldedPool, - tendermint: mockTendermint, - }, - }), - ) as MockServices['getWalletServices'], - }; - - mockCtx = createHandlerContext({ - service: ViewService, - method: ViewService.methods.balances, - protocolName: 'mock', - requestMethod: 'MOCK', - url: '/mock', - contextValues: createContextValues() - .set(servicesCtx, () => Promise.resolve(mockServices as unknown as ServicesInterface)) - .set(fvkCtx, () => Promise.resolve(testFullViewingKey)), - }); - - for (const record of testData) { - mockIterateSpendableNotes.next.mockResolvedValueOnce({ - value: record, - }); - } - mockIterateSpendableNotes.next.mockResolvedValueOnce({ - done: true, - }); - - mockIndexedDb.getAssetsMetadata?.mockImplementation((assetId: AssetId) => { - return Promise.resolve( - new Metadata({ - penumbraAssetId: assetId, - }), - ); - }); - - mockIndexedDb.getPricesForAsset?.mockImplementation(() => Promise.resolve([])); - req = new BalancesRequest(); - }); - - test('aggregation, with no filtering', async () => { - const responses: BalancesResponse[] = []; - for await (const res of balances(req, mockCtx)) { - responses.push(new BalancesResponse(res)); - } - expect(responses.length).toBe(4); - assertOnlyUniqueAssetIds(responses, 0); - assertOnlyUniqueAssetIds(responses, 1); - assertOnlyUniqueAssetIds(responses, 2); - assertOnlyUniqueAssetIds(responses, 3); - }); - - test('filtering asset id', async () => { - const assetId = new AssetId({ - inner: base64ToUint8Array('KeqcLzNx9qSH5+lcJHBB9KNW+YPrBk5dKzvPMiypahA='), - }); - req.assetIdFilter = assetId; - const responses: BalancesResponse[] = []; - for await (const res of balances(req, mockCtx)) { - responses.push(new BalancesResponse(res)); - } - expect(responses.length).toBe(3); - responses.forEach(r => { - expect(getMetadata(r.balanceView).penumbraAssetId?.equals(assetId)).toBeTruthy(); - }); - }); - - test('filtering account', async () => { - req.accountFilter = new AddressIndex({ account: 12 }); - const responses: BalancesResponse[] = []; - for await (const res of balances(req, mockCtx)) { - responses.push(new BalancesResponse(res)); - } - expect(responses.length).toBe(1); - responses.forEach(r => { - expect(getAddressIndex(r.accountAddress).account).toBe(12); - }); - }); - - test('spent notes', async () => { - req.accountFilter = new AddressIndex({ account: 99 }); - const responses: BalancesResponse[] = []; - for await (const res of balances(req, mockCtx)) { - responses.push(new BalancesResponse(res)); - } - expect(responses.length).toBe(0); - }); - - test('equivalent values', async () => { - expect.assertions(3); - - const numeraire = new AssetId({ inner: new Uint8Array([1, 2, 3, 4]) }); - const pricedAsset = new AssetId({ inner: new Uint8Array([5, 6, 7, 8]) }); - const mockNumerairePerUnit = 2.5; - - // We'll just mock the same response for every call -- we're just testing - // that the equivalent prices get included in the RPC response. - mockIndexedDb.getPricesForAsset?.mockResolvedValue([ - new EstimatedPrice({ - asOfHeight: 123n, - numerairePerUnit: mockNumerairePerUnit, - numeraire, - pricedAsset, - }), - ]); - - const assetId = new AssetId({ - inner: base64ToUint8Array('KeqcLzNx9qSH5+lcJHBB9KNW+YPrBk5dKzvPMiypahA='), - }); - req.assetIdFilter = assetId; - - for await (const res of balances(req, mockCtx)) { - const response = new BalancesResponse(res); - const amount = getAmount(response.balanceView); - const equivalentAmount = multiplyAmountByNumber(amount, mockNumerairePerUnit); - - expect(getEquivalentValues(response.balanceView)).toEqual([ - new EquivalentValue({ - asOfHeight: 123n, - numeraire: { penumbraAssetId: numeraire }, - equivalentAmount, - }), - ]); - } - }); -}); - -const testData: SpendableNoteRecord[] = [ - SpendableNoteRecord.fromJson({ - noteCommitment: { - inner: 'pXS1k2kvlph+vuk9uhqeoP1mZRc+f526a06/bg3EBwQ=', - }, - heightSpent: '124342342', - note: { - value: { - amount: { - lo: '12000000', - }, - assetId: { - inner: 'KeqcLzNx9qSH5+lcJHBB9KNW+YPrBk5dKzvPMiypahA=', - }, - }, - rseed: 'h04XyitXpY1Q77M+vSzPauf4ZPx9NNRBAuUcVqP6pWo=', - address: { - inner: - '874bHlYDfy3mT57v2bXQWm3SJ7g8LI3cZFKob8J8CfrP2aqVGo6ESrpGScI4t/B2/KgkjhzmAasx8GM1ejNz0J153vD8MBVM9FUZFACzSCg=', - }, - }, - addressIndex: { - account: 99, - randomizer: 'AAAAAAAAAAAAAAAA', - }, - nullifier: { - inner: 'fv/wPZDA5L96Woc+Ry2s7u9IrwNxTFjSDYInZj3lRA8=', - }, - heightCreated: '7197', - position: '42986962944', - source: { - transaction: { id: '3CBS08dM9eLHH45Z9loZciZ9RaG9x1fc26Qnv0lQlto=' }, - }, - }), - SpendableNoteRecord.fromJson({ - noteCommitment: { - inner: 'pXS1k2kvlph+vuk9uhqeoP1mZRc+f526a06/bg3EBwQ=', - }, - note: { - value: { - amount: { - lo: '12000000', - }, - assetId: { - inner: 'KeqcLzNx9qSH5+lcJHBB9KNW+YPrBk5dKzvPMiypahA=', - }, - }, - rseed: 'h04XyitXpY1Q77M+vSzPauf4ZPx9NNRBAuUcVqP6pWo=', - address: { - inner: - '874bHlYDfy3mT57v2bXQWm3SJ7g8LI3cZFKob8J8CfrP2aqVGo6ESrpGScI4t/B2/KgkjhzmAasx8GM1ejNz0J153vD8MBVM9FUZFACzSCg=', - }, - }, - addressIndex: { - account: 12, - randomizer: 'AAAAAAAAAAAAAAAA', - }, - nullifier: { - inner: 'fv/wPZDA5L96Woc+Ry2s7u9IrwNxTFjSDYInZj3lRA8=', - }, - heightCreated: '7197', - position: '42986962944', - source: { - transaction: { - id: '3CBS08dM9eLHH45Z9loZciZ9RaG9x1fc26Qnv0lQlto=', - }, - }, - }), - SpendableNoteRecord.fromJson({ - noteCommitment: { - inner: '2x5KAgUMdC2Gg2aZmj0bZFa5eQv2z9pQlSFfGXcgHQk=', - }, - note: { - value: { - amount: { - lo: '12000000', - }, - assetId: { - inner: 'KeqcLzNx9qSH5+lcJHBB9KNW+YPrBk5dKzvPMiypahA=', - }, - }, - rseed: 'nUSCddD9pm02FxwlmXBCIx1DMrN7QsQ1Mu4QghmIZzU=', - address: { - inner: - '874bHlYDfy3mT57v2bXQWm3SJ7g8LI3cZFKob8J8CfrP2aqVGo6ESrpGScI4t/B2/KgkjhzmAasx8GM1ejNz0J153vD8MBVM9FUZFACzSCg=', - }, - }, - addressIndex: { - account: 12, - randomizer: 'AAAAAAAAAAAAAAAA', - }, - nullifier: { - inner: 'YDmbVyQxPBJbowlAy2R8ThWZTXefTLQVXJ5CPT4sGBE=', - }, - heightCreated: '7235', - position: '42989453314', - source: { - transaction: { - id: 'VwplfDTpKBFLavZ252viYuVxl+EYpmlmnuj5w+jm/MU=', - }, - }, - }), - SpendableNoteRecord.fromJson({ - noteCommitment: { - inner: '2x5KAgUMdC2Gg2aZmj0bZFa5eQv2z9pQlSFfGXcgHQk=', - }, - note: { - value: { - amount: { - lo: '12000000', - }, - assetId: { - inner: 'KeqcLzNx9qSH5+lcJHBB9KNW+YPrBk5dKzvPMiypahA=', - }, - }, - rseed: 'nUSCddD9pm02FxwlmXBCIx1DMrN7QsQ1Mu4QghmIZzU=', - address: { - inner: - '874bHlYDfy3mT57v2bXQWm3SJ7g8LI3cZFKob8J8CfrP2aqVGo6ESrpGScI4t/B2/KgkjhzmAasx8GM1ejNz0J153vD8MBVM9FUZFACzSCg=', - }, - }, - addressIndex: { - account: 3, - randomizer: 'AAAAAAAAAAAAAAAA', - }, - nullifier: { - inner: 'YDmbVyQxPBJbowlAy2R8ThWZTXefTLQVXJ5CPT4sGBE=', - }, - heightCreated: '7235', - position: '42989453314', - source: { - transaction: { - id: 'VwplfDTpKBFLavZ252viYuVxl+EYpmlmnuj5w+jm/MU=', - }, - }, - }), - SpendableNoteRecord.fromJson({ - noteCommitment: { - inner: '9ykyJTT1AMzrEdmpeHlLdiKO6Atrzrw4UBHsy6uwyAE=', - }, - note: { - value: { - amount: { - lo: '976000000', - }, - assetId: { - inner: 'KeqcLzNx9qSH5+lcJHBB9KNW+YPrBk5dKzvPMiypahA=', - }, - }, - rseed: 'NV9zekY5a2HOqIiHUQxpeuZJnmJwk4UDrcf+Qn4gR1U=', - address: { - inner: - 'r7ae/+8Q9d3QdaAs66/GAAbYBo/Am59nYWeIBU7REchE3LYtFPa1EHW2Lo1KZcRWuXzO/cM54CLSFnv2iArQnxjrlJnTB4nGnuLdFtCY9vc=', - }, - }, - addressIndex: { - randomizer: 'AAAAAAAAAAAAAAAA', - }, - nullifier: { - inner: 'xkteBU+VZGL5VtGGCXiF8FNTk11s+26O150ak5YKawc=', - }, - heightCreated: '7614', - position: '47262138369', - source: { - transaction: { - id: 'eD/vckPCdUQ19vXeJP0nSBcBPD5hm7mpgfYXOe4NbMI=', - }, - }, - }), - SpendableNoteRecord.fromJson({ - noteCommitment: { - inner: '1hzgmsvqLjwE8oUKqwjvjioP/NjBw7gA559qH1vXfAs=', - }, - note: { - value: { - amount: { - lo: '1001882102603448320', - hi: '27105', - }, - assetId: { - inner: 'reum7wQmk/owgvGMWMZn/6RFPV24zIKq3W6In/WwZgg=', - }, - }, - rseed: '78CYHBgQbxFq10fZp8KMJTJMv0/W8h/9CG4b+mpbr2M=', - address: { - inner: - 'r7ae/+8Q9d3QdaAs66/GAAbYBo/Am59nYWeIBU7REchE3LYtFPa1EHW2Lo1KZcRWuXzO/cM54CLSFnv2iArQnxjrlJnTB4nGnuLdFtCY9vc=', - }, - }, - addressIndex: { - randomizer: 'AAAAAAAAAAAAAAAA', - }, - nullifier: { - inner: 'xsqQgf4xVTer74FonmkgkjC1VVaV0OlGKkBt9zKGggM=', - }, - position: '20', - source: { - transaction: { - id: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAA=', - }, - }, - }), -]; diff --git a/packages/services/src/view-service/balances.ts b/packages/services/src/view-service/balances.ts deleted file mode 100644 index 64c1ef94..00000000 --- a/packages/services/src/view-service/balances.ts +++ /dev/null @@ -1,229 +0,0 @@ -import type { Impl } from '.'; -import { servicesCtx } from '../ctx/prax'; -import { getAmount } from '@penumbra-zone/getters/value-view'; -import { - getAmountFromRecord, - getAssetIdFromRecord, -} from '@penumbra-zone/getters/spendable-note-record'; -import { - AssetId, - EquivalentValue, - EstimatedPrice, - Metadata, - ValueView, - ValueView_KnownAssetId, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; -import { - AddressIndex, - AddressView, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb'; -import { - AddressByIndexRequest, - AssetMetadataByIdRequest, - BalancesRequest, - BalancesResponse, - SpendableNoteRecord, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; -import { HandlerContext } from '@connectrpc/connect'; -import { assetMetadataById } from './asset-metadata-by-id'; -import { addressByIndex } from './address-by-index'; -import { Amount } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/num/v1/num_pb'; -import { Base64Str, uint8ArrayToBase64 } from '@penumbra-zone/types/base64'; -import { addLoHi } from '@penumbra-zone/types/lo-hi'; -import { IndexedDbInterface } from '@penumbra-zone/types/indexed-db'; -import { isZero, multiplyAmountByNumber } from '@penumbra-zone/types/amount'; -import { Stringified } from '@penumbra-zone/types/jsonified'; - -// Handles aggregating amounts and filtering by account number/asset id -export const balances: Impl['balances'] = async function* (req, ctx) { - const services = await ctx.values.get(servicesCtx)(); - const { indexedDb, querier } = await services.getWalletServices(); - - // latestBlockHeight is needed to calculate the threshold of price relevance, - //it is better to use rather than fullSyncHeight to avoid displaying old prices during the synchronization process - const latestKnownBlockHeight = - (await querier.tendermint.latestBlockHeight()) ?? (await indexedDb.getFullSyncHeight()) ?? 0n; - - const aggregator = new BalancesAggregator(ctx, indexedDb, latestKnownBlockHeight); - - for await (const noteRecord of indexedDb.iterateSpendableNotes()) { - if (noteRecord.heightSpent !== 0n) continue; - if (isZero(getAmountFromRecord(noteRecord))) continue; - - await aggregator.add(noteRecord); - } - - yield* aggregator.filteredResponses(req); -}; - -/** - * account number -> aggregated assets map - * { - * 0: { - * "6KBVsPINa8gWSHhfH+kAFJC4afEJA3EtuB2HyCqJUws=": BalancesResponse - * "CwpUYIdQ9H5Dnf3oQ1l7ISeVMVahWbVNNvMA0dBSdwI": BalancesResponse - * } - * 12: { - * "nDjzm+ldIrNMJha1anGMDVxpA5cLCPnUYQ1clmHF1gw=": BalancesResponse - * } - * } - */ -type BalancesMap = Record; -type AccountMap = Record; - -class BalancesAggregator { - readonly accounts: AccountMap = {}; - private readonly estimatedPriceByPricedAsset: Record< - Stringified, - EstimatedPrice[] - > = {}; - - constructor( - private readonly ctx: HandlerContext, - private readonly indexedDb: IndexedDbInterface, - private readonly latestBlockHeight: bigint, - ) {} - - async add(n: SpendableNoteRecord) { - const accountNumber = n.addressIndex?.account ?? 0; - - // Initialize account obj if not present - if (!this.accounts[accountNumber]) { - this.accounts[accountNumber] = {}; - } - - const assetId = getAssetIdFromRecord(n); - const assetIdBase64 = uint8ArrayToBase64(assetId.inner); - - // If asset not present in map, initialize it with its metadata - if (!this.accounts[accountNumber]![assetIdBase64]) { - this.accounts[accountNumber]![assetIdBase64] = await this.initializeBalResponse(n); - } - - // Many type overrides, but initialization above guarantees presence - const valueView = this.accounts[accountNumber]![assetIdBase64]!.balanceView!; - this.aggregateAmount(valueView, n); - await this.aggregateEquivalentValues(valueView, n); - } - - filteredResponses({ assetIdFilter, accountFilter }: BalancesRequest) { - return Object.entries(this.accounts) - .filter( - ([accountNumber]) => - !accountFilter || // No account filter requested - Number(accountNumber) === accountFilter.account, // Address indexes match - ) - .flatMap(([, balances]) => - Object.entries(balances) - .filter( - ([assetId]) => - !assetIdFilter || // No asset id filter requested - assetId === uint8ArrayToBase64(assetIdFilter.inner), // Asset id's match - ) - .map(([, balances]) => balances), - ); - } - - private aggregateAmount(valueView: ValueView, toAdd: SpendableNoteRecord) { - const currentAmount = getAmount(valueView); - const newAmount = addLoHi( - { lo: currentAmount.lo, hi: currentAmount.hi }, - { - lo: BigInt(toAdd.note?.value?.amount?.lo ?? 0n), - hi: BigInt(toAdd.note?.value?.amount?.hi ?? 0n), - }, - ); - currentAmount.lo = newAmount.lo; - currentAmount.hi = newAmount.hi; - } - - /** - * Attach equivalent values to the `ValueView`, based on the estimated price - * of the equivalent value and the `amount` of the `ValueView`. - */ - private async aggregateEquivalentValues(valueView: ValueView, toAdd: SpendableNoteRecord) { - const assetId = getAssetIdFromRecord.optional()(toAdd); - if (!assetId?.inner) return; - - const amount = getAmount(valueView); - - const equivalentValues: EquivalentValue[] = []; - - for (const price of this.estimatedPriceByPricedAsset[uint8ArrayToBase64(assetId.inner)] ?? []) { - if (!price.numeraire) continue; - - const numeraire = await assetMetadataById( - new AssetMetadataByIdRequest({ assetId: price.numeraire }), - this.ctx, - ); - if (!numeraire.denomMetadata) continue; - - const equivalentAmount = multiplyAmountByNumber(amount, price.numerairePerUnit); - - equivalentValues.push( - new EquivalentValue({ - asOfHeight: price.asOfHeight, - numeraire: numeraire.denomMetadata, - equivalentAmount, - }), - ); - } - - (valueView.valueView.value as ValueView_KnownAssetId).equivalentValues = equivalentValues; - } - - private async initializeBalResponse(n: SpendableNoteRecord) { - const [accountAddress, balanceView] = await Promise.all([ - this.initializeAddressView(this.ctx, n.addressIndex), - this.initializeValueView(this.ctx, getAssetIdFromRecord(n)), - ]); - return new BalancesResponse({ accountAddress, balanceView }); - } - - // Amount initialized to 0 - private async initializeValueView(ctx: HandlerContext, assetId: AssetId): Promise { - const req = new AssetMetadataByIdRequest({ assetId }); - const { denomMetadata } = await assetMetadataById(req, ctx); - - if (!denomMetadata) { - return new ValueView({ - valueView: { case: 'unknownAssetId', value: { assetId, amount: new Amount() } }, - }); - } else { - if (!this.estimatedPriceByPricedAsset[uint8ArrayToBase64(assetId.inner)]) { - const prices = await this.indexedDb.getPricesForAsset( - denomMetadata as Metadata, - this.latestBlockHeight, - ); - this.estimatedPriceByPricedAsset[uint8ArrayToBase64(assetId.inner)] = prices; - } - - return new ValueView({ - valueView: { - case: 'knownAssetId', - value: { - metadata: denomMetadata, - amount: new Amount(), - }, - }, - }); - } - } - - private async initializeAddressView( - ctx: HandlerContext, - addressIndex?: AddressIndex, - ): Promise { - const req = new AddressByIndexRequest({ addressIndex }); - const { address } = await addressByIndex(req, ctx); - return new AddressView({ - addressView: { - case: 'decoded', - value: { - address, - index: addressIndex, - }, - }, - }); - } -} diff --git a/packages/services/src/view-service/broadcast-transaction.test.ts b/packages/services/src/view-service/broadcast-transaction.test.ts deleted file mode 100644 index 4d5b7ac3..00000000 --- a/packages/services/src/view-service/broadcast-transaction.test.ts +++ /dev/null @@ -1,478 +0,0 @@ -import { beforeEach, describe, expect, Mock, test, vi } from 'vitest'; -import { - BroadcastTransactionRequest, - BroadcastTransactionResponse, - TransactionInfo, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; -import { createContextValues, createHandlerContext, HandlerContext } from '@connectrpc/connect'; -import { ViewService } from '@penumbra-zone/protobuf'; -import { servicesCtx } from '../ctx/prax'; -import { Transaction } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/transaction/v1/transaction_pb'; -import { broadcastTransaction } from './broadcast-transaction'; -import type { ServicesInterface } from '@penumbra-zone/types/services'; -import { TransactionId } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/txhash/v1/txhash_pb'; -import { IndexedDbMock, MockServices, TendermintMock } from '../test-utils'; - -const mockSha256 = vi.hoisted(() => vi.fn()); -vi.mock('@penumbra-zone/crypto-web/sha256', () => ({ - sha256Hash: mockSha256, -})); - -describe('BroadcastTransaction request handler', () => { - let mockServices: MockServices; - let mockCtx: HandlerContext; - let mockIndexedDb: IndexedDbMock; - let mockTendermint: TendermintMock; - let txSubNext: Mock; - let broadcastTransactionRequest: BroadcastTransactionRequest; - - beforeEach(() => { - vi.resetAllMocks(); - - mockSha256.mockImplementation(() => transactionIdData.inner); - - mockTendermint = { - broadcastTx: vi.fn(), - }; - - txSubNext = vi.fn(); - const mockTransactionInfoSubscription = { - next: txSubNext, - [Symbol.asyncIterator]: () => mockTransactionInfoSubscription, - }; - - mockIndexedDb = { - subscribe: (table: string) => { - if (table === 'TRANSACTIONS') return mockTransactionInfoSubscription; - throw new Error('Table not supported'); - }, - }; - mockServices = { - getWalletServices: vi.fn(() => - Promise.resolve({ - indexedDb: mockIndexedDb, - querier: { - tendermint: mockTendermint, - }, - }), - ) as MockServices['getWalletServices'], - }; - - mockCtx = createHandlerContext({ - service: ViewService, - method: ViewService.methods.broadcastTransaction, - protocolName: 'mock', - requestMethod: 'MOCK', - url: '/mock', - contextValues: createContextValues().set(servicesCtx, () => - Promise.resolve(mockServices as unknown as ServicesInterface), - ), - }); - - broadcastTransactionRequest = new BroadcastTransactionRequest({ - transaction: transactionData, - }); - }); - - test('should successfully broadcastTransaction without await detection', async () => { - mockTendermint.broadcastTx?.mockResolvedValue(transactionIdData); - - const broadcastResponses: BroadcastTransactionResponse[] = []; - for await (const response of broadcastTransaction(broadcastTransactionRequest, mockCtx)) { - broadcastResponses.push(new BroadcastTransactionResponse(response)); - } - expect(broadcastResponses.length === 1).toBeTruthy(); - expect(broadcastResponses[0]?.status.case === 'broadcastSuccess').toBeTruthy(); - }); - - test('should successfully broadcastTransaction with await detection', async () => { - const detectionHeight = 222n; - const txRecord = new TransactionInfo({ - transaction: transactionData, - height: detectionHeight, - id: transactionIdData, - }); - - mockTendermint.broadcastTx?.mockResolvedValue(transactionIdData); - txSubNext.mockResolvedValueOnce({ - value: { value: txRecord.toJson(), table: 'TRANSACTIONS' }, - }); - - broadcastTransactionRequest.awaitDetection = true; - - const broadcastResponses: BroadcastTransactionResponse[] = []; - for await (const response of broadcastTransaction(broadcastTransactionRequest, mockCtx)) { - broadcastResponses.push(new BroadcastTransactionResponse(response)); - } - expect(broadcastResponses.length === 2).toBeTruthy(); - expect(broadcastResponses[0]?.status.case === 'broadcastSuccess').toBeTruthy(); - expect(broadcastResponses[1]?.status.case === 'confirmed').toBeTruthy(); - expect(broadcastResponses[1]?.status.value?.id?.equals(transactionIdData)).toBeTruthy(); - }); - - test('should throw error if broadcast transaction id disagrees', async () => { - mockTendermint.broadcastTx?.mockResolvedValue(new TransactionId()); - await expect( - (async () => { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - for await (const _ of broadcastTransaction(broadcastTransactionRequest, mockCtx)); - })(), - ).rejects.toThrow('broadcast transaction id disagrees'); - }); - - test('should throw error if broadcast transaction fails', async () => { - mockTendermint.broadcastTx?.mockRejectedValue(new Error('broadcast failed')); - await expect( - (async () => { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - for await (const _ of broadcastTransaction(broadcastTransactionRequest, mockCtx)); - })(), - ).rejects.toThrow('broadcast failed'); - }); -}); - -const transactionIdData = TransactionId.fromJson({ - inner: 'BbfE5hIr5e0Qv9K36lCoSIdFy55OnI4guuySeSX6C5s=', -}); -const transactionData = Transaction.fromJson({ - body: { - actions: [ - { - spend: { - body: { - balanceCommitment: { - inner: 'mLSHGBzim3wSsFOn431tR9fsD+RcPXK1hn7FtxYOlws=', - }, - nullifier: { - inner: 'knpvZH3soGxnNVQZcvlA+VMuvCZWVCgknts1mowDSgg=', - }, - rk: { - inner: 'cmAa4EqbtHC5lhoVU6PGJfJl06QpBga4eO3cuF/8MAU=', - }, - }, - authSig: { - inner: - 'GJo9VlwKrGKwwbRW6rTfZk6pIWYL0UEct3NTCFx7YhEnzeNg1l5zx9hfnxJysEBSU63OmG3NsLp+GABIsboTAA==', - }, - proof: { - inner: - 'OvLGAV9gAH3n5r/MV+nRkLMATFHpM6zubwdP6J1aJbBj7Ir1wteZg7OiXE3F4HkBg2dMaVLUUkTnLe1zyu9fIvLR5eMKLgCNI6MUfHZm0ax14fmMInQxv5JCijZe4WIBGpSxDFyGBAFaMoYOtbspGyeby7skgy9rAX7OMGrLGhrFp7YlevcgByRxbyEBqVABlptYxE/RLVP64ovO8pkSx7bJiK3NSfdC7RsxqqzaS+yGYK7biB24tGn1BG8z1EUA', - }, - }, - }, - { - spend: { - body: { - balanceCommitment: { - inner: 'LnUs6kKZ+9MO+J+bHiDFm+WRnHEWgIjkw7ieivpQ7xE=', - }, - nullifier: { inner: 'iKtEKV32USvsFJINbWs8WlpGrf4ISt+D61LkVzAyPwY=' }, - rk: { - inner: 'oIpHfSwEialuU436KIw9tXR3wWpgk0NHIcc17dRnYQM=', - }, - }, - authSig: { - inner: - '5vBg2TjWbJuG6XYG+D8vky7wrXv+2spahENVpQRFWQmVwhHEhdbKSa94LswbMsiuVC0UipX11ezgCWXpuDq6AA==', - }, - proof: { - inner: - 'bJixhv1Lr5D0uMeieXID9ESaFEKxv3pDb8Hppovl0kWc1fWtnESWhOXBmh7l+8EAehSUrZiEcNLJahtXP05xPy4qdBVfPPOYsFMiTTXyCsdgg/I+/21rBP99LBJAJU8A+WgWvu6TL84YRepUPOC56KsOnaP6hSEajt8liL3lTHeYYerbzGfzsESwjyPKuJEB+UJjTH419Mq5fXd5swY+3sqXB4/hDq/wVk9SuPGkDXvNUUZH6T1WqXSOXeaJOiGB', - }, - }, - }, - { - spend: { - body: { - balanceCommitment: { - inner: 'yI14CUmNVu+N5+0/rgQdAMU5RBikcCQQzWaWHStfSAs=', - }, - nullifier: { inner: 'B3XzzNvAuT3hMVqTfAAN6m9UlODZ9fldv3OyA55ABAs=' }, - rk: { inner: 'vhkNUmggYaQRaIb1f0tT1RWapAcvF+i4NmuJPNi/iwo=' }, - }, - authSig: { - inner: - 'MhWvmocns1opnTDOuPT6NL6dSL7aeZEZV6I2A+ayJwqeRVK3kaFtOqo4vxnummdw/ydsPiAvVQnCHtnUXCmpAA==', - }, - proof: { - inner: - '20w8HjUS/fthqz7vYcwvKyAbmONpCAm5QMYyMF+39EcHwGIanxNesVjoxKg/WTQBj/vO2fae6cR8bPZM+FzGzClDJx0Zn6zn6rKSPV6DAxxoK/ZvP/l7oNO9zVz56RgBEmfpuUwYEdc3jzQ2ND887zw/2lxTXYc1n+NWxBrm8SA9p5gENkfTEDkKK4iEF/EAMXz5kWx3jQ5OsxPj5XMFJ279P3LrR9a1jFx1ChMv9lROcpqGsLvuyQkXWsEvMFUB', - }, - }, - }, - { - spend: { - body: { - balanceCommitment: { - inner: 'drR8MmEnfMs0CkY9QRaxiAGSZmM9lpU4+metaRt3UxA=', - }, - nullifier: { - inner: 'x40Dz0PFP84vJ3cswSdiKFJJCWuLtYxapRXSey/+wgQ=', - }, - rk: { - inner: 'pujbFovCIVxlF5hCJ/+PlvBeCG0jHelV7im2Li+uTQI=', - }, - }, - authSig: { - inner: - 'BrZoeKQXBpQD+E6EJ2OxzvEhW5RVZYGE5euvDeRNKwerXNmEuGpxFD8XsFqaA98kooJnHc35uP+ARYB9YOnDAw==', - }, - proof: { - inner: - 'PtvZI64TyNA0j2aHy31mz7sTOPkXVvGJJHImPfecYTag4K8ahmeCGjXx/5wTjWaBsiAnuVJD63mFlKr8MhmK9rp7llprkM8ehRGA0S9tB/IHJ0da46YDzH8XGyG4UHcBuoK03fuq+4V84TAOzAs5+Ca/NSnV1Z0C7HTqd1M86tdo2mC1Gs5Ys/EM+ItleHoACY+cqDrWZVbiuONHAq7HE9/gKx9kiTCDCFDK05kawUBK1scKQG5jiybFebVkik2A', - }, - }, - }, - { - output: { - body: { - notePayload: { - noteCommitment: { - inner: '3WvedSSpq4kX951dVMMMeKR2OepBTPqGpF8QOO//fgw=', - }, - ephemeralKey: '+kGNLsbePwgL6LuINJqnV4l/y2AwbBDI224/1nq5xgk=', - encryptedNote: { - inner: - 'R/Gf/zakltAbRg0shbrd85bP4phrFZ4Msuw+gUjD3qGgsChIVIrLpSSOTtMlJpKCGhAmxDn3oCvdk5ASU3HkPVLaL90RniZ2ZJ1nGgij0pA2XbVcdotRdRfw6ZHxB0SAB2EWSv9oV/K7vNAtR+SpNAMG6bbQsLjqVJCbZMmSVhhnojoQV6/KeYEfa/R8T7LUBwEBR4MY3qO4SxLfPIQQulxo6qoYm462wUF1njA1pIE=', - }, - }, - balanceCommitment: { - inner: 'mBZDCVkBXzFEdebcHD1QPqn5xuAIpoF+SMa4IRxvZww=', - }, - wrappedMemoKey: 'tfvqFYlHGJ7x0R1ch7sThXGPGLL/jYSK9My1ngipfdLtIjbOQRZoO/oty0jGXYjZ', - ovkWrappedKey: 'v40iQUFriHfiy8sSjfuQlc7P7fU6VfknPgMEGiC1cJxRHRRCBknbxlCG+99GKZAG', - }, - proof: { - inner: - '7mya0y4ZcnHrtHA9xuMmtf+6V1jfpA8GNrtQoxPaDnAuMN9Qe2h6K9MtoDTOpC0AVN5DZVt7zITsVZLPMZ70sQ+XlS2fivUNIk6/20Twkev4xc809nebdr3AqSoNoIIAor1ZbGQNIdqaNItvp3DQ4S0FguaGcS1TBwebiJTeUwfL4TH9D6QL6YvkGp1JSg0Bv0q7psIptEdI5WtSZZjR8kY11QXlPr0bwDiyc15CFIhlHGAj3RqhlH0fsNmEGZUB', - }, - }, - }, - { - output: { - body: { - notePayload: { - noteCommitment: { - inner: '5LGElYM7UCex9oVWgBfgfo1iQkTSm5Z1DZAPFUW+NQo=', - }, - ephemeralKey: '0g8xqLhvfT+h/dfX90f7xF7Jyyv4tCXzLCBKXhUyKRI=', - encryptedNote: { - inner: - 'p4051rDIv7tVLIqGk7cagA6O+Km2Byo0yscU1DFCgJkkdQnkEFabmJS601rLQ7tsyh/+FPEnb0dSIi00S1rmLCya2tRlRS4ru6WtBjchw6vn9To/S5qbGVMD6l3siIxJo9RVrAaNFE35ForqpZpCXqPctiHKC30dSMHG0+O9MPKzRqlwCJKDOezUR1rrPZV+ukvB1KU6QUpHnZtQFLQnMW7cZmOzp5SraYksZqhoTy4=', - }, - }, - balanceCommitment: { - inner: 'jttI7PeS8mE1wp+COaVNuu7HOBFkrTCWThyZLrobvww=', - }, - wrappedMemoKey: 'nyv6CdQkZqOMTGP0mBAv3ec01+g4v4HCmUKuup7cG+Dz6M5Jb1welFOmicaImiM+', - ovkWrappedKey: 'i9FMZLMduuTBQQ2t3QXSXAgf4aWHA1eTJAsGEKcoQPDXReWdVNC1/V2OXhiXLxcp', - }, - proof: { - inner: - 'fW2/mxyDh+X5bxGeOzSp/OoGyqDkd2///6wzQZaIEZRyHSpG1+/8ZGZ8EI0YU7KAPjzCqPd7Nkb+nTHp/KWFV3Uu4IxNs4mbAKIyeYII2NybTphQdC3MzRZg+oTkH2IABdqP4X2hdBZ28zntxXSdicA3lq+fQfD6KxfrJpA80d9BLTqJsrFI0dRwCSF6LLOAgXpvlsM16IYtb0ykQ9q5cBmvsXdvPliAIAq5Pi40j05XX/tb+msZ6RLhdXnqkgMA', - }, - }, - }, - { - output: { - body: { - notePayload: { - noteCommitment: { - inner: 'GuHzSMZYeSJvb07AgErw50TH13xxE5SMD7fPmH8N+gA=', - }, - ephemeralKey: 'ZAQfdUWQRWFSaCGVeThQtiWQWE2BXPqr+45L+3Rqlw0=', - encryptedNote: { - inner: - '96BGfrpJL3ir7pO4GW6YKZjlqR/qf5Fa+qxFpqH+rRJg7JDXL525HpZy8VoQWLsXaTsnGVERwyPoGZG291LAY5rUZDGMIs8v5Pyfn4mLnTPzeH6abr/cOvVTmJ4h4642z7KhdGyo5IbXdGyCkbgWydTePv0KmD9M8s4UW/F15rpds+gQIGz2AE4+12+4jPr++oangCNLf4pEmwiKjBlx0IihrNxk1/6kTRuAfL4VI8g=', - }, - }, - balanceCommitment: { - inner: 'IvBWZSjXNrtEFuLlbawHFN61dglil7l55i+GwG8PbgY=', - }, - wrappedMemoKey: 'U3llcLx+1omlkP+/C1QQAMDoyuRaAcBwDjIQjtDQL6F1q4JF9PRTvrYikhdtOJZJ', - ovkWrappedKey: 'CFRgB/mTvu+MpaoLzJ7iEqs3ndKsMNA9eGE3rPJLcIWRbCWpv7YMx9szPzTmZAQ1', - }, - proof: { - inner: - 'CzpdU4xERq3c+XtOPYvEZkvvQZOBK7uLoBoBqJGeDnzDonmaOXh4KR93f3VzMniA3KEeT46K+KxDTQ54pKQU8gk7OeYtQzbTLEiMTIIcmNLnZ2Ec2//zLOi0d7M/TXgBi3H4g6rLqbRcU7W7cxHyYvbNOBmM6Oi+SMMuLAKpRzBT8ygmIvMDnwxa1o5zeG0B1TWh2HLQFzGVUgT4517B+6nOj4/gJy7lofIiOvr8pAZsz2InVDNoxwf13DttoxcA', - }, - }, - }, - { - output: { - body: { - notePayload: { - noteCommitment: { - inner: 'VZvk7tv1zn/hSti2nLpL6x7gAHzJUbdkIy5LDR70kBE=', - }, - ephemeralKey: 'HnWYIW5yBrSjxzgGf3fNLY3C3RkwrX6XuW7/RO8qqhE=', - encryptedNote: { - inner: - 'N4VY6GxAOfDo/CtV3TggMTnS9qdp8ixYkJktrrw3YtmsQusyVd8BQPggnbpC3XyhOabe0phE5+BFr07EwCDH71bGO/7FglAPV3zCA2G1rKLGge5GeRz7mlorDvueAx/T9286Vx8DN2dRBfgLEGw5YmLjsUISVH9hAPk4KzjBgAQqBeNxATv7PROUhjnp8fO8DrEe9fL7lWnjhtTd7Id1s23aIshpTIEOQG21CgOQxdY=', - }, - }, - balanceCommitment: { - inner: 'dOxUDjSlcIAL+W5YtUKpodErvfz7S53YlR6uke1iWwk=', - }, - wrappedMemoKey: 'DJUfS5jfFyoBb6E4H/ATFpG5CjcPJPC9RmuzKrDIzVG+it+/Y7KBpN2ABGrJL5WC', - ovkWrappedKey: 'l6YPHV8bxB1oPbAcBLtDAc1Aq20kD5U4+oZRpYj59bviXUzfCIvnITfuanhJtrOG', - }, - proof: { - inner: - 'xxwfTg9Reb/WGu4wmUkWUarpLeU2vRXAE8Btc6QHExK398wytGzxlsyNY2S7qXoBJHFVcRv6Tx3oC6dZ5fAoGpzJI7uEN70i/eJOSZbHLTA6XY0VOrkA2P3zIbgLZu8A6cyW3hl7uMBphf6bqLyxsGFUZu7noSHUb4AnW5Wfod2giwsIm9/kzjpBDf3iQ9kASJBJTffLAvszNUVrR3mrJC0wEdqPTtoz84Iyy7VUzkcAJmi/P+AIJJIRtdnp7IqB', - }, - }, - }, - { - output: { - body: { - notePayload: { - noteCommitment: { - inner: 'v00WG4eq2UfFceMbEePaWakxAEuyXkNpiR/RhUIP3gw=', - }, - ephemeralKey: 'IN7b2urD0lenpjQHDqfcc3d8XXCgsKpASqyJDoPZzws=', - encryptedNote: { - inner: - 'me0HxTd9Ca5SRXOPTCC9zbJ4fi75eYgjNIDA/7Uf6jcntYij6lMg5OoUBr1MKNYG44mJWxUBNmaG0iZ1k/P+KNVc9aCqCAdZJBT/72Cw9KCOa4Z3dYhmwW9JVwFEVN4taeNi81xi+nLd/0BzrKAMJCCLkH5z7tUztCXvZGcK26AGsqUa5M3JadsmwtAmAa0mhtP8Nvj1GCxtfnyxFiOTw6iF4xnRxcT97LkrF43jPPM=', - }, - }, - balanceCommitment: { - inner: 'xhEvO8D8VosI/rXowFT18XKphHx2KE/flhsueexl4hE=', - }, - wrappedMemoKey: 'aqV0AB1qGm+H7MANkV7GOf+gy9yol9Zeq1KJCiwv2P+JxrCneSMnNYod3eAToWGn', - ovkWrappedKey: '86CR823j7a/R8PTy9KmlXBPoRVDtqmjuuSWgSRa9Lv5lxHuS0N5aSDQ7udlhgx9M', - }, - proof: { - inner: - 'l8neFhNDPbJ1AqemLyIdMbwAtUBrs60ea36j9upZKo7gtTsryYDYhCimNLlt2SgAQDrAAW+t6Do4DDv14x9GLFifBiw2bnbbtf97JUDGKZJ8T8H5RQdpfOCEIiC5lAUB82DDjN8LeAjkfUHybqBytvsNCRuULznIbKTT8LJm8OJXsbH60/F/lkuI38KyI78AWjZks2sdX141IT51czpMGNs1NepX/d739+dcdsmoQSMU8OSrVNns4eZNvknS+3SA', - }, - }, - }, - { - output: { - body: { - notePayload: { - noteCommitment: { - inner: 'WinDFqc8CqAxkr/NOQHNtSO+6Ro7u/lGD6slOYR1lg0=', - }, - ephemeralKey: 'pBtwFCcA/FC22GzngcQrvWk/+2++b+2uo3QahfjkMgQ=', - encryptedNote: { - inner: - '6Gqpf/x3cd1g1hQ1U2b4nNok5SpYuEwwWg5nUtDHYS9CZz35+dg9XbqDUtFP74mVjYbxVB4+qXr2F2HiT8WrX0artkKS4/iWNxe4KlxnG1g/cLcTreZ1S36OH7rVXzcMQWFEgYH8HCKkTvIuMNnQr6E+uTUaX1qIj0gpKCMMfqzFtFAPQVKlHTNkHB+2gY9c6MOa3r/HfGehDgnk5t7S+hYha/hYmcV193GYSIIalE0=', - }, - }, - balanceCommitment: { - inner: 'wsJeHMoAbyf/NTCUwX0kOLUxEOQF303v2WlFOkzkGAw=', - }, - wrappedMemoKey: 'gMvMDEebtNu2MgbaSESx0X5NoIHgBjnd7EFVQF6wPorDV3Zxn8QrXHIUqfhQX7tB', - ovkWrappedKey: '9z9jH7JMS+/0uOQ+wGbQnir+YUWZHXGOGtMG6O7GZYz7SCMCyMweiwk/Tu0ATnZv', - }, - proof: { - inner: - 'Q2Oberg+JGR2QrG+3lxCkcVko7XDlbQBPWe1DeytG7rdco7NVPZw7mGMDmqhfOGA+QMeo4xXV+vFmpP8e2qS5E5kJW3MVMs/QFhs8nptPNqm14aF27U9vsPVJpeio4MBlDVi+TAsjVk2zQ/lFw33l5Dla4fne1cMFrYPaG6WrwH5YQYZuaJzz5bUX+FGnlQBtfZl3YlGDYZHL0NijuM9jujzpjAh/p6ROIKNZahMXSxsSHp7iQsO0cwQFw4y87gA', - }, - }, - }, - { - output: { - body: { - notePayload: { - noteCommitment: { - inner: 'mycDZGRmawM/gn5mcSLdekUcwayLwCBaPNdvVhL41Qk=', - }, - ephemeralKey: 'MAraIMUu/UiY5oQeo6Jh6Tm3sS3a5uqqGXiGDKmc/AM=', - encryptedNote: { - inner: - '3pJ7goLAX/kHPRPqzhPJ3fYMrS0PvKxESdfcvxWB7b8MPByC34G/HkMDqjx6/DO599ubAJM5LsFpGrnhGPtE0hg+GNu8W+d54oRd3qJ2Uh5LtvXfGK0zM0qBXSXKIkXBEOGODZJ6f2L+m9qX6roK1J59VodCIa1wEBVuPbXogcq/CYn3L0A3ot7Yj9MWYQnZ0QcW1s0g/NkaNonHnhz6UWsK1U3zaPRih10p/GoapXg=', - }, - }, - balanceCommitment: { - inner: 'PKW0VKrMuencxQGVVUq5Rjp0OQZvrpXHlanBwyVC1gU=', - }, - wrappedMemoKey: 'gbYRvDj2DmvyqB0MrVqAydcOmCcFbmOF4wrFNaZtx/stz7n0CjEuUdH4LJV99LZ+', - ovkWrappedKey: 'A/2JWy9UhF3xx7wXfhf8735w7HlzT5KBWT6V4yKJNw8xirQ7luzpGs+lyQkw7+Ke', - }, - proof: { - inner: - 'm+yVsZSP2w0SvlakWAyypRI8zZFZ000XwA3lf6UF8xDP/b7wZyHiyZof8dMy2TwBwodfNx2D9vxBax73RVBovUjceqGhYU5MqxFkjIlREH1U0rKgMqRVayzzStnzbdUA4Lf7ByeQAjm7DlyK03tfedaiXV4jkPyEoyI9m78A74O0qPzCdUExFoDUx3/XC2+Bog1NvDN5NFmP/XBOl3ZMJDH1rcBkskHipdGiSE92V+c9Mtdea3vWX7C+ebD5sSEA', - }, - }, - }, - { - output: { - body: { - notePayload: { - noteCommitment: { - inner: '/mmvwP2dPRNkX4IJiq+7ZfXsubsoCY9gp2N/9ugHqRI=', - }, - ephemeralKey: 'xhgPCiRjN6snO5qlsdRpA7oCUVRWxpE8n7/Z2uU60gw=', - encryptedNote: { - inner: - 'ayaHlEzPbu8QJwtLea/WxhucXytntgXhLFfrIf8YrHkuYewBDEIuMjyQJ1q6zHjXVt46QF0bcXDi5rfnFepdVyLiS0z3ZQAO73SGuPOJegiwgz0iPgngMpqE39S2m5VH8saFzRzywkTQpWsR//naWB5oqfS3/AVpNUwzm9Mnvme4LImyR3vWT4dbvsYVsmQgcXK/mYjb5KRtTyxzqe3PnLFTIRbGCKeRFEZ7My0QgG8=', - }, - }, - balanceCommitment: { - inner: 'aqUqgKx/4+12S6yk6hUCurgMTxiJ286AcfjVGPiORAM=', - }, - wrappedMemoKey: 'hu4iFAe9hP7zBAOw5xaBWv2TSaLzhQ/1oJhkSp5Ug2M2pr/EZhJGSLOvix501AcM', - ovkWrappedKey: 'uZYJSJUbd9R6LB5ii508XyxLJtIvWjZ6co88VTKEL/33lkMvhsIxTZyp+RZKS4cF', - }, - proof: { - inner: - 'TTjJyg3Wo8a5IYfhwCynxLuY25413eUpl17F6ZBw6tbBKzCBcPCESpcwhEZSmNGAjFM8v5H7Wh6qmDa/gG3AIJANB0ZDShaMO/tlaBBRc+vTmDU9xMvsnfZtAlMa2YoBuwmjkjFcu2bz0c08jjp6Tg3K9RkjPWA685UDZVnHjDzVet+lVeCeah1IDiYiBKQAAjpa2vXwC6kGCACV6I8HXSMx27faqX7mQMFVNve9p8isXbyQWqzJax+z24Kjh08A', - }, - }, - }, - ], - transactionParameters: { - chainId: 'penumbra-testnet-rhea', - }, - detectionData: { - fmdClues: [ - { - inner: - 'vCPE22JFgv8JPOWri+IknthYYx5bbUBwqrSnL2Ko2hGtDfh7NRI3lI8Co5Zei8+4jUcaJctQkGrYD0uXwI5SBAAAAAA=', - }, - { - inner: - 'FCuaszw2jXO9bjcKHtXBTNpK80fg4qF1RuV8o19kHgJCh0Gg+OfHjuds5Qpnp73oZBr4zOrxVojO3cCRNv5KAQAAAAA=', - }, - { - inner: - 'CnlKAo3MOrejUQJYobus9R0mx0s5B2N3RD9KHCy+1gZipbCHMWsxQtNI4Aq6mne0lEpjimOkJBoIfV7rd4dsAgAAAAA=', - }, - { - inner: - 'EtmIfw5uII1WoDURC9Fwt5XvWOUNSYmhz4IvdMZocwO9783PQd+DcfnjBkT2JRUj8ZWRlULSxmoUemdyrnWWAAAAAAA=', - }, - { - inner: - 'MHMLUbB/CJasfDn5SrNzU86/ADJ80vRlp14fp5BACg4+5TST+rgMVxWI4G65Z/TT3NEFU/od8WSCSwrBPFB1BAAAAAA=', - }, - { - inner: - 'TLjYWauiUprJeZvQm7pn7qhGgQqGpdUO8XY168bUFgbIaGZAucv8+Ih9oprdDJtwu+u6XMOthV0lxXcExWAJAAAAAAA=', - }, - { - inner: - 'rpz7S5DAzY+vBfnpx6v+XGeQGIAVQHJdfPDX0GM1FxHN++wjE99MUgQWj7PQ/xor8Bq78LXCyFV4sBqAe9rzAgAAAAA=', - }, - { - inner: - 'go/zUaQciHzEjoBJcwZw7hAr3nGoscaPxnRg5iiUYwTlE3kMXx6RfbQqkMrzSz+cVR0j8d9FzMk3+I+efM0EAwAAAAA=', - }, - ], - }, - memo: { - inner: - 'NGJ0T7iaorVP2ApR/78bejqFVn87DO+2vcaogbZYf5VvL6HvazSfYGiLq52c24n4ZfYGtN1z8dTyVknbJ9JawwComzYZ7kkWlQyUbXuKIGCowgxuv0dZ+5QXPuL7acycgnVXlzkfPH6CJylHKhWPb1Wskdk5KJaM+I2ofKi69LPtkIQhYcy3Prc7/nAwytxdjcWjsvS3bjRfry+F4ch8n+2EcUklygz2wnAr21crV6Hd855q+/OZKyEpWkODTB4wuYetm4b8laFklWKWDhFzezdmIUXgf/RSVIgk51H5hThVauH8m1dg4kW/5wklVCrzJjrem2/T/KnIIJEcxzuQ85Smk86fWycgnraQ80Sy9G1nU8rqwBE4KUFLQ6OVu5z0pfYH3DaYKTpVmOsvwCz2l2+me9U6JIB5jiQRvdcjjmPquDIhPbOSNlKRmLa6tmvEqM0Y7rxT1MnbR3Cdzp+30gwruLg0oiTm80N1Ltdkwv2+0uR8iSAfSVmW9o05/Lnqt548hGS/bW3LDX7BHV/Jq464prPUOejEqiFPHjohHlC3hs4T3k8if9euY5DIBwk5evwQ+rNE2E/x8g/wjJyWLp+Nslms8E66ecHWUNgQb5i6NiLwZ8f15/kdrG+ioZj1d/S0hTC9JgZCTEmcvfNBKxOw7ge93cxRmv7Sj688QA5acUDAejinEZmvXXyRV2AD', - }, - }, - bindingSig: { - inner: - 'VDwfYSlhod90QLBvTdIM+T+WdscTjqecFp4PSeRhhwQX2Al3CHo0Bikx3hix0iO4zF/EnRIuz4J70clixI9VAg==', - }, - anchor: { - inner: 'mrchwun83TOMYsdXtkBSdUYXXMzlg6N2NYfEcqWmfwE=', - }, -}); diff --git a/packages/services/src/view-service/broadcast-transaction.ts b/packages/services/src/view-service/broadcast-transaction.ts deleted file mode 100644 index dbe5fa7d..00000000 --- a/packages/services/src/view-service/broadcast-transaction.ts +++ /dev/null @@ -1,52 +0,0 @@ -import type { Impl } from '.'; -import { servicesCtx } from '../ctx/prax'; -import { TransactionId } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/txhash/v1/txhash_pb'; -import { Code, ConnectError } from '@connectrpc/connect'; -import { sha256Hash } from '@penumbra-zone/crypto-web/sha256'; -import { TransactionInfo } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; -import { uint8ArrayToHex } from '@penumbra-zone/types/hex'; - -export const broadcastTransaction: Impl['broadcastTransaction'] = async function* (req, ctx) { - const services = await ctx.values.get(servicesCtx)(); - const { indexedDb, querier } = await services.getWalletServices(); - if (!req.transaction) - throw new ConnectError('No transaction provided in request', Code.InvalidArgument); - - // start subscription early to prevent race condition - const subscription = indexedDb.subscribe('TRANSACTIONS'); - - const id = new TransactionId({ inner: await sha256Hash(req.transaction.toBinary()) }); - - const broadcastId = await querier.tendermint.broadcastTx(req.transaction); - if (!id.equals(broadcastId)) { - console.error('broadcast transaction id disagrees', id, broadcastId); - throw new Error( - `broadcast transaction id disagrees: expected ${uint8ArrayToHex(id.inner)} but tendermint ${uint8ArrayToHex(broadcastId.inner)}`, - ); - } - - yield { - status: { - case: 'broadcastSuccess', - value: { id }, - }, - }; - - if (!req.awaitDetection) return; - - // Wait until DB records a new transaction with this id - for await (const { value } of subscription) { - const { height: detectionHeight, id: detectionId } = TransactionInfo.fromJson(value); - if (id.equals(detectionId)) { - yield { - status: { - case: 'confirmed', - value: { id, detectionHeight }, - }, - }; - return; - } - } - - throw new Error('subscription ended'); -}; diff --git a/packages/services/src/view-service/delegations-by-address-index.test.ts b/packages/services/src/view-service/delegations-by-address-index.test.ts deleted file mode 100644 index ce8d9a40..00000000 --- a/packages/services/src/view-service/delegations-by-address-index.test.ts +++ /dev/null @@ -1,351 +0,0 @@ -import { beforeEach, describe, expect, it, vi } from 'vitest'; -import { delegationsByAddressIndex } from './delegations-by-address-index'; -import { ViewService } from '@penumbra-zone/protobuf'; -import { - createContextValues, - createHandlerContext, - HandlerContext, - PromiseClient, -} from '@connectrpc/connect'; -import { stakeClientCtx } from '../ctx/stake-client'; -import { StakeService } from '@penumbra-zone/protobuf'; -import { - AssetMetadataByIdResponse, - BalancesResponse, - DelegationsByAddressIndexRequest, - DelegationsByAddressIndexRequest_Filter, - DelegationsByAddressIndexResponse, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; -import { - ValidatorInfoRequest, - ValidatorInfoResponse, - ValidatorState_ValidatorStateEnum, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/stake/v1/stake_pb'; -import { getAmount, getValidatorInfoFromValueView } from '@penumbra-zone/getters/value-view'; -import { identityKeyFromBech32m } from '@penumbra-zone/bech32m/penumbravalid'; -import { PartialMessage } from '@bufbuild/protobuf'; -import { - Metadata, - ValueView, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; - -vi.mock('@penumbra-zone/wasm/metadata', () => ({ - customizeSymbol: (metadata: Metadata) => metadata, -})); - -const mockBalances = vi.hoisted(() => vi.fn()); -vi.mock('./balances', () => ({ - balances: mockBalances, -})); - -vi.mock('./asset-metadata-by-id', () => ({ - assetMetadataById: () => - Promise.resolve(new AssetMetadataByIdResponse({ denomMetadata: new Metadata() })), -})); - -const activeValidatorBech32IdentityKey = - 'penumbravalid1zpwtnnmeu2fdqx9dslmd5sc44rja4jqlzqvzel8tajkk6ur7jyqq0cgcy9'; -const activeValidatorInfoResponse = new ValidatorInfoResponse({ - validatorInfo: { - validator: { - name: 'Active validator', - identityKey: identityKeyFromBech32m(activeValidatorBech32IdentityKey), - }, - status: { - state: { state: ValidatorState_ValidatorStateEnum.ACTIVE }, - }, - }, -}); - -const activeValidator2Bech32IdentityKey = - 'penumbravalid1tnsyu4tppg7rwgyl3wwcfxwfq6g6ahmlyywqvt77a2zlx6s34qpsxxh7qm'; -const activeValidator2InfoResponse = new ValidatorInfoResponse({ - validatorInfo: { - validator: { - name: 'Active validator 2', - identityKey: identityKeyFromBech32m(activeValidator2Bech32IdentityKey), - }, - status: { - state: { state: ValidatorState_ValidatorStateEnum.ACTIVE }, - }, - }, -}); - -const inactiveValidatorBech32IdentityKey = - 'penumbravalid1r6ja22cl476tluzea3w07r8kxl46ppqlckcvyzslg3ywsmqdnyys86t55e'; -const inactiveValidatorInfoResponse = new ValidatorInfoResponse({ - validatorInfo: { - validator: { - name: 'Inactive validator', - identityKey: identityKeyFromBech32m(inactiveValidatorBech32IdentityKey), - }, - status: { - state: { state: ValidatorState_ValidatorStateEnum.INACTIVE }, - }, - }, -}); - -const inactiveValidator2Bech32IdentityKey = - 'penumbravalid1acjrk7dhkd5tpal0m0rytsfytg5r9vc67y02v6fnv4qvrcr2kqxqgyn9wy'; -const inactiveValidator2InfoResponse = new ValidatorInfoResponse({ - validatorInfo: { - validator: { - name: 'Inactive validator 2', - identityKey: identityKeyFromBech32m(inactiveValidator2Bech32IdentityKey), - }, - status: { - state: { state: ValidatorState_ValidatorStateEnum.INACTIVE }, - }, - }, -}); - -const MOCK_ALL_VALIDATOR_INFOS = [ - activeValidatorInfoResponse, - activeValidator2InfoResponse, - inactiveValidatorInfoResponse, - inactiveValidator2InfoResponse, -]; - -const MOCK_ACTIVE_VALIDATOR_INFOS = [activeValidatorInfoResponse, activeValidator2InfoResponse]; - -const penumbraBalancesResponse = new BalancesResponse({ - accountAddress: { - addressView: { - case: 'decoded', - value: { - index: { account: 0 }, - }, - }, - }, - balanceView: { - valueView: { - case: 'knownAssetId', - value: { - amount: { hi: 0n, lo: 1n }, - metadata: {}, - }, - }, - }, -}); - -const activeValidatorBalancesResponse = new BalancesResponse({ - accountAddress: { - addressView: { - case: 'decoded', - value: { - index: { account: 0 }, - }, - }, - }, - balanceView: { - valueView: { - case: 'knownAssetId', - value: { - amount: { hi: 0n, lo: 2n }, - metadata: { - base: `udelegation_${activeValidatorBech32IdentityKey}`, - display: `delegation_${activeValidatorBech32IdentityKey}`, - }, - }, - }, - }, -}); - -const inactiveValidatorBalancesResponse = new BalancesResponse({ - accountAddress: { - addressView: { - case: 'decoded', - value: { - index: { account: 0 }, - }, - }, - }, - balanceView: { - valueView: { - case: 'knownAssetId', - value: { - amount: { hi: 0n, lo: 3n }, - metadata: { - base: `udelegation_${inactiveValidatorBech32IdentityKey}`, - display: `delegation_${inactiveValidatorBech32IdentityKey}`, - }, - }, - }, - }, -}); - -const MOCK_BALANCES = [ - penumbraBalancesResponse, - activeValidatorBalancesResponse, - inactiveValidatorBalancesResponse, -]; - -describe('DelegationsByAddressIndex request handler', () => { - const mockStakeClient = { - validatorInfo: vi.fn(), - }; - let mockCtx: HandlerContext; - - const mockBalancesResponse = { - next: vi.fn(), - [Symbol.asyncIterator]: () => mockBalancesResponse, - }; - - const mockAllValidatorInfosResponse = { - next: vi.fn(), - [Symbol.asyncIterator]: () => mockAllValidatorInfosResponse, - }; - - const mockActiveValidatorInfosResponse = { - next: vi.fn(), - [Symbol.asyncIterator]: () => mockActiveValidatorInfosResponse, - }; - - beforeEach(() => { - vi.resetAllMocks(); - mockBalances.mockReturnValue(mockBalancesResponse); - MOCK_BALANCES.forEach(value => mockBalancesResponse.next.mockResolvedValueOnce({ value })); - mockBalancesResponse.next.mockResolvedValueOnce({ done: true }); - - // Miniature mock staking client that actually switches what response it - // gives based on `req.showInactive`. - mockStakeClient.validatorInfo.mockImplementation((req: ValidatorInfoRequest) => - req.showInactive ? mockAllValidatorInfosResponse : mockActiveValidatorInfosResponse, - ); - MOCK_ALL_VALIDATOR_INFOS.forEach(value => - mockAllValidatorInfosResponse.next.mockResolvedValueOnce({ value }), - ); - mockAllValidatorInfosResponse.next.mockResolvedValueOnce({ done: true }); - MOCK_ACTIVE_VALIDATOR_INFOS.forEach(value => - mockActiveValidatorInfosResponse.next.mockResolvedValueOnce({ value }), - ); - mockActiveValidatorInfosResponse.next.mockResolvedValueOnce({ done: true }); - - mockCtx = createHandlerContext({ - service: ViewService, - method: ViewService.methods.fMDParameters, - protocolName: 'mock', - requestMethod: 'MOCK', - url: '/mock', - contextValues: createContextValues().set( - stakeClientCtx, - mockStakeClient as unknown as PromiseClient, - ), - }); - }); - - it("includes the address's balance in the `ValueView` for delegation tokens the address holds", async () => { - const results: ( - | DelegationsByAddressIndexResponse - | PartialMessage - )[] = []; - - for await (const result of delegationsByAddressIndex( - new DelegationsByAddressIndexRequest({ addressIndex: { account: 0 } }), - mockCtx, - )) { - results.push(result); - } - - const firstValueView = new ValueView(results[0]!.valueView); - - expect(getAmount(firstValueView)).toEqual({ hi: 0n, lo: 2n }); - }); - - it("includes `ValidatorInfo` in the `ValueView`'s `extendedMetadata` property", async () => { - const results: ( - | DelegationsByAddressIndexResponse - | PartialMessage - )[] = []; - - for await (const result of delegationsByAddressIndex( - new DelegationsByAddressIndexRequest({ addressIndex: { account: 0 } }), - mockCtx, - )) { - results.push(result); - } - - const firstValueView = new ValueView(results[0]!.valueView); - const validatorInfo = getValidatorInfoFromValueView(firstValueView); - - expect(validatorInfo.toJson()).toEqual(activeValidatorInfoResponse.validatorInfo!.toJson()); - }); - - describe('when no filter option is passed', () => { - it('returns one `ValueView` for each active validator', async () => { - const results: ( - | DelegationsByAddressIndexResponse - | PartialMessage - )[] = []; - - for await (const result of delegationsByAddressIndex( - new DelegationsByAddressIndexRequest({ addressIndex: { account: 0 } }), - mockCtx, - )) { - results.push(result); - } - - expect(results.length).toBe(2); - }); - - it('returns a zero-balance `ValueView` for validators the address has no tokens for', async () => { - const results: ( - | DelegationsByAddressIndexResponse - | PartialMessage - )[] = []; - - for await (const result of delegationsByAddressIndex( - new DelegationsByAddressIndexRequest({ addressIndex: { account: 0 } }), - mockCtx, - )) { - results.push(result); - } - - const secondValueView = new ValueView(results[1]!.valueView); - - expect(getAmount(secondValueView)).toEqual({ hi: 0n, lo: 0n }); - }); - }); - - describe('when the nonzero balances filter option is passed', () => { - it('returns one `ValueView` for each validator the address has tokens for', async () => { - const results: ( - | DelegationsByAddressIndexResponse - | PartialMessage - )[] = []; - - for await (const result of delegationsByAddressIndex( - new DelegationsByAddressIndexRequest({ - addressIndex: { account: 0 }, - filter: DelegationsByAddressIndexRequest_Filter.ALL_ACTIVE_WITH_NONZERO_BALANCES, - }), - mockCtx, - )) { - results.push(result); - } - - expect(results.length).toBe(1); - }); - }); - - describe('when the `ALL` filter option is passed', () => { - it('returns one `ValueView` for each validator, including inactive ones', async () => { - const results: ( - | DelegationsByAddressIndexResponse - | PartialMessage - )[] = []; - - for await (const result of delegationsByAddressIndex( - new DelegationsByAddressIndexRequest({ - addressIndex: { account: 0 }, - filter: DelegationsByAddressIndexRequest_Filter.ALL, - }), - mockCtx, - )) { - results.push(result); - } - - expect(results.length).toBe(4); - }); - }); -}); diff --git a/packages/services/src/view-service/delegations-by-address-index.ts b/packages/services/src/view-service/delegations-by-address-index.ts deleted file mode 100644 index dad9ef31..00000000 --- a/packages/services/src/view-service/delegations-by-address-index.ts +++ /dev/null @@ -1,116 +0,0 @@ -import { IdentityKey } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb'; -import Array from '@penumbra-zone/polyfills/Array.fromAsync'; -import { customizeSymbol } from '@penumbra-zone/wasm/metadata'; -import { assetPatterns } from '@penumbra-zone/types/assets'; -import { bech32mIdentityKey } from '@penumbra-zone/bech32m/penumbravalid'; -import { Any, PartialMessage } from '@bufbuild/protobuf'; -import { getValidatorInfo } from '@penumbra-zone/getters/validator-info-response'; -import { getIdentityKeyFromValidatorInfo } from '@penumbra-zone/getters/validator-info'; -import { ValidatorInfo } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/stake/v1/stake_pb'; -import { - AssetMetadataByIdRequest, - BalancesRequest, - BalancesResponse, - DelegationsByAddressIndexRequest_Filter, - DelegationsByAddressIndexResponse, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; -import { stakeClientCtx } from '../ctx/stake-client'; -import { balances } from './balances'; -import { - Metadata, - ValueView, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; -import { assetMetadataById } from './asset-metadata-by-id'; -import { getDisplayDenomFromView } from '@penumbra-zone/getters/value-view'; -import { Impl } from '.'; - -const isDelegationBalance = (balance: BalancesResponse, identityKey: IdentityKey) => { - const match = assetPatterns.delegationToken.capture(getDisplayDenomFromView(balance.balanceView)); - if (!match) return false; - - return bech32mIdentityKey(identityKey) === match.idKey; -}; - -const getDelegationTokenBaseDenom = (validatorInfo: ValidatorInfo) => - `udelegation_${bech32mIdentityKey(getIdentityKeyFromValidatorInfo(validatorInfo))}`; - -const addressHasDelegationTokens = ( - delegation?: PartialMessage, -): delegation is PartialMessage & { balanceView: ValueView } => - delegation?.balanceView instanceof ValueView; - -export const delegationsByAddressIndex: Impl['delegationsByAddressIndex'] = async function* ( - req, - ctx, -) { - const { addressIndex } = req; - if (!addressIndex) { - throw new Error('Missing `addressIndex` in `DelegationsByAddressIndex` request'); - } - - const mockStakeClient = ctx.values.get(stakeClientCtx); - if (!mockStakeClient) throw new Error('Staking context not found'); - - const assetBalances = await Array.fromAsync( - balances(new BalancesRequest({ accountFilter: addressIndex }), ctx), - ); - - // See https://github.com/typescript-eslint/typescript-eslint/issues/7114 - // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison - const showInactive = req.filter === DelegationsByAddressIndexRequest_Filter.ALL; - - for await (const validatorInfoResponse of mockStakeClient.validatorInfo({ showInactive })) { - const validatorInfo = getValidatorInfo(validatorInfoResponse); - const extendedMetadata = new Any({ - typeUrl: ValidatorInfo.typeName, - value: validatorInfo.toBinary(), - }); - - const identityKey = getValidatorInfo.pipe(getIdentityKeyFromValidatorInfo)( - validatorInfoResponse, - ); - const delegation = assetBalances.find(balance => - isDelegationBalance(new BalancesResponse(balance), identityKey), - ); - - if (addressHasDelegationTokens(delegation)) { - const withValidatorInfo = delegation.balanceView.clone(); - - if (withValidatorInfo.valueView.case !== 'knownAssetId') - throw new Error(`Unexpected ValueView case: ${withValidatorInfo.valueView.case}`); - - withValidatorInfo.valueView.value.extendedMetadata = extendedMetadata; - - yield new DelegationsByAddressIndexResponse({ valueView: withValidatorInfo }); - } else { - // See https://github.com/typescript-eslint/typescript-eslint/issues/7114 - // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison - if (req.filter === DelegationsByAddressIndexRequest_Filter.ALL_ACTIVE_WITH_NONZERO_BALANCES) { - continue; - } - - const { denomMetadata } = await assetMetadataById( - new AssetMetadataByIdRequest({ - assetId: { altBaseDenom: getDelegationTokenBaseDenom(validatorInfo) }, - }), - ctx, - ); - - yield new DelegationsByAddressIndexResponse({ - valueView: { - valueView: { - case: 'knownAssetId', - value: { - amount: { - hi: 0n, - lo: 0n, - }, - metadata: denomMetadata ? customizeSymbol(new Metadata(denomMetadata)) : undefined, - extendedMetadata, - }, - }, - }, - }); - } - } -}; diff --git a/packages/services/src/view-service/ephemeral-address.test.ts b/packages/services/src/view-service/ephemeral-address.test.ts deleted file mode 100644 index 51cf3007..00000000 --- a/packages/services/src/view-service/ephemeral-address.test.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { beforeEach, describe, expect, test } from 'vitest'; -import { - EphemeralAddressRequest, - EphemeralAddressResponse, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; -import { createContextValues, createHandlerContext, HandlerContext } from '@connectrpc/connect'; -import { ViewService } from '@penumbra-zone/protobuf'; -import { Address } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb'; -import { ephemeralAddress } from './ephemeral-address'; -import { testFullViewingKey } from '../test-utils'; -import { fvkCtx } from '../ctx/full-viewing-key'; - -describe('EphemeralAddress request handler', () => { - let mockCtx: HandlerContext; - - beforeEach(() => { - mockCtx = createHandlerContext({ - service: ViewService, - method: ViewService.methods.ephemeralAddress, - protocolName: 'mock', - requestMethod: 'MOCK', - url: '/mock', - contextValues: createContextValues().set(fvkCtx, () => Promise.resolve(testFullViewingKey)), - }); - }); - - test('should successfully get EphemeralAddress', async () => { - const ephemeralAddressResponse = await ephemeralAddress( - new EphemeralAddressRequest({ addressIndex: { account: 0 } }), - mockCtx, - ); - expect(ephemeralAddressResponse.address).toBeInstanceOf(Address); - }); - - test('should get an error if addressIndex is missing', async () => { - await expect(ephemeralAddress(new EphemeralAddressRequest(), mockCtx)).rejects.toThrow( - 'Missing address index', - ); - }); - - test('addresses with different indexes should be different', async () => { - const ephemeral1Response = new EphemeralAddressResponse( - await ephemeralAddress( - new EphemeralAddressRequest({ addressIndex: { account: 1 } }), - mockCtx, - ), - ); - const ephemeral2Response = new EphemeralAddressResponse( - await ephemeralAddress( - new EphemeralAddressRequest({ addressIndex: { account: 2 } }), - mockCtx, - ), - ); - expect(ephemeral1Response.address?.equals(ephemeral2Response.address)).toBeFalsy(); - }); - - test('addresses with same indexes should be different', async () => { - const ephemeralFirst = new EphemeralAddressResponse( - await ephemeralAddress( - new EphemeralAddressRequest({ addressIndex: { account: 3 } }), - mockCtx, - ), - ); - const ephemeralSecond = new EphemeralAddressResponse( - await ephemeralAddress( - new EphemeralAddressRequest({ addressIndex: { account: 3 } }), - mockCtx, - ), - ); - expect(ephemeralFirst.address?.equals(ephemeralSecond.address)).toBeFalsy(); - }); -}); diff --git a/packages/services/src/view-service/ephemeral-address.ts b/packages/services/src/view-service/ephemeral-address.ts deleted file mode 100644 index 5017c0b1..00000000 --- a/packages/services/src/view-service/ephemeral-address.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { Impl } from '.'; - -import { getEphemeralByIndex } from '@penumbra-zone/wasm/keys'; -import { fvkCtx } from '../ctx/full-viewing-key'; - -export const ephemeralAddress: Impl['ephemeralAddress'] = async (req, ctx) => { - if (!req.addressIndex) { - throw new Error('Missing address index'); - } - const fvk = ctx.values.get(fvkCtx); - const address = getEphemeralByIndex(await fvk(), req.addressIndex.account); - - return { address }; -}; diff --git a/packages/services/src/view-service/fmd-parameters.test.ts b/packages/services/src/view-service/fmd-parameters.test.ts deleted file mode 100644 index cd3a3c80..00000000 --- a/packages/services/src/view-service/fmd-parameters.test.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { beforeEach, describe, expect, test, vi } from 'vitest'; -import { - FMDParametersRequest, - FMDParametersResponse, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; -import { createContextValues, createHandlerContext, HandlerContext } from '@connectrpc/connect'; -import { ViewService } from '@penumbra-zone/protobuf'; -import { servicesCtx } from '../ctx/prax'; -import { IndexedDbMock, MockServices } from '../test-utils'; -import { FmdParameters } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/shielded_pool/v1/shielded_pool_pb'; -import { fMDParameters } from './fmd-parameters'; -import type { ServicesInterface } from '@penumbra-zone/types/services'; - -describe('FmdParameters request handler', () => { - let mockServices: MockServices; - let mockIndexedDb: IndexedDbMock; - let mockCtx: HandlerContext; - - beforeEach(() => { - vi.resetAllMocks(); - - mockIndexedDb = { - getFmdParams: vi.fn(), - }; - mockServices = { - getWalletServices: vi.fn(() => - Promise.resolve({ indexedDb: mockIndexedDb }), - ) as MockServices['getWalletServices'], - }; - mockCtx = createHandlerContext({ - service: ViewService, - method: ViewService.methods.fMDParameters, - protocolName: 'mock', - requestMethod: 'MOCK', - url: '/mock', - contextValues: createContextValues().set(servicesCtx, () => - Promise.resolve(mockServices as unknown as ServicesInterface), - ), - }); - }); - - test('should successfully get fmdParameters when idb has them', async () => { - mockIndexedDb.getFmdParams?.mockResolvedValue(testData); - const fmdParameterResponse = new FMDParametersResponse( - await fMDParameters(new FMDParametersRequest(), mockCtx), - ); - expect(fmdParameterResponse.parameters?.equals(testData)).toBeTruthy(); - }); - - test('should fail to get fmdParameters when idb has none', async () => { - mockIndexedDb.getFmdParams?.mockResolvedValue(undefined); - await expect(fMDParameters(new FMDParametersRequest(), mockCtx)).rejects.toThrow(); - }); -}); - -const testData = new FmdParameters({ asOfBlockHeight: 1n, precisionBits: 0 }); diff --git a/packages/services/src/view-service/fmd-parameters.ts b/packages/services/src/view-service/fmd-parameters.ts deleted file mode 100644 index 572854d4..00000000 --- a/packages/services/src/view-service/fmd-parameters.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type { Impl } from '.'; -import { servicesCtx } from '../ctx/prax'; - -import { Code, ConnectError } from '@connectrpc/connect'; - -export const fMDParameters: Impl['fMDParameters'] = async (_, ctx) => { - const services = await ctx.values.get(servicesCtx)(); - const { indexedDb } = await services.getWalletServices(); - const parameters = await indexedDb.getFmdParams(); - if (!parameters) throw new ConnectError('No FMD parameters', Code.FailedPrecondition); - return { parameters }; -}; diff --git a/packages/services/src/view-service/gas-prices.test.ts b/packages/services/src/view-service/gas-prices.test.ts deleted file mode 100644 index d918b09b..00000000 --- a/packages/services/src/view-service/gas-prices.test.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { beforeEach, describe, expect, test, vi } from 'vitest'; -import { - GasPricesRequest, - GasPricesResponse, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; -import { createContextValues, createHandlerContext, HandlerContext } from '@connectrpc/connect'; -import { ViewService } from '@penumbra-zone/protobuf'; -import { servicesCtx } from '../ctx/prax'; -import { IndexedDbMock, MockServices } from '../test-utils'; -import { GasPrices } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/fee/v1/fee_pb'; -import { gasPrices } from './gas-prices'; -import type { ServicesInterface } from '@penumbra-zone/types/services'; - -describe('GasPrices request handler', () => { - let mockServices: MockServices; - let mockIndexedDb: IndexedDbMock; - let mockCtx: HandlerContext; - - beforeEach(() => { - vi.resetAllMocks(); - - mockIndexedDb = { - getGasPrices: vi.fn(), - }; - mockServices = { - getWalletServices: vi.fn(() => - Promise.resolve({ indexedDb: mockIndexedDb }), - ) as MockServices['getWalletServices'], - }; - mockCtx = createHandlerContext({ - service: ViewService, - method: ViewService.methods.gasPrices, - protocolName: 'mock', - requestMethod: 'MOCK', - url: '/mock', - contextValues: createContextValues().set(servicesCtx, () => - Promise.resolve(mockServices as unknown as ServicesInterface), - ), - }); - }); - - test('should successfully get gas prices when idb has them', async () => { - mockIndexedDb.getGasPrices?.mockResolvedValue(testData); - const gasPricesResponse = new GasPricesResponse( - await gasPrices(new GasPricesRequest(), mockCtx), - ); - expect(gasPricesResponse.gasPrices?.equals(testData)).toBeTruthy(); - }); - - test('should fail to get gas prices when idb has none', async () => { - mockIndexedDb.getGasPrices?.mockResolvedValue(undefined); - await expect(gasPrices(new GasPricesRequest(), mockCtx)).rejects.toThrow( - 'Gas prices is not available', - ); - }); -}); - -const testData = new GasPrices({ - blockSpacePrice: 22n, - executionPrice: 12n, - verificationPrice: 222n, - compactBlockSpacePrice: 122n, -}); diff --git a/packages/services/src/view-service/gas-prices.ts b/packages/services/src/view-service/gas-prices.ts deleted file mode 100644 index 954f139f..00000000 --- a/packages/services/src/view-service/gas-prices.ts +++ /dev/null @@ -1,32 +0,0 @@ -import type { Impl } from '.'; -import { servicesCtx } from '../ctx/prax'; -import { Code, ConnectError } from '@connectrpc/connect'; - -/** - * Gas prices are published within the 'CompactBlock' whenever they change. The specific block - * in which the Gas prices change is unknown and the current Gas prices cannot be retrieved - * directly from the penumbra full node. - * - * The process can be visualized as follows: - * height:0 - Gas prices are published in a block - * ... - * height:288 - - * height:289 - Gas prices are published in another block. - * ... - * height:382 - - * height:383 - A user needs to create a transaction and needs the gas prices. However, it is - * unknown which block contains the current gas prices. - * - * To handle this, the last known value of the Gas prices should be cached in IndexedDB - * as the blocks are scanned. This way, it can be readily accessed when needed. - */ -export const gasPrices: Impl['gasPrices'] = async (_, ctx) => { - const services = await ctx.values.get(servicesCtx)(); - const { indexedDb } = await services.getWalletServices(); - const gasPrices = await indexedDb.getGasPrices(); - if (!gasPrices) throw new ConnectError('Gas prices is not available', Code.NotFound); - - return { - gasPrices, - }; -}; diff --git a/packages/services/src/view-service/index-by-address.test.ts b/packages/services/src/view-service/index-by-address.test.ts deleted file mode 100644 index b76ce2d2..00000000 --- a/packages/services/src/view-service/index-by-address.test.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { beforeEach, describe, expect, test } from 'vitest'; -import { IndexByAddressRequest } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; -import { createContextValues, createHandlerContext, HandlerContext } from '@connectrpc/connect'; -import { ViewService } from '@penumbra-zone/protobuf'; -import { - Address, - FullViewingKey, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb'; -import { indexByAddress } from './index-by-address'; -import { getAddressByIndex, getEphemeralByIndex } from '@penumbra-zone/wasm/keys'; -import { fullViewingKeyFromBech32m } from '@penumbra-zone/bech32m/penumbrafullviewingkey'; -import { testFullViewingKey } from '../test-utils'; -import { fvkCtx } from '../ctx/full-viewing-key'; - -describe('IndexByAddress request handler', () => { - let mockCtx: HandlerContext; - let testAddress: Address; - - beforeEach(() => { - mockCtx = createHandlerContext({ - service: ViewService, - method: ViewService.methods.indexByAddress, - protocolName: 'mock', - requestMethod: 'MOCK', - url: '/mock', - contextValues: createContextValues().set(fvkCtx, () => Promise.resolve(testFullViewingKey)), - }); - - testAddress = getAddressByIndex(testFullViewingKey, 0); - }); - - test('should successfully get index for a given address', async () => { - const addressByIndexResponse = await indexByAddress( - new IndexByAddressRequest({ address: testAddress }), - mockCtx, - ); - expect(addressByIndexResponse.addressIndex?.account === 0).toBeTruthy(); - }); - - test('should successfully get index for ephemeral address', async () => { - testAddress = getEphemeralByIndex(testFullViewingKey, 2); - - const addressByIndexResponse = await indexByAddress( - new IndexByAddressRequest({ address: testAddress }), - mockCtx, - ); - expect(addressByIndexResponse.addressIndex?.account === 2).toBeTruthy(); - }); - - test('should return empty index for address that is associated with another FVK', async () => { - const anotherFVK = new FullViewingKey( - fullViewingKeyFromBech32m( - 'penumbrafullviewingkey1f33fr3zrquh869s3h8d0pjx4fpa9fyut2utw7x5y7xdcxz6z7c8sgf5hslrkpf3mh8d26vufsq8y666chx0x0su06ay3rkwu74zuwqq9w8aza', - ), - ); - - testAddress = getEphemeralByIndex(anotherFVK, 5); - - const addressByIndexResponse = await indexByAddress( - new IndexByAddressRequest({ address: testAddress }), - mockCtx, - ); - expect(addressByIndexResponse.addressIndex).toBeUndefined(); - }); -}); diff --git a/packages/services/src/view-service/index-by-address.ts b/packages/services/src/view-service/index-by-address.ts deleted file mode 100644 index 94231e3a..00000000 --- a/packages/services/src/view-service/index-by-address.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { Impl } from '.'; - -import { getAddressIndexByAddress } from '@penumbra-zone/wasm/address'; - -import { Code, ConnectError } from '@connectrpc/connect'; -import { fvkCtx } from '../ctx/full-viewing-key'; - -export const indexByAddress: Impl['indexByAddress'] = async (req, ctx) => { - if (!req.address) throw new ConnectError('no address given in request', Code.InvalidArgument); - const fvk = ctx.values.get(fvkCtx); - const addressIndex = getAddressIndexByAddress(await fvk(), req.address); - - if (!addressIndex) return {}; - - return { addressIndex }; -}; diff --git a/packages/services/src/view-service/index.ts b/packages/services/src/view-service/index.ts deleted file mode 100644 index 4d3ce738..00000000 --- a/packages/services/src/view-service/index.ts +++ /dev/null @@ -1,65 +0,0 @@ -import type { ServiceImpl } from '@connectrpc/connect'; -import type { ViewService } from '@penumbra-zone/protobuf'; -import { addressByIndex } from './address-by-index'; -import { appParameters } from './app-parameters'; -import { assetMetadataById } from './asset-metadata-by-id'; -import { assets } from './assets'; -import { auctions } from './auctions'; -import { authorizeAndBuild } from './authorize-and-build'; -import { balances } from './balances'; -import { broadcastTransaction } from './broadcast-transaction'; -import { delegationsByAddressIndex } from './delegations-by-address-index'; -import { ephemeralAddress } from './ephemeral-address'; -import { fMDParameters } from './fmd-parameters'; -import { gasPrices } from './gas-prices'; -import { indexByAddress } from './index-by-address'; -import { noteByCommitment } from './note-by-commitment'; -import { notes } from './notes'; -import { notesForVoting } from './notes-for-voting'; -import { nullifierStatus } from './nullifier-status'; -import { ownedPositionIds } from './owned-position-ids'; -import { status } from './status'; -import { statusStream } from './status-stream'; -import { swapByCommitment } from './swap-by-commitment'; -import { transactionInfo } from './transaction-info'; -import { transactionInfoByHash } from './transaction-info-by-hash'; -import { transactionPlanner } from './transaction-planner'; -import { unbondingTokensByAddressIndex } from './unbonding-tokens-by-address-index'; -import { unclaimedSwaps } from './unclaimed-swaps'; -import { walletId } from './wallet-id'; -import { witness } from './witness'; -import { witnessAndBuild } from './witness-and-build'; - -export type Impl = ServiceImpl; - -export const viewImpl: Impl = { - addressByIndex, - appParameters, - assetMetadataById, - assets, - auctions, - authorizeAndBuild, - balances, - broadcastTransaction, - delegationsByAddressIndex, - ephemeralAddress, - fMDParameters, - gasPrices, - indexByAddress, - noteByCommitment, - notes, - notesForVoting, - nullifierStatus, - ownedPositionIds, - status, - statusStream, - swapByCommitment, - transactionInfo, - transactionInfoByHash, - transactionPlanner, - unbondingTokensByAddressIndex, - unclaimedSwaps, - walletId, - witness, - witnessAndBuild, -}; diff --git a/packages/services/src/view-service/note-by-commitment.test.ts b/packages/services/src/view-service/note-by-commitment.test.ts deleted file mode 100644 index 255cd1ed..00000000 --- a/packages/services/src/view-service/note-by-commitment.test.ts +++ /dev/null @@ -1,143 +0,0 @@ -import { beforeEach, describe, expect, Mock, test, vi } from 'vitest'; -import { - NoteByCommitmentRequest, - NoteByCommitmentResponse, - SpendableNoteRecord, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; -import { createContextValues, createHandlerContext, HandlerContext } from '@connectrpc/connect'; -import { ViewService } from '@penumbra-zone/protobuf'; -import { servicesCtx } from '../ctx/prax'; -import { IndexedDbMock, MockServices } from '../test-utils'; -import { StateCommitment } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/crypto/tct/v1/tct_pb'; -import { noteByCommitment } from './note-by-commitment'; -import type { ServicesInterface } from '@penumbra-zone/types/services'; - -describe('NoteByCommitment request handler', () => { - let mockServices: MockServices; - let mockIndexedDb: IndexedDbMock; - let mockCtx: HandlerContext; - let request: NoteByCommitmentRequest; - let noteSubNext: Mock; - - beforeEach(() => { - vi.resetAllMocks(); - - noteSubNext = vi.fn(); - const mockNoteSubscription = { - next: noteSubNext, - [Symbol.asyncIterator]: () => mockNoteSubscription, - }; - - mockIndexedDb = { - getSpendableNoteByCommitment: vi.fn(), - subscribe: () => mockNoteSubscription, - }; - mockServices = { - getWalletServices: vi.fn(() => - Promise.resolve({ indexedDb: mockIndexedDb }), - ) as MockServices['getWalletServices'], - }; - mockCtx = createHandlerContext({ - service: ViewService, - method: ViewService.methods.noteByCommitment, - protocolName: 'mock', - requestMethod: 'MOCK', - url: '/mock', - contextValues: createContextValues().set(servicesCtx, () => - Promise.resolve(mockServices as unknown as ServicesInterface), - ), - }); - - request = new NoteByCommitmentRequest({ noteCommitment: testCommitment }); - }); - - test('should successfully get note by commitment when idb has them', async () => { - mockIndexedDb.getSpendableNoteByCommitment?.mockResolvedValue(testNote); - const noteByCommitmentResponse = new NoteByCommitmentResponse( - await noteByCommitment(request, mockCtx), - ); - expect(noteByCommitmentResponse.spendableNote?.equals(testNote)).toBeTruthy(); - }); - - test('should throw error if commitment is missing in request', async () => { - await expect(noteByCommitment(new NoteByCommitmentRequest(), mockCtx)).rejects.toThrow( - 'Missing note commitment in request', - ); - }); - - test('should throw an error if note no found in idb and awaitDetection is false', async () => { - mockIndexedDb.getSpendableNoteByCommitment?.mockResolvedValue(undefined); - request.awaitDetection = false; - await expect(noteByCommitment(request, mockCtx)).rejects.toThrow('Note not found'); - }); - - test('should get note if note is not found in idb, but awaitDetection is true, and has been detected', async () => { - mockIndexedDb.getSpendableNoteByCommitment?.mockResolvedValue(undefined); - request.awaitDetection = true; - noteSubNext.mockResolvedValueOnce({ - value: { value: testNote.toJson() }, - }); - const noteByCommitmentResponse = new NoteByCommitmentResponse( - await noteByCommitment(request, mockCtx), - ); - expect(noteByCommitmentResponse.spendableNote?.equals(testNote)).toBeTruthy(); - }); - - test('should throw error if note is not found in idb, and has not been detected', async () => { - mockIndexedDb.getSpendableNoteByCommitment?.mockResolvedValue(undefined); - request.awaitDetection = true; - - noteSubNext.mockResolvedValueOnce({ - value: { value: noteWithAnotherCommitment.toJson() }, - }); - noteSubNext.mockResolvedValueOnce({ - done: true, - }); - await expect(noteByCommitment(request, mockCtx)).rejects.toThrow('Note not found'); - }); -}); - -const testCommitment = StateCommitment.fromJson({ - inner: 'pXS1k2kvlph+vuk9uhqeoP1mZRc+f526a06/bg3EBwQ=', -}); - -const testNote = SpendableNoteRecord.fromJson({ - noteCommitment: { - inner: 'pXS1k2kvlph+vuk9uhqeoP1mZRc+f526a06/bg3EBwQ=', - }, - note: { - value: { - amount: { - lo: '12000000', - }, - assetId: { - inner: 'KeqcLzNx9qSH5+lcJHBB9KNW+YPrBk5dKzvPMiypahA=', - }, - }, - rseed: 'h04XyitXpY1Q77M+vSzPauf4ZPx9NNRBAuUcVqP6pWo=', - address: { - inner: - '874bHlYDfy3mT57v2bXQWm3SJ7g8LI3cZFKob8J8CfrP2aqVGo6ESrpGScI4t/B2/KgkjhzmAasx8GM1ejNz0J153vD8MBVM9FUZFACzSCg=', - }, - }, - addressIndex: { - account: 12, - randomizer: 'AAAAAAAAAAAAAAAA', - }, - nullifier: { - inner: 'fv/wPZDA5L96Woc+Ry2s7u9IrwNxTFjSDYInZj3lRA8=', - }, - heightCreated: '7197', - position: '42986962944', - source: { - transaction: { - id: '3CBS08dM9eLHH45Z9loZciZ9RaG9x1fc26Qnv0lQlto=', - }, - }, -}); - -const noteWithAnotherCommitment = SpendableNoteRecord.fromJson({ - noteCommitment: { - inner: '2x5KAgUMdC2Gg2aZmj0bZFa5eQv2z9pQlSFfGXcgHQk=', - }, -}); diff --git a/packages/services/src/view-service/note-by-commitment.ts b/packages/services/src/view-service/note-by-commitment.ts deleted file mode 100644 index a324eefb..00000000 --- a/packages/services/src/view-service/note-by-commitment.ts +++ /dev/null @@ -1,25 +0,0 @@ -import type { Impl } from '.'; -import { servicesCtx } from '../ctx/prax'; - -import { SpendableNoteRecord } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; - -import { Code, ConnectError } from '@connectrpc/connect'; - -export const noteByCommitment: Impl['noteByCommitment'] = async (req, ctx) => { - const services = await ctx.values.get(servicesCtx)(); - const { indexedDb } = await services.getWalletServices(); - if (!req.noteCommitment) - throw new ConnectError('Missing note commitment in request', Code.InvalidArgument); - - const noteByCommitment = await indexedDb.getSpendableNoteByCommitment(req.noteCommitment); - if (noteByCommitment) return { spendableNote: noteByCommitment }; - - // Wait until our DB encounters a new note with this commitment - if (req.awaitDetection) { - for await (const update of indexedDb.subscribe('SPENDABLE_NOTES')) { - const spendableNote = SpendableNoteRecord.fromJson(update.value); - if (spendableNote.noteCommitment?.equals(req.noteCommitment)) return { spendableNote }; - } - } - throw new ConnectError('Note not found', Code.NotFound); -}; diff --git a/packages/services/src/view-service/notes-for-voting.test.ts b/packages/services/src/view-service/notes-for-voting.test.ts deleted file mode 100644 index d190afd0..00000000 --- a/packages/services/src/view-service/notes-for-voting.test.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { beforeEach, describe, expect, test, vi } from 'vitest'; -import { - NotesForVotingRequest, - NotesForVotingResponse, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; -import { createContextValues, createHandlerContext, HandlerContext } from '@connectrpc/connect'; -import { ViewService } from '@penumbra-zone/protobuf'; -import { servicesCtx } from '../ctx/prax'; -import { IndexedDbMock, MockServices } from '../test-utils'; -import { notesForVoting } from './notes-for-voting'; -import type { ServicesInterface } from '@penumbra-zone/types/services'; - -describe('NotesForVoting request handler', () => { - let mockServices: MockServices; - let mockIndexedDb: IndexedDbMock; - let mockCtx: HandlerContext; - - beforeEach(() => { - vi.resetAllMocks(); - - mockIndexedDb = { - getNotesForVoting: vi.fn(), - }; - mockServices = { - getWalletServices: vi.fn(() => - Promise.resolve({ indexedDb: mockIndexedDb }), - ) as MockServices['getWalletServices'], - }; - mockCtx = createHandlerContext({ - service: ViewService, - method: ViewService.methods.notesForVoting, - protocolName: 'mock', - requestMethod: 'MOCK', - url: '/mock', - contextValues: createContextValues().set(servicesCtx, () => - Promise.resolve(mockServices as unknown as ServicesInterface), - ), - }); - }); - - test('should successfully get notes for voting', async () => { - mockIndexedDb.getNotesForVoting?.mockResolvedValueOnce(testData); - const responses: NotesForVotingResponse[] = []; - const req = new NotesForVotingRequest({}); - for await (const res of notesForVoting(req, mockCtx)) { - responses.push(new NotesForVotingResponse(res)); - } - expect(responses.length).toBe(2); - }); -}); - -const testData: NotesForVotingResponse[] = [ - NotesForVotingResponse.fromJson({ - noteRecord: { - noteCommitment: { - inner: 'pXS1k2kvlph+vuk9uhqeoP1mZRc+f526a06/bg3EBwQ=', - }, - }, - identityKey: { - ik: 'VAv+z5ieJk7AcAIJoVIqB6boOj0AhZB2FKWsEidfvAE=', - }, - }), - NotesForVotingResponse.fromJson({ - noteRecord: { - noteCommitment: { - inner: '2XS1k2kvlph+vuk9uhqeoP1mZRc+f526a06/bg3EBwQ=', - }, - }, - identityKey: { - ik: 'pkxdxOn9EMqdjoCJdEGBKA8XY9P9RK9XmurIly/9yBA=', - }, - }), -]; diff --git a/packages/services/src/view-service/notes-for-voting.ts b/packages/services/src/view-service/notes-for-voting.ts deleted file mode 100644 index 1bf0d7ae..00000000 --- a/packages/services/src/view-service/notes-for-voting.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type { Impl } from '.'; -import { servicesCtx } from '../ctx/prax'; - -export const notesForVoting: Impl['notesForVoting'] = async function* (req, ctx) { - const services = await ctx.values.get(servicesCtx)(); - const { indexedDb } = await services.getWalletServices(); - const votingNotes = await indexedDb.getNotesForVoting(req.addressIndex, req.votableAtHeight); - - yield* votingNotes; -}; diff --git a/packages/services/src/view-service/notes.test.ts b/packages/services/src/view-service/notes.test.ts deleted file mode 100644 index db788e28..00000000 --- a/packages/services/src/view-service/notes.test.ts +++ /dev/null @@ -1,495 +0,0 @@ -import { notes } from './notes'; - -import { ViewService } from '@penumbra-zone/protobuf'; -import { servicesCtx } from '../ctx/prax'; - -import { createContextValues, createHandlerContext, HandlerContext } from '@connectrpc/connect'; - -import { beforeEach, describe, expect, test, vi } from 'vitest'; - -import { AssetId } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; -import { AddressIndex } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb'; -import { - NotesRequest, - NotesResponse, - SpendableNoteRecord, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; -import { IndexedDbMock, MockServices } from '../test-utils'; -import type { ServicesInterface } from '@penumbra-zone/types/services'; - -describe('Notes request handler', () => { - let mockServices: MockServices; - let mockCtx: HandlerContext; - let mockIndexedDb: IndexedDbMock; - - beforeEach(() => { - vi.resetAllMocks(); - - const mockIterateSpendableNotes = { - next: vi.fn(), - [Symbol.asyncIterator]: () => mockIterateSpendableNotes, - }; - - mockIndexedDb = { - iterateSpendableNotes: () => mockIterateSpendableNotes, - }; - - mockServices = { - getWalletServices: vi.fn(() => - Promise.resolve({ indexedDb: mockIndexedDb }), - ) as MockServices['getWalletServices'], - }; - - mockCtx = createHandlerContext({ - service: ViewService, - method: ViewService.methods.notes, - protocolName: 'mock', - requestMethod: 'MOCK', - url: '/mock', - contextValues: createContextValues().set(servicesCtx, () => - Promise.resolve(mockServices as unknown as ServicesInterface), - ), - }); - - for (const record of testData) { - mockIterateSpendableNotes.next.mockResolvedValueOnce({ - value: record, - }); - } - mockIterateSpendableNotes.next.mockResolvedValueOnce({ - done: true, - }); - }); - - test('should get all unspent notes if the query is empty', async () => { - const responses: NotesResponse[] = []; - const req = new NotesRequest({}); - for await (const res of notes(req, mockCtx)) { - responses.push(new NotesResponse(res)); - } - expect(responses.length).toBe(5); - }); - - test('should get all unspent notes if if includeSpent is false', async () => { - const responses: NotesResponse[] = []; - const req = new NotesRequest({ - includeSpent: false, - }); - for await (const res of notes(req, mockCtx)) { - responses.push(new NotesResponse(res)); - } - expect(responses.length).toBe(5); - }); - - test('should get both spent and unspent notes, if includeSpent is true', async () => { - const responses: NotesResponse[] = []; - const req = new NotesRequest({ - includeSpent: true, - }); - for await (const res of notes(req, mockCtx)) { - responses.push(new NotesResponse(res)); - } - expect(responses.length).toBe(6); - }); - - test('should get unspent notes with a given assetId', async () => { - const responses: NotesResponse[] = []; - - const assetId = AssetId.fromJson({ - inner: 'KeqcLzNx9qSH5+lcJHBB9KNW+YPrBk5dKzvPMiypahA=', - }); - - const req = new NotesRequest({ - assetId, - }); - for await (const res of notes(req, mockCtx)) { - responses.push(new NotesResponse(res)); - } - expect(responses.length).toBe(4); - }); - - test('should get unspent and spent notes with a given assetId and includeSpent is true', async () => { - const responses: NotesResponse[] = []; - - const assetId = AssetId.fromJson({ - inner: 'KeqcLzNx9qSH5+lcJHBB9KNW+YPrBk5dKzvPMiypahA=', - }); - - const req = new NotesRequest({ - includeSpent: true, - assetId, - }); - for await (const res of notes(req, mockCtx)) { - responses.push(new NotesResponse(res)); - } - expect(responses.length).toBe(5); - }); - - test('should get unspent and spent notes with a given addressIndex and includeSpent is true', async () => { - const responses: NotesResponse[] = []; - - const addressIndex = AddressIndex.fromJson({ - account: 99, - randomizer: 'AAAAAAAAAAAAAAAA', - }); - - const req = new NotesRequest({ - includeSpent: true, - addressIndex, - }); - for await (const res of notes(req, mockCtx)) { - responses.push(new NotesResponse(res)); - } - expect(responses.length).toBe(1); - }); - - test('should get unspent notes with a given addressIndex', async () => { - const responses: NotesResponse[] = []; - - const addressIndex = AddressIndex.fromJson({ - account: 99, - randomizer: 'AAAAAAAAAAAAAAAA', - }); - - const req = new NotesRequest({ - addressIndex, - }); - for await (const res of notes(req, mockCtx)) { - responses.push(new NotesResponse(res)); - } - expect(responses.length).toBe(0); - }); - - test('should get unspent and spent notes with a given addressIndex and given assetId and includeSpent is true', async () => { - const responses: NotesResponse[] = []; - - const addressIndex = AddressIndex.fromJson({ - account: 99, - randomizer: 'AAAAAAAAAAAAAAAA', - }); - const assetId = AssetId.fromJson({ - inner: 'KeqcLzNx9qSH5+lcJHBB9KNW+YPrBk5dKzvPMiypahA=', - }); - - const req = new NotesRequest({ - includeSpent: true, - addressIndex, - assetId, - }); - for await (const res of notes(req, mockCtx)) { - responses.push(new NotesResponse(res)); - } - expect(responses.length).toBe(1); - }); - - test('should get unspent notes with a given addressIndex and given assetId', async () => { - const responses: NotesResponse[] = []; - - const addressIndex = AddressIndex.fromJson({ - account: 99, - randomizer: 'AAAAAAAAAAAAAAAA', - }); - const assetId = AssetId.fromJson({ - inner: 'KeqcLzNx9qSH5+lcJHBB9KNW+YPrBk5dKzvPMiypahA=', - }); - - const req = new NotesRequest({ - addressIndex, - assetId, - }); - for await (const res of notes(req, mockCtx)) { - responses.push(new NotesResponse(res)); - } - expect(responses.length).toBe(0); - }); - - test('should get notes total exceeding the specified amountToSpend given assetId and amountToSpend', async () => { - const responses: NotesResponse[] = []; - - const assetId = AssetId.fromJson({ - inner: 'KeqcLzNx9qSH5+lcJHBB9KNW+YPrBk5dKzvPMiypahA=', - }); - - const amountToSpend = { - lo: 24000000n, - ho: 0n, - }; - - const req = new NotesRequest({ - assetId, - amountToSpend, - }); - for await (const res of notes(req, mockCtx)) { - responses.push(new NotesResponse(res)); - } - expect(responses.length).toBe(2); - }); - - test('should get an empty array when assetId is set and amountToSpend is zero', async () => { - const responses: NotesResponse[] = []; - - const assetId = AssetId.fromJson({ - inner: 'KeqcLzNx9qSH5+lcJHBB9KNW+YPrBk5dKzvPMiypahA=', - }); - - const amountToSpend = { - lo: 0n, - ho: 0n, - }; - - const req = new NotesRequest({ - assetId, - amountToSpend, - }); - for await (const res of notes(req, mockCtx)) { - responses.push(new NotesResponse(res)); - } - expect(responses.length).toBe(1); - }); - - test('should ignore amountToSpend filter when assetId is not set', async () => { - const responses: NotesResponse[] = []; - - const amountToSpend = { - lo: 0n, - ho: 0n, - }; - - const req = new NotesRequest({ - amountToSpend, - }); - for await (const res of notes(req, mockCtx)) { - responses.push(new NotesResponse(res)); - } - expect(responses.length).toBe(5); - }); - - test('should ignore the filter when assetId, amountToSpend are set but includeSpent is true', async () => { - const responses: NotesResponse[] = []; - - const assetId = AssetId.fromJson({ - inner: 'KeqcLzNx9qSH5+lcJHBB9KNW+YPrBk5dKzvPMiypahA=', - }); - - const amountToSpend = { - lo: 0n, - ho: 0n, - }; - - const req = new NotesRequest({ - assetId, - amountToSpend, - includeSpent: true, - }); - - for await (const res of notes(req, mockCtx)) { - responses.push(new NotesResponse(res)); - } - - expect(responses.length).toBe(5); - }); -}); - -const testData: SpendableNoteRecord[] = [ - SpendableNoteRecord.fromJson({ - noteCommitment: { - inner: 'pXS1k2kvlph+vuk9uhqeoP1mZRc+f526a06/bg3EBwQ=', - }, - heightSpent: '124342342', - note: { - value: { - amount: { - lo: '12000000', - }, - assetId: { - inner: 'KeqcLzNx9qSH5+lcJHBB9KNW+YPrBk5dKzvPMiypahA=', - }, - }, - rseed: 'h04XyitXpY1Q77M+vSzPauf4ZPx9NNRBAuUcVqP6pWo=', - address: { - inner: - '874bHlYDfy3mT57v2bXQWm3SJ7g8LI3cZFKob8J8CfrP2aqVGo6ESrpGScI4t/B2/KgkjhzmAasx8GM1ejNz0J153vD8MBVM9FUZFACzSCg=', - }, - }, - addressIndex: { - account: 99, - randomizer: 'AAAAAAAAAAAAAAAA', - }, - nullifier: { - inner: 'fv/wPZDA5L96Woc+Ry2s7u9IrwNxTFjSDYInZj3lRA8=', - }, - heightCreated: '7197', - position: '42986962944', - source: { - transaction: { id: '3CBS08dM9eLHH45Z9loZciZ9RaG9x1fc26Qnv0lQlto=' }, - }, - }), - SpendableNoteRecord.fromJson({ - noteCommitment: { - inner: 'pXS1k2kvlph+vuk9uhqeoP1mZRc+f526a06/bg3EBwQ=', - }, - note: { - value: { - amount: { - lo: '12000000', - }, - assetId: { - inner: 'KeqcLzNx9qSH5+lcJHBB9KNW+YPrBk5dKzvPMiypahA=', - }, - }, - rseed: 'h04XyitXpY1Q77M+vSzPauf4ZPx9NNRBAuUcVqP6pWo=', - address: { - inner: - '874bHlYDfy3mT57v2bXQWm3SJ7g8LI3cZFKob8J8CfrP2aqVGo6ESrpGScI4t/B2/KgkjhzmAasx8GM1ejNz0J153vD8MBVM9FUZFACzSCg=', - }, - }, - addressIndex: { - account: 12, - randomizer: 'AAAAAAAAAAAAAAAA', - }, - nullifier: { - inner: 'fv/wPZDA5L96Woc+Ry2s7u9IrwNxTFjSDYInZj3lRA8=', - }, - heightCreated: '7197', - position: '42986962944', - source: { - transaction: { - id: '3CBS08dM9eLHH45Z9loZciZ9RaG9x1fc26Qnv0lQlto=', - }, - }, - }), - SpendableNoteRecord.fromJson({ - noteCommitment: { - inner: '2x5KAgUMdC2Gg2aZmj0bZFa5eQv2z9pQlSFfGXcgHQk=', - }, - note: { - value: { - amount: { - lo: '12000000', - }, - assetId: { - inner: 'KeqcLzNx9qSH5+lcJHBB9KNW+YPrBk5dKzvPMiypahA=', - }, - }, - rseed: 'nUSCddD9pm02FxwlmXBCIx1DMrN7QsQ1Mu4QghmIZzU=', - address: { - inner: - '874bHlYDfy3mT57v2bXQWm3SJ7g8LI3cZFKob8J8CfrP2aqVGo6ESrpGScI4t/B2/KgkjhzmAasx8GM1ejNz0J153vD8MBVM9FUZFACzSCg=', - }, - }, - addressIndex: { - account: 12, - randomizer: 'AAAAAAAAAAAAAAAA', - }, - nullifier: { - inner: 'YDmbVyQxPBJbowlAy2R8ThWZTXefTLQVXJ5CPT4sGBE=', - }, - heightCreated: '7235', - position: '42989453314', - source: { - transaction: { - id: 'VwplfDTpKBFLavZ252viYuVxl+EYpmlmnuj5w+jm/MU=', - }, - }, - }), - SpendableNoteRecord.fromJson({ - noteCommitment: { - inner: '2x5KAgUMdC2Gg2aZmj0bZFa5eQv2z9pQlSFfGXcgHQk=', - }, - note: { - value: { - amount: { - lo: '12000000', - }, - assetId: { - inner: 'KeqcLzNx9qSH5+lcJHBB9KNW+YPrBk5dKzvPMiypahA=', - }, - }, - rseed: 'nUSCddD9pm02FxwlmXBCIx1DMrN7QsQ1Mu4QghmIZzU=', - address: { - inner: - '874bHlYDfy3mT57v2bXQWm3SJ7g8LI3cZFKob8J8CfrP2aqVGo6ESrpGScI4t/B2/KgkjhzmAasx8GM1ejNz0J153vD8MBVM9FUZFACzSCg=', - }, - }, - addressIndex: { - account: 3, - randomizer: 'AAAAAAAAAAAAAAAA', - }, - nullifier: { - inner: 'YDmbVyQxPBJbowlAy2R8ThWZTXefTLQVXJ5CPT4sGBE=', - }, - heightCreated: '7235', - position: '42989453314', - source: { - transaction: { - id: 'VwplfDTpKBFLavZ252viYuVxl+EYpmlmnuj5w+jm/MU=', - }, - }, - }), - SpendableNoteRecord.fromJson({ - noteCommitment: { - inner: '9ykyJTT1AMzrEdmpeHlLdiKO6Atrzrw4UBHsy6uwyAE=', - }, - note: { - value: { - amount: { - lo: '976000000', - }, - assetId: { - inner: 'KeqcLzNx9qSH5+lcJHBB9KNW+YPrBk5dKzvPMiypahA=', - }, - }, - rseed: 'NV9zekY5a2HOqIiHUQxpeuZJnmJwk4UDrcf+Qn4gR1U=', - address: { - inner: - 'r7ae/+8Q9d3QdaAs66/GAAbYBo/Am59nYWeIBU7REchE3LYtFPa1EHW2Lo1KZcRWuXzO/cM54CLSFnv2iArQnxjrlJnTB4nGnuLdFtCY9vc=', - }, - }, - addressIndex: { - randomizer: 'AAAAAAAAAAAAAAAA', - }, - nullifier: { - inner: 'xkteBU+VZGL5VtGGCXiF8FNTk11s+26O150ak5YKawc=', - }, - heightCreated: '7614', - position: '47262138369', - source: { - transaction: { - id: 'eD/vckPCdUQ19vXeJP0nSBcBPD5hm7mpgfYXOe4NbMI=', - }, - }, - }), - SpendableNoteRecord.fromJson({ - noteCommitment: { - inner: '1hzgmsvqLjwE8oUKqwjvjioP/NjBw7gA559qH1vXfAs=', - }, - note: { - value: { - amount: { - lo: '1001882102603448320', - hi: '27105', - }, - assetId: { - inner: 'reum7wQmk/owgvGMWMZn/6RFPV24zIKq3W6In/WwZgg=', - }, - }, - rseed: '78CYHBgQbxFq10fZp8KMJTJMv0/W8h/9CG4b+mpbr2M=', - address: { - inner: - 'r7ae/+8Q9d3QdaAs66/GAAbYBo/Am59nYWeIBU7REchE3LYtFPa1EHW2Lo1KZcRWuXzO/cM54CLSFnv2iArQnxjrlJnTB4nGnuLdFtCY9vc=', - }, - }, - addressIndex: { - randomizer: 'AAAAAAAAAAAAAAAA', - }, - nullifier: { - inner: 'xsqQgf4xVTer74FonmkgkjC1VVaV0OlGKkBt9zKGggM=', - }, - position: '20', - source: { - transaction: { - id: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAA=', - }, - }, - }), -]; diff --git a/packages/services/src/view-service/notes.ts b/packages/services/src/view-service/notes.ts deleted file mode 100644 index ee21eb38..00000000 --- a/packages/services/src/view-service/notes.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { Impl } from '.'; -import { servicesCtx } from '../ctx/prax'; - -import { Amount } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/num/v1/num_pb'; -import { addAmounts, joinLoHiAmount } from '@penumbra-zone/types/amount'; - -export const notes: Impl['notes'] = async function* (req, ctx) { - const services = await ctx.values.get(servicesCtx)(); - const { indexedDb } = await services.getWalletServices(); - - const { assetId, addressIndex, includeSpent, amountToSpend } = req; - - let spent = new Amount(); - - for await (const n of indexedDb.iterateSpendableNotes()) { - if (assetId && !n.note?.value?.assetId?.equals(assetId)) continue; - if (addressIndex && !n.addressIndex?.equals(addressIndex)) continue; - if (!includeSpent && n.heightSpent !== 0n) continue; - - yield { noteRecord: n }; - - // If set, stop returning notes once the total exceeds this amount. - // Ignored if `assetId` is unset or if `includeSpent` is set. - if (amountToSpend && assetId && !includeSpent) { - const noteAmount = n.note?.value?.amount ?? new Amount(); - spent = addAmounts(spent, noteAmount); - if (joinLoHiAmount(spent) >= joinLoHiAmount(amountToSpend)) break; - } - } -}; diff --git a/packages/services/src/view-service/nullifier-status.test.ts b/packages/services/src/view-service/nullifier-status.test.ts deleted file mode 100644 index ddaf9d84..00000000 --- a/packages/services/src/view-service/nullifier-status.test.ts +++ /dev/null @@ -1,253 +0,0 @@ -import { nullifierStatus } from './nullifier-status'; - -import { ViewService } from '@penumbra-zone/protobuf'; -import { servicesCtx } from '../ctx/prax'; - -import { createContextValues, createHandlerContext, HandlerContext } from '@connectrpc/connect'; -import type { ServicesInterface } from '@penumbra-zone/types/services'; - -import { beforeEach, describe, expect, Mock, test, vi } from 'vitest'; - -import { Nullifier } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/sct/v1/sct_pb'; -import { - NullifierStatusRequest, - SpendableNoteRecord, - SwapRecord, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; -import { IndexedDbMock, MockServices } from '../test-utils'; -import { stringToUint8Array } from '@penumbra-zone/types/string'; - -describe('nullifierStatus', () => { - let mockServices: MockServices; - let mockIndexedDb: IndexedDbMock; - let mockCtx: HandlerContext; - let noteSubNext: Mock; - let swapSubNext: Mock; - - beforeEach(() => { - vi.resetAllMocks(); - - noteSubNext = vi.fn(); - const mockNoteSubscription = { - next: noteSubNext, - [Symbol.asyncIterator]: () => mockNoteSubscription, - }; - - swapSubNext = vi.fn(); - const mockSwapSubscription = { - next: swapSubNext, - [Symbol.asyncIterator]: () => mockSwapSubscription, - }; - - mockIndexedDb = { - getSpendableNoteByNullifier: vi.fn(), - getSwapByNullifier: vi.fn(), - subscribe: (table: string) => { - if (table === 'SPENDABLE_NOTES') return mockNoteSubscription; - if (table === 'SWAPS') return mockSwapSubscription; - throw new Error('Table not supported'); - }, - }; - mockServices = { - getWalletServices: vi.fn(() => - Promise.resolve({ indexedDb: mockIndexedDb }), - ) as MockServices['getWalletServices'], - }; - - mockCtx = createHandlerContext({ - service: ViewService, - method: ViewService.methods.nullifierStatus, - protocolName: 'mock', - requestMethod: 'MOCK', - url: '/mock', - contextValues: createContextValues().set(servicesCtx, () => - Promise.resolve(mockServices as unknown as ServicesInterface), - ), - }); - }); - - test('returns empty response if no nullifier provided', async () => { - const req = new NullifierStatusRequest(); - await expect(nullifierStatus(req, mockCtx)).rejects.toThrowError('No nullifier passed'); - }); - - test('returns false if nullifier not found in db', async () => { - const req = new NullifierStatusRequest({ - nullifier: new Nullifier({ inner: stringToUint8Array('nullifier_abc') }), - }); - - mockIndexedDb.getSpendableNoteByNullifier?.mockResolvedValue(undefined); - mockIndexedDb.getSwapByNullifier?.mockResolvedValue(undefined); - - const res = await nullifierStatus(req, mockCtx); - expect(res.spent).toBe(false); - }); - - test('returns true if nullifier found in swaps and is spent', async () => { - const req = new NullifierStatusRequest({ - nullifier: new Nullifier({ inner: stringToUint8Array('nullifier_abc') }), - }); - - mockIndexedDb.getSpendableNoteByNullifier?.mockResolvedValue(undefined); - mockIndexedDb.getSwapByNullifier?.mockResolvedValue(new SwapRecord({ heightClaimed: 324234n })); - - const res = await nullifierStatus(req, mockCtx); - expect(res.spent).toBe(true); - }); - - test('returns false if nullifier found in swaps and is not spent', async () => { - const req = new NullifierStatusRequest({ - nullifier: new Nullifier({ inner: stringToUint8Array('nullifier_abc') }), - }); - - mockIndexedDb.getSpendableNoteByNullifier?.mockResolvedValue(undefined); - mockIndexedDb.getSwapByNullifier?.mockResolvedValue(new SwapRecord()); - - const res = await nullifierStatus(req, mockCtx); - expect(res.spent).toBe(false); - }); - - test('returns true if nullifier found in notes and is spent', async () => { - const req = new NullifierStatusRequest({ - nullifier: new Nullifier({ inner: stringToUint8Array('nullifier_abc') }), - }); - - mockIndexedDb.getSpendableNoteByNullifier?.mockResolvedValue( - new SpendableNoteRecord({ heightSpent: 324234n }), - ); - mockIndexedDb.getSwapByNullifier?.mockResolvedValue(undefined); - - const res = await nullifierStatus(req, mockCtx); - expect(res.spent).toBe(true); - }); - - test('returns false if nullifier found in notes and is not spent', async () => { - const req = new NullifierStatusRequest({ - nullifier: new Nullifier({ inner: stringToUint8Array('nullifier_abc') }), - }); - - mockIndexedDb.getSpendableNoteByNullifier?.mockResolvedValue(new SpendableNoteRecord()); - mockIndexedDb.getSwapByNullifier?.mockResolvedValue(undefined); - - const res = await nullifierStatus(req, mockCtx); - expect(res.spent).toBe(false); - }); - - test('await detect corresponding note', async () => { - mockIndexedDb.getSpendableNoteByNullifier?.mockResolvedValue(undefined); - mockIndexedDb.getSwapByNullifier?.mockResolvedValue(undefined); - - const matchingNullifier = new Nullifier({ inner: stringToUint8Array('nullifier_abc') }); - - const nonMatchingNote = new SpendableNoteRecord({ - nullifier: new Nullifier({ inner: stringToUint8Array('nope') }), - }); - - const matchingNoteNotSpent = new SpendableNoteRecord({ - nullifier: matchingNullifier, - }); - - const matchingNoteSpent = new SpendableNoteRecord({ - nullifier: matchingNullifier, - heightSpent: 10314n, - }); - - const nonMatchingSwap = new SwapRecord({ - nullifier: new Nullifier({ inner: stringToUint8Array('nope') }), - }); - - // Incoming swaps with no matches - swapSubNext - .mockResolvedValueOnce({ - value: { value: nonMatchingSwap.toJson(), table: 'SWAPS' }, - }) - .mockResolvedValueOnce({ - value: { value: nonMatchingSwap.toJson(), table: 'SWAPS' }, - }) - .mockResolvedValueOnce({ - value: { value: nonMatchingSwap.toJson(), table: 'SWAPS' }, - }); - - // Incoming notes with the last one being the match - noteSubNext - .mockResolvedValueOnce({ - value: { value: nonMatchingNote.toJson(), table: 'SPENDABLE_NOTES' }, - }) - .mockResolvedValueOnce({ - value: { value: matchingNoteNotSpent.toJson(), table: 'SPENDABLE_NOTES' }, - }) - .mockResolvedValueOnce({ - value: { value: matchingNoteSpent.toJson(), table: 'SPENDABLE_NOTES' }, - }); - - const req = new NullifierStatusRequest({ - nullifier: matchingNullifier, - awaitDetection: true, - }); - - const res = await nullifierStatus(req, mockCtx); - expect(res.spent).toBe(true); - }); - - test('await detect corresponding swap', async () => { - mockIndexedDb.getSpendableNoteByNullifier?.mockResolvedValue(undefined); - mockIndexedDb.getSwapByNullifier?.mockResolvedValue(undefined); - - const matchingNullifier = new Nullifier({ inner: stringToUint8Array('nullifier_abc') }); - - const nonMatchingSwap = new SwapRecord({ - nullifier: new Nullifier({ inner: stringToUint8Array('nope') }), - }); - - const matchingSwapNotSpent = new SwapRecord({ - nullifier: matchingNullifier, - }); - - const matchingSwapSpent = new SwapRecord({ - nullifier: matchingNullifier, - heightClaimed: 10314n, - }); - - // Incoming swaps with the last one being the match - swapSubNext - .mockResolvedValueOnce({ - value: { value: nonMatchingSwap.toJson(), table: 'SWAPS' }, - }) - .mockResolvedValueOnce({ - value: { value: matchingSwapNotSpent.toJson(), table: 'SWAPS' }, - }) - .mockResolvedValueOnce({ - value: { value: matchingSwapSpent.toJson(), table: 'SWAPS' }, - }); - - const nonMatchingNote = new SpendableNoteRecord({ - nullifier: new Nullifier({ inner: stringToUint8Array('nope') }), - }); - - // Incoming notes with no matches - noteSubNext - .mockResolvedValueOnce({ - value: { value: nonMatchingNote.toJson(), table: 'SPENDABLE_NOTES' }, - }) - .mockResolvedValueOnce({ - value: { value: nonMatchingNote.toJson(), table: 'SPENDABLE_NOTES' }, - }) - .mockResolvedValueOnce({ - value: { value: nonMatchingNote.toJson(), table: 'SPENDABLE_NOTES' }, - }) - .mockResolvedValueOnce({ - value: { value: nonMatchingNote.toJson(), table: 'SPENDABLE_NOTES' }, - }) - .mockResolvedValueOnce({ - value: { value: nonMatchingNote.toJson(), table: 'SPENDABLE_NOTES' }, - }); - - const req = new NullifierStatusRequest({ - nullifier: matchingNullifier, - awaitDetection: true, - }); - - const res = await nullifierStatus(req, mockCtx); - expect(res.spent).toBe(true); - }); -}); diff --git a/packages/services/src/view-service/nullifier-status.ts b/packages/services/src/view-service/nullifier-status.ts deleted file mode 100644 index 937775bb..00000000 --- a/packages/services/src/view-service/nullifier-status.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { - SpendableNoteRecord, - SwapRecord, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; -import type { Impl } from '.'; -import { servicesCtx } from '../ctx/prax'; - -import { Code, ConnectError } from '@connectrpc/connect'; - -const watchStream = async ( - subscription: AsyncGenerator, - test: (x: U) => boolean, -): Promise => { - for await (const update of subscription) if (test(update)) return update; - throw new Error('Subscription ended'); -}; - -export const nullifierStatus: Impl['nullifierStatus'] = async (req, ctx) => { - const { nullifier } = req; - if (!nullifier) throw new ConnectError('No nullifier passed', Code.InvalidArgument); - - const services = await ctx.values.get(servicesCtx)(); - const { indexedDb } = await services.getWalletServices(); - - // grab subscription to table updates before checking the tables. this avoids - // a race condition: if instead we checked the tables, and *then* subscribed, - // it would be possible to miss updates that arrived in the short time between - // the two calls. - const swapStream = indexedDb.subscribe('SWAPS'); - const noteStream = indexedDb.subscribe('SPENDABLE_NOTES'); - - // If present, a swap or note should never have an undefined height, and a - // zero-height spend should never appear. So if one of these is truthy, the - // nullifier is spent. - const [swap, note] = await Promise.all([ - indexedDb.getSwapByNullifier(nullifier), - indexedDb.getSpendableNoteByNullifier(nullifier), - ]); - const spent = Boolean(swap?.heightClaimed) || Boolean(note?.heightSpent); - - if (!spent && req.awaitDetection) { - // use of the nullifier was not present in db, so watch that subscription. - // we might double-check very recent items, but we won't miss any. - const eventuallySpent = Promise.race([ - watchStream(swapStream, ({ value: swapJson }) => { - const swap = SwapRecord.fromJson(swapJson); - return Boolean(swap.heightClaimed) && nullifier.equals(swap.nullifier); - }), - watchStream(noteStream, ({ value: noteJson }) => { - const note = SpendableNoteRecord.fromJson(noteJson); - return Boolean(note.heightSpent) && nullifier.equals(note.nullifier); - }), - ]); - return eventuallySpent.then(() => ({ spent: true })); - } - - return { spent }; -}; diff --git a/packages/services/src/view-service/owned-position-ids.test.ts b/packages/services/src/view-service/owned-position-ids.test.ts deleted file mode 100644 index 52b38eac..00000000 --- a/packages/services/src/view-service/owned-position-ids.test.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { ViewService } from '@penumbra-zone/protobuf'; -import { servicesCtx } from '../ctx/prax'; - -import { createContextValues, createHandlerContext, HandlerContext } from '@connectrpc/connect'; - -import { beforeEach, describe, expect, test, vi } from 'vitest'; - -import { - OwnedPositionIdsRequest, - OwnedPositionIdsResponse, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; -import { IndexedDbMock, MockServices } from '../test-utils'; -import type { ServicesInterface } from '@penumbra-zone/types/services'; -import { PositionId } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/dex/v1/dex_pb'; -import { ownedPositionIds } from './owned-position-ids'; - -describe('OwnedPositionIds request handler', () => { - let mockServices: MockServices; - let mockCtx: HandlerContext; - let mockIndexedDb: IndexedDbMock; - let req: OwnedPositionIdsRequest; - - beforeEach(() => { - vi.resetAllMocks(); - - const mockIteratePositions = { - next: vi.fn(), - [Symbol.asyncIterator]: () => mockIteratePositions, - }; - - mockIndexedDb = { - getOwnedPositionIds: () => mockIteratePositions, - }; - - mockServices = { - getWalletServices: vi.fn(() => - Promise.resolve({ indexedDb: mockIndexedDb }), - ) as MockServices['getWalletServices'], - }; - - mockCtx = createHandlerContext({ - service: ViewService, - method: ViewService.methods.ownedPositionIds, - protocolName: 'mock', - requestMethod: 'MOCK', - url: '/mock', - contextValues: createContextValues().set(servicesCtx, () => - Promise.resolve(mockServices as unknown as ServicesInterface), - ), - }); - - for (const record of testData) { - mockIteratePositions.next.mockResolvedValueOnce({ - value: record, - }); - } - mockIteratePositions.next.mockResolvedValueOnce({ - done: true, - }); - req = new OwnedPositionIdsRequest(); - }); - - test('should get all owned position ids', async () => { - const responses: OwnedPositionIdsResponse[] = []; - for await (const res of ownedPositionIds(req, mockCtx)) { - responses.push(new OwnedPositionIdsResponse(res)); - } - expect(responses.length).toBe(3); - }); -}); - -const testData: PositionId[] = [ - PositionId.fromJson({ - inner: 'qE/PCp65S+GHi2HFO74G8Gx5ansmxeMwEdNUgn3GXYE=', - }), - PositionId.fromJson({ - inner: 'jPb6+hLkYgwIs4sVxhyYUmpbvIyPOXATqL/hiKGwhbg=', - }), - PositionId.fromJson({ - inner: '8hpmQDWRJFAqYI1NaKltjbFqCRiI4eEQT5DzzNUkDXQ=', - }), -]; diff --git a/packages/services/src/view-service/owned-position-ids.ts b/packages/services/src/view-service/owned-position-ids.ts deleted file mode 100644 index 6675a296..00000000 --- a/packages/services/src/view-service/owned-position-ids.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { Impl } from '.'; -import { servicesCtx } from '../ctx/prax'; - -export const ownedPositionIds: Impl['ownedPositionIds'] = async function* (req, ctx) { - const services = await ctx.values.get(servicesCtx)(); - - const { indexedDb } = await services.getWalletServices(); - - for await (const positionId of indexedDb.getOwnedPositionIds( - req.positionState, - req.tradingPair, - )) { - yield { positionId: positionId }; - } -}; diff --git a/packages/services/src/view-service/status-stream.test.ts b/packages/services/src/view-service/status-stream.test.ts deleted file mode 100644 index b98616bf..00000000 --- a/packages/services/src/view-service/status-stream.test.ts +++ /dev/null @@ -1,92 +0,0 @@ -import { beforeEach, describe, expect, Mock, test, vi } from 'vitest'; -import { - StatusStreamRequest, - StatusStreamResponse, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; -import { createContextValues, createHandlerContext, HandlerContext } from '@connectrpc/connect'; -import { ViewService } from '@penumbra-zone/protobuf'; -import { servicesCtx } from '../ctx/prax'; -import { IndexedDbMock, MockServices, TendermintMock } from '../test-utils'; -import { statusStream } from './status-stream'; -import type { ServicesInterface } from '@penumbra-zone/types/services'; - -describe('Status stream request handler', () => { - let mockServices: MockServices; - let mockIndexedDb: IndexedDbMock; - let mockCtx: HandlerContext; - let mockTendermint: TendermintMock; - let lastBlockSubNext: Mock; - let request: StatusStreamRequest; - - beforeEach(() => { - vi.resetAllMocks(); - - lastBlockSubNext = vi.fn(); - const mockLastBlockSubscription = { - next: lastBlockSubNext, - [Symbol.asyncIterator]: () => mockLastBlockSubscription, - }; - - mockIndexedDb = { - subscribe: () => mockLastBlockSubscription, - }; - - mockTendermint = { - latestBlockHeight: vi.fn(), - }; - - mockServices = { - getWalletServices: vi.fn(() => - Promise.resolve({ - indexedDb: mockIndexedDb, - querier: { - tendermint: mockTendermint, - }, - }), - ) as MockServices['getWalletServices'], - }; - - mockCtx = createHandlerContext({ - service: ViewService, - method: ViewService.methods.statusStream, - protocolName: 'mock', - requestMethod: 'MOCK', - url: '/mock', - contextValues: createContextValues().set(servicesCtx, () => - Promise.resolve(mockServices as unknown as ServicesInterface), - ), - }); - - request = new StatusStreamRequest(); - - for (let i = 200; i < 222; i++) { - lastBlockSubNext.mockResolvedValueOnce({ - value: { - value: BigInt(i), - }, - }); - } - // synchronization never ends, but the test can't last indefinitely, so we end the stream - lastBlockSubNext.mockResolvedValueOnce({ - done: true, - }); - }); - - test('should receive a status stream when view service synchronizes and lags behind last known block in tendermint', async () => { - mockTendermint.latestBlockHeight?.mockResolvedValue(222n); - for await (const res of statusStream(request, mockCtx)) { - const response = new StatusStreamResponse(res); - expect(response.latestKnownBlockHeight === 222n).toBeTruthy(); - expect(response.partialSyncHeight === response.fullSyncHeight).toBeTruthy(); - } - }); - - test('should receive a status stream when view service is synchronized block by block', async () => { - mockTendermint.latestBlockHeight?.mockResolvedValue(200n); - for await (const res of statusStream(request, mockCtx)) { - const response = new StatusStreamResponse(res); - expect(response.partialSyncHeight === response.fullSyncHeight).toBeTruthy(); - expect(response.fullSyncHeight === response.latestKnownBlockHeight).toBeTruthy(); - } - }); -}); diff --git a/packages/services/src/view-service/status-stream.ts b/packages/services/src/view-service/status-stream.ts deleted file mode 100644 index 89a591bc..00000000 --- a/packages/services/src/view-service/status-stream.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type { Impl } from '.'; -import { servicesCtx } from '../ctx/prax'; - -export const statusStream: Impl['statusStream'] = async function* (_, ctx) { - const services = await ctx.values.get(servicesCtx)(); - const { indexedDb, querier } = await services.getWalletServices(); - - // This should stream forever unless cancelled. - let remoteBlockHeight: bigint | undefined; - for await (const { value: syncHeight } of indexedDb.subscribe('FULL_SYNC_HEIGHT')) { - remoteBlockHeight ??= await querier.tendermint.latestBlockHeight(); - if (remoteBlockHeight) { - yield { - latestKnownBlockHeight: syncHeight <= remoteBlockHeight ? remoteBlockHeight : syncHeight, - partialSyncHeight: syncHeight, - fullSyncHeight: syncHeight, - }; - } - } -}; diff --git a/packages/services/src/view-service/status.test.ts b/packages/services/src/view-service/status.test.ts deleted file mode 100644 index e70c391f..00000000 --- a/packages/services/src/view-service/status.test.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { beforeEach, describe, expect, test, vi } from 'vitest'; -import { - StatusRequest, - StatusResponse, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; -import { createContextValues, createHandlerContext, HandlerContext } from '@connectrpc/connect'; -import { ViewService } from '@penumbra-zone/protobuf'; -import { servicesCtx } from '../ctx/prax'; -import { IndexedDbMock, MockServices, TendermintMock } from '../test-utils'; -import { status } from './status'; -import type { ServicesInterface } from '@penumbra-zone/types/services'; - -describe('Status request handler', () => { - let mockServices: MockServices; - let mockIndexedDb: IndexedDbMock; - let mockCtx: HandlerContext; - let mockTendermint: TendermintMock; - - beforeEach(() => { - vi.resetAllMocks(); - - mockIndexedDb = { - getFullSyncHeight: vi.fn(), - }; - - mockTendermint = { - latestBlockHeight: vi.fn(), - }; - - mockServices = { - getWalletServices: vi.fn(() => - Promise.resolve({ - indexedDb: mockIndexedDb, - querier: { - tendermint: mockTendermint, - }, - }), - ) as MockServices['getWalletServices'], - }; - - mockCtx = createHandlerContext({ - service: ViewService, - method: ViewService.methods.status, - protocolName: 'mock', - requestMethod: 'MOCK', - url: '/mock', - contextValues: createContextValues().set(servicesCtx, () => - Promise.resolve(mockServices as unknown as ServicesInterface), - ), - }); - }); - - test('should get status when view service is synchronized with last known block in tendermint', async () => { - mockIndexedDb.getFullSyncHeight?.mockResolvedValue(222n); - mockTendermint.latestBlockHeight?.mockResolvedValue(222n); - const statusResponse = new StatusResponse(await status(new StatusRequest(), mockCtx)); - expect(statusResponse.catchingUp).toBe(false); - expect(statusResponse.fullSyncHeight === 222n).toBeTruthy(); - }); - - test('should receive status when view service synchronizes and lags behind last known block in tendermint', async () => { - mockIndexedDb.getFullSyncHeight?.mockResolvedValue(111n); - mockTendermint.latestBlockHeight?.mockResolvedValue(222n); - const statusResponse = new StatusResponse(await status(new StatusRequest(), mockCtx)); - expect(statusResponse.catchingUp).toBe(true); - expect(statusResponse.partialSyncHeight === 111n).toBeTruthy(); - }); -}); diff --git a/packages/services/src/view-service/status.ts b/packages/services/src/view-service/status.ts deleted file mode 100644 index 688bbb33..00000000 --- a/packages/services/src/view-service/status.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { Impl } from '.'; -import { servicesCtx } from '../ctx/prax'; - -export const status: Impl['status'] = async (_, ctx) => { - const services = await ctx.values.get(servicesCtx)(); - const { indexedDb, querier } = await services.getWalletServices(); - const latestBlockHeight = await querier.tendermint.latestBlockHeight(); - const fullSyncHeight = (await indexedDb.getFullSyncHeight()) ?? 0n; - - return { - catchingUp: !latestBlockHeight || latestBlockHeight > fullSyncHeight, - partialSyncHeight: fullSyncHeight, - fullSyncHeight: fullSyncHeight, - }; -}; diff --git a/packages/services/src/view-service/swap-by-commitment.test.ts b/packages/services/src/view-service/swap-by-commitment.test.ts deleted file mode 100644 index 3deff17f..00000000 --- a/packages/services/src/view-service/swap-by-commitment.test.ts +++ /dev/null @@ -1,147 +0,0 @@ -import { beforeEach, describe, expect, Mock, test, vi } from 'vitest'; -import { - SwapByCommitmentRequest, - SwapByCommitmentResponse, - SwapRecord, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; -import { createContextValues, createHandlerContext, HandlerContext } from '@connectrpc/connect'; -import { ViewService } from '@penumbra-zone/protobuf'; -import { servicesCtx } from '../ctx/prax'; -import { IndexedDbMock, MockServices } from '../test-utils'; -import { StateCommitment } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/crypto/tct/v1/tct_pb'; -import { swapByCommitment } from './swap-by-commitment'; -import type { ServicesInterface } from '@penumbra-zone/types/services'; - -describe('SwapByCommitment request handler', () => { - let mockServices: MockServices; - let mockIndexedDb: IndexedDbMock; - let mockCtx: HandlerContext; - let request: SwapByCommitmentRequest; - let swapSubNext: Mock; - - beforeEach(() => { - vi.resetAllMocks(); - - swapSubNext = vi.fn(); - const mockSwapSubscription = { - next: swapSubNext, - [Symbol.asyncIterator]: () => mockSwapSubscription, - }; - - mockIndexedDb = { - getSwapByCommitment: vi.fn(), - subscribe: () => mockSwapSubscription, - }; - mockServices = { - getWalletServices: vi.fn(() => - Promise.resolve({ indexedDb: mockIndexedDb }), - ) as MockServices['getWalletServices'], - }; - mockCtx = createHandlerContext({ - service: ViewService, - method: ViewService.methods.swapByCommitment, - protocolName: 'mock', - requestMethod: 'MOCK', - url: '/mock', - contextValues: createContextValues().set(servicesCtx, () => - Promise.resolve(mockServices as unknown as ServicesInterface), - ), - }); - - request = new SwapByCommitmentRequest({ swapCommitment: testCommitment }); - }); - - test('should successfully get swap by commitment when idb has them', async () => { - mockIndexedDb.getSwapByCommitment?.mockResolvedValue(testSwap); - const swapByCommitmentResponse = new SwapByCommitmentResponse( - await swapByCommitment(request, mockCtx), - ); - expect(swapByCommitmentResponse.swap?.equals(testSwap)).toBeTruthy(); - }); - - test('should throw error if idb has none', async () => { - await expect(swapByCommitment(new SwapByCommitmentRequest(), mockCtx)).rejects.toThrow( - 'Missing swap commitment in request', - ); - }); - - test('should throw an error if swap no found in idb and awaitDetection is false', async () => { - mockIndexedDb.getSwapByCommitment?.mockResolvedValue(undefined); - request.awaitDetection = false; - await expect(swapByCommitment(request, mockCtx)).rejects.toThrow('Swap not found'); - }); - - test('should get swap if swap is not found in idb, but awaitDetection is true, and has been detected', async () => { - mockIndexedDb.getSwapByCommitment?.mockResolvedValue(undefined); - request.awaitDetection = true; - swapSubNext.mockResolvedValueOnce({ - value: { value: testSwap.toJson() }, - }); - const swapByCommitmentResponse = new SwapByCommitmentResponse( - await swapByCommitment(request, mockCtx), - ); - expect(swapByCommitmentResponse.swap?.equals(testSwap)).toBeTruthy(); - }); - - test('should throw error if swap is not found in idb, and has not been detected', async () => { - mockIndexedDb.getSwapByCommitment?.mockResolvedValue(undefined); - request.awaitDetection = true; - - swapSubNext.mockResolvedValueOnce({ - value: { value: swapWithAnotherCommitment.toJson() }, - }); - swapSubNext.mockResolvedValueOnce({ - done: true, - }); - await expect(swapByCommitment(request, mockCtx)).rejects.toThrow('Swap not found'); - }); -}); - -const testCommitment = StateCommitment.fromJson({ - inner: 'A6VBVkrk+s18q+Sjhl8uEGfS3i0dwF1FrkNm8Db6VAA=', -}); - -const testSwap = SwapRecord.fromJson({ - swapCommitment: { inner: 'A6VBVkrk+s18q+Sjhl8uEGfS3i0dwF1FrkNm8Db6VAA=' }, - swap: { - tradingPair: { - asset1: { inner: 'HW2Eq3UZVSBttoUwUi/MUtE7rr2UU7/UH500byp7OAc=' }, - asset2: { inner: 'KeqcLzNx9qSH5+lcJHBB9KNW+YPrBk5dKzvPMiypahA=' }, - }, - delta1I: {}, - delta2I: { lo: '1000000' }, - claimFee: { amount: {} }, - claimAddress: { - inner: - '2VQ9nQKqga8RylgOq+wAY3/Hmxg96mGnI+Te/BRnXWpr5bSxpLShbpOmzO4pPULf+tGjaBum6InyEpipJ+8wk+HufrvSBa43H9o2ir5WPbk=', - }, - rseed: 'RPuhZ9q2F3XHbTcDPRTHnJjJaMxv8hes4TzJuMbsA/k=', - }, - position: '2383742304257', - nullifier: { inner: 'dE7LbhBDgDXHiRvreFyCllcKOOQeuIVsbn2aw8uKhww=' }, - outputData: { - delta1: {}, - delta2: { lo: '1000000' }, - lambda1: { lo: '2665239' }, - lambda2: {}, - unfilled1: {}, - unfilled2: {}, - height: '356591', - tradingPair: { - asset1: { inner: 'HW2Eq3UZVSBttoUwUi/MUtE7rr2UU7/UH500byp7OAc=' }, - asset2: { inner: 'KeqcLzNx9qSH5+lcJHBB9KNW+YPrBk5dKzvPMiypahA=' }, - }, - epochStartingHeight: '356050', - }, - source: { - transaction: { - id: '9e1OaxysQAzHUUKsroXMNRCzlPxd6hBWLrqURgNBrmE=', - }, - }, -}); - -const swapWithAnotherCommitment = SwapRecord.fromJson({ - swapCommitment: { - inner: 'n86D13I1rRUDoLCkX7LKl/AG8/F+2MV76p4XgPD++xA=', - }, -}); diff --git a/packages/services/src/view-service/swap-by-commitment.ts b/packages/services/src/view-service/swap-by-commitment.ts deleted file mode 100644 index abbce7f3..00000000 --- a/packages/services/src/view-service/swap-by-commitment.ts +++ /dev/null @@ -1,26 +0,0 @@ -import type { Impl } from '.'; -import { servicesCtx } from '../ctx/prax'; - -import { SwapRecord } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; - -import { Code, ConnectError } from '@connectrpc/connect'; - -export const swapByCommitment: Impl['swapByCommitment'] = async (req, ctx) => { - const services = await ctx.values.get(servicesCtx)(); - const { indexedDb } = await services.getWalletServices(); - const { swapCommitment } = req; - if (!swapCommitment) - throw new ConnectError('Missing swap commitment in request', Code.InvalidArgument); - - const swap = await indexedDb.getSwapByCommitment(swapCommitment); - if (swap) return { swap }; - - if (req.awaitDetection) { - for await (const { value: swapJson } of indexedDb.subscribe('SWAPS')) { - const swap = SwapRecord.fromJson(swapJson); - if (swap.swapCommitment?.equals(swapCommitment)) return { swap }; - } - } - - throw new ConnectError('Swap not found', Code.NotFound); -}; diff --git a/packages/services/src/view-service/transaction-info-by-hash.test.ts b/packages/services/src/view-service/transaction-info-by-hash.test.ts deleted file mode 100644 index 1e4b6d3d..00000000 --- a/packages/services/src/view-service/transaction-info-by-hash.test.ts +++ /dev/null @@ -1,257 +0,0 @@ -import { beforeEach, describe, expect, test, vi } from 'vitest'; -import { - TransactionInfoByHashRequest, - TransactionInfoByHashResponse, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; -import { createContextValues, createHandlerContext, HandlerContext } from '@connectrpc/connect'; -import { ViewService } from '@penumbra-zone/protobuf'; -import { servicesCtx } from '../ctx/prax'; -import { IndexedDbMock, MockServices, TendermintMock, testFullViewingKey } from '../test-utils'; -import { transactionInfoByHash } from './transaction-info-by-hash'; -import { TransactionId } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/txhash/v1/txhash_pb'; -import type { ServicesInterface } from '@penumbra-zone/types/services'; -import { - Transaction, - TransactionPerspective, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/transaction/v1/transaction_pb'; -import { fvkCtx } from '../ctx/full-viewing-key'; - -const mockTransactionInfo = vi.hoisted(() => vi.fn()); -vi.mock('@penumbra-zone/wasm/transaction', () => ({ - generateTransactionInfo: mockTransactionInfo, -})); -describe('TransactionInfoByHash request handler', () => { - let mockServices: MockServices; - let mockIndexedDb: IndexedDbMock; - let mockCtx: HandlerContext; - let mockTendermint: TendermintMock; - - beforeEach(() => { - vi.resetAllMocks(); - - mockIndexedDb = { - getTransaction: vi.fn(), - constants: vi.fn(), - }; - mockTendermint = { - getTransaction: vi.fn(), - }; - mockServices = { - getWalletServices: vi.fn(() => - Promise.resolve({ - indexedDb: mockIndexedDb, - querier: { - tendermint: mockTendermint, - }, - }), - ) as MockServices['getWalletServices'], - }; - - mockCtx = createHandlerContext({ - service: ViewService, - method: ViewService.methods.transactionInfoByHash, - protocolName: 'mock', - requestMethod: 'MOCK', - url: '/mock', - contextValues: createContextValues() - .set(servicesCtx, () => Promise.resolve(mockServices as unknown as ServicesInterface)) - .set(fvkCtx, () => Promise.resolve(testFullViewingKey)), - }); - mockTransactionInfo.mockReturnValueOnce({ - txp: transactionPerspective, - txv: {}, - }); - }); - - test('should get TransactionInfo from indexed-db if there is a record in indexed-db', async () => { - mockIndexedDb.getTransaction?.mockResolvedValue({ - height: 22n, - id: transactionId, - transaction, - }); - const txInfoByHashResponse = new TransactionInfoByHashResponse( - await transactionInfoByHash(new TransactionInfoByHashRequest({ id: transactionId }), mockCtx), - ); - - expect(txInfoByHashResponse.txInfo?.transaction!.equals(transaction)).toBeTruthy(); - }); - - test('should get TransactionInfo from tendermint if record is not found in indexed-db', async () => { - mockIndexedDb.getTransaction?.mockResolvedValue(undefined); - mockTendermint.getTransaction?.mockResolvedValue({ - height: 22n, - transaction: transaction, - }); - - const txInfoByHashResponse = new TransactionInfoByHashResponse( - await transactionInfoByHash(new TransactionInfoByHashRequest({ id: transactionId }), mockCtx), - ); - expect(txInfoByHashResponse.txInfo?.transaction!.equals(transaction)).toBeTruthy(); - }); - - test('should get an error if TransactionId is not passed', async () => { - await expect( - transactionInfoByHash(new TransactionInfoByHashRequest(), mockCtx), - ).rejects.toThrow('Missing transaction ID in request'); - }); -}); - -const transactionId = TransactionId.fromJson({ - inner: 'v5fO5kM6B/VYpaLyy/cXvlqtSb4/i8WWlwbfrSPTDlI=', -}); - -const transaction = Transaction.fromJson({ - body: { - actions: [ - { - output: { - body: { - notePayload: { - noteCommitment: { - inner: 'VxJkYflpkJKddFzcvB0r81ZdyEBY3ar1ixW405l/rwM=', - }, - ephemeralKey: 'glXyMr+5esBZGdX3VBq9eouX31rR+x16HhB8ZKzA6ww=', - encryptedNote: { - inner: - 'pq0A9/dYLjHlXNXh+OcGVHAbT2rFJWqz1BAonq77jVCs0fp0G726mokatGp22BkBSkyCpYzhLng4pqz9NRpDJvzGGZVJqkOWWq4eyQZgCymjTeGTI2j2rFt3GbkoFByyUNezwYV3wNdYmq9HwY9qkkSROjzEXp6x9sNYY19xB4uDAIEEJ57oDzsaO/qNrCnsE8UmlYMjJRcP9IvBySQ1PAhbdckrsJkoDiD2WZ+4Elk=', - }, - }, - balanceCommitment: { - inner: 'jORWdUta04bYg75Fb4yV0meiO+XlH5AitF2AZ+g2BQU=', - }, - wrappedMemoKey: 'f7q2mb0bL1bSKX9b6YZ77Y58+tQ07r3Id80RM5WzryWTnt2t5obqCOcLonXLO3bg', - ovkWrappedKey: 'PWegX3A+huNHMqX/J0pthNP/2C02BMyDZrqBzH3sGxI6SU0eT7+sM9lDV43DefSo', - }, - proof: { - inner: - 'rO1LrPqAha58cQtoL7UTtl23cju65ae7vFlwJre1ZjUq35Vp2pLQcAO9T9ujzSoBdvViLmyFzeh0+B7/MFwCmJ+zyIEjAYpOwBwu92UNAfUdawv+ScSY6XE+vgLAXCgAGzEjV5sSD0byaj65J85piBAUCwbvRkpHFlmKVxfe6qATcedSs7MZXhDdrW6HgrqAIYiHJn5gTYfUjOwnpNBaQkOIm11SoHrohjdMLhihv7/O2F7SNkYltw62A6Qc7TKB', - }, - }, - }, - { - spend: { - body: { - balanceCommitment: { - inner: 'wuR6JewcTPhnBzmMUTNcGjcTUqDApPN/HXYQGw32IQI=', - }, - nullifier: { - inner: 'HwxySpKV8nuDyQW0sHavb8k1hjBU6y35y7LfmYAbnQ4=', - }, - rk: { - inner: 'LuDiuan9I6R3tJsQIHFuG128OojxsZ44s4PPcaARUgc=', - }, - }, - authSig: { - inner: - 'Nk8XwaFeRYjatcWyk05CVi9gTTh0RckTtfp3RNHT3QdzwRr2GxXjiz1y6puTsph0aU68R+2Qdpcp7kpoV7TZAA==', - }, - proof: { - inner: - 'vhq7Hw4l3Ff5CmY88nqRfmH7Yn8U+Thg74a/H8fPdqvLpEyuzt8c5EZXznyRaaiAv0zk7CfCoE07gXm4SSJiVM9eJfyNGwi2HrBRENX0GQSGGAMs674Fbm6u0CJLIgkAB41KMakBiNE6ovlw1lHYIQXC4QyUV0sCTPHZv8YquG40L7PNRET5ipCsrYffFaqB8UTMkNJg/Kegz0k/mI4Nrz7T7OAF/1snTsQ+spDjTfUw6rckmS8VOASlLjputN+A', - }, - }, - }, - { - spend: { - body: { - balanceCommitment: { - inner: 'rqbOMGjlC6+bAOvEM62zZoFePVDuiziyCIZEeWYDAhA=', - }, - nullifier: { - inner: 'E/bOScHoO2Lka4n89fHq4iJHFkeRuy1P+vcyVHN4PRE=', - }, - rk: { - inner: 'LsLGKRp22uQkybzmiIXh+NM2n38JVvZvfxGYmK7lNwA=', - }, - }, - authSig: { - inner: - 'KsJpO4aqv6mjjFWJX6g8KMDNMi2xf9nzri9l2bFT7QlCffCaAhr3DjNsiJdoAx4Y58k7tP9CUbj3yeX5RuTKAg==', - }, - proof: { - inner: - 'SsOCfPgz7Iyr4ZJ69xsr28VZbfGiYFSiuFlOKoPxWeMOnEeZqpFk+9/bmAf1UzOBGA03Byh4edilYDhwVNYQKh7VKgtWRQjQCs8KrVRyZ1lHI8jKc/NDrHcwaHpqfGIBsCXrbc3vyjeKlVhFkC9p7WGNEY0yUHIzdxMTBP9NJ4YauJ4Zk/dOIjY4NxTDk1GAx5KjCnZmn9Ux7B3Y/q7yArWb7QRiri6qEshPAFWhQOmqaYPzLuSbjsa0XByhHqEA', - }, - }, - }, - { - output: { - body: { - notePayload: { - noteCommitment: { - inner: '3FTx6D+IH8RBr5VuJTak34oHtGk+cu/zMDK32Kb8wAQ=', - }, - ephemeralKey: 'uk9Ctf0KcBRsErY5GpSBVjtFj+vlDom0ljSmwqaspQ8=', - encryptedNote: { - inner: - 'PM7/bjyXmV6xaWnwEWxsULs4F06fxmkAjMI5H5TC1BExYQVecJvmcI9RtxRuwMJQdb4opX0y7H2JdypVPhKr3Rl3Ngjw+GdtAP/PBuhW2ftNj/RkY5qQKXB7GqRF19gvkbHaLGZp42Aw8zWF9ba7kU01uTbfh2dpJQZIVSAdSQnWBLcs2u747mK4zKwMaxlssCX0vvjL0dYrtaPjmSFySe8EVL7iLJg7zzoENA7pJzc=', - }, - }, - balanceCommitment: { - inner: 'BoQIdVlbLjgzjoMFFq9/DfH6749Rl+sDC6EhLJlGZRI=', - }, - wrappedMemoKey: 'yLlXMEeghEa7HxQOh6MQGlzz8CruMZPuVA3ULj4qs9WK3OgsX7bftyPkYmjZ7Yft', - ovkWrappedKey: 'LX7h8SsJ/zJFGSc9Gc/rlCi3ZTHp3ABe9fvfpwitRvL8viZe80aModXq/ri3c3qE', - }, - proof: { - inner: - 'XHxrJbh21801r8tfC2Ryhe7wmxTfCa9S3WuXFdWYEkUlRvj4KD0t8xafnNUbfeyAGqb7D9vTf+6v3hmz+5TYPStcXJqbknyHGb7dFPrpNJeXn3IM+530BBg0BKCSbXsABbv5GEA1Lbnt6JX08r7qf6eupMGT7SqoYaURwcChnI5NDX6IaRL8QOXD7ofUeysBb+mD4e0jWt2Xr2ANl1EMrsgl7lCWkp5mnQ4M/DYS4i3P3s3JUoYG9h9nbfhE1CkA', - }, - }, - }, - ], - transactionParameters: { - chainId: 'penumbra-testnet-deimos', - fee: { - amount: {}, - }, - }, - detectionData: { - fmdClues: [ - { - inner: - '4sbjmNOe3fKz96wEUJR3r6opa4MSwFFeZAgjG1UZNRJcn/LpOc+ZKMj1ZozM/E6Q8agIZRKrY94NCjoU5vfVAgAAAAA=', - }, - { - inner: - 'JBC0c08hfc6BoI2DPpxkrw7L+s+s3XCPpM842sLCOA262Af3+6kW5RTsnRWIQ+h2IcqGUJWrNPkZzibglM02BAAAAAA=', - }, - ], - }, - memo: { - inner: - 'Ne9LOPmWu+oeMWtF2bCd2fgKu8UTeJyi4f2dqmsUSe78Jigz4sBELgFQwyO/9byAG2b2crdsXwyUrLS8/D3z5YXkizaFNFDJ180Bc3F3p+7wS1wi6cRzM18tJCtD9eCSZtIPru/B5fbP0NFt7X/UHVf5IWPpzM4TwlF6E1S8phcSOQIvybc+nLKfVVuyo+gcnPGGx3SJAoK3NozxrA7tcLlMbKB0X9I2kHg2qv9sdvYASCLOEk9z2ylAQLvPKrwTnUzv+WDsuIi48+llhYp/RCQS0dYryrIzTKf5s6OPNjteImDKI6Ze7csuNAtWQg/FtcQrm6Nfpvg1AYHjk/cbaJdLnXDwg/IJL5dlxlxX6Wr+6JFpLrE/Xi7mfg6F6qwcHAFj3uKEKNzFiWb9Yv0NklSCq7G5kculVYD8xgwHjorI+ldpI4KxHcBDTjpnTzKEgVg98OofskYOp6UqxKJioo7BMTAmb8RqfobzVrqbZypLhaDcyvZtWE9MFw13sopV4WkRtNhsZdTmOfsa2SrOHjAywFdyrdDrLSy8byBY2WtWfJWM5YreSrAR4QPF9PLHslM0WKuvR2naldVVqy/Qkzk1kyF+6lk+hwfrFxE8oGuFf4hoa/mIT9BLkejR/bmQl+aulziKClKzKOLqIcRwhRFa1rcTd2WAn+wWmaV3i7HNevrHqxQJ+Th8/qZObM9L', - }, - }, - bindingSig: { - inner: - 'opEm2HzD29Kie5TkVmEpxHa/wpF4I0mW5CfLCz+GOwI2cHe46BPyWjz8COZekiCc1VECYEeQXe1a/leNyRixAA==', - }, - anchor: { - inner: 'pO/o5BB9FaNnk69lszgtX+DeJtw3jNjXXC81XERcUQY=', - }, -}); - -const transactionPerspective = TransactionPerspective.fromJson({ - payloadKeys: [ - { - payloadKey: { - inner: 'tXxc7JUZT1HcboC07cMUUumUKvhJGfv+Izp6Fjq13iQ=', - }, - commitment: { - inner: 'VxJkYflpkJKddFzcvB0r81ZdyEBY3ar1ixW405l/rwM=', - }, - }, - { - payloadKey: { - inner: 'SLpi6Ub0ltYRjUhdvn82j4SejwPI23kpMS30yiyXkXw=', - }, - commitment: { - inner: '3FTx6D+IH8RBr5VuJTak34oHtGk+cu/zMDK32Kb8wAQ=', - }, - }, - ], - transactionId: { - inner: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=', - }, -}); diff --git a/packages/services/src/view-service/transaction-info-by-hash.ts b/packages/services/src/view-service/transaction-info-by-hash.ts deleted file mode 100644 index 196f338f..00000000 --- a/packages/services/src/view-service/transaction-info-by-hash.ts +++ /dev/null @@ -1,29 +0,0 @@ -import type { Impl } from '.'; -import { servicesCtx } from '../ctx/prax'; -import { Code, ConnectError } from '@connectrpc/connect'; -import { generateTransactionInfo } from '@penumbra-zone/wasm/transaction'; -import { TransactionInfo } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; -import { fvkCtx } from '../ctx/full-viewing-key'; - -export const transactionInfoByHash: Impl['transactionInfoByHash'] = async (req, ctx) => { - if (!req.id) throw new ConnectError('Missing transaction ID in request', Code.InvalidArgument); - - const services = await ctx.values.get(servicesCtx)(); - const { indexedDb, querier } = await services.getWalletServices(); - const fvk = ctx.values.get(fvkCtx); - - // Check database for transaction first - // if not in database, query tendermint for public info on the transaction - const { transaction, height } = - (await indexedDb.getTransaction(req.id)) ?? (await querier.tendermint.getTransaction(req.id)); - - if (!transaction) throw new ConnectError('Transaction not available', Code.NotFound); - - const { txp: perspective, txv: view } = await generateTransactionInfo( - await fvk(), - transaction, - indexedDb.constants(), - ); - const txInfo = new TransactionInfo({ height, id: req.id, transaction, perspective, view }); - return { txInfo }; -}; diff --git a/packages/services/src/view-service/transaction-info.test.ts b/packages/services/src/view-service/transaction-info.test.ts deleted file mode 100644 index 0a72d387..00000000 --- a/packages/services/src/view-service/transaction-info.test.ts +++ /dev/null @@ -1,141 +0,0 @@ -import { ViewService } from '@penumbra-zone/protobuf'; -import { servicesCtx } from '../ctx/prax'; - -import { createContextValues, createHandlerContext, HandlerContext } from '@connectrpc/connect'; - -import { beforeEach, describe, expect, test, vi } from 'vitest'; - -import { - TransactionInfo, - TransactionInfoRequest, - TransactionInfoResponse, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; -import { IndexedDbMock, MockServices, testFullViewingKey } from '../test-utils'; -import type { ServicesInterface } from '@penumbra-zone/types/services'; -import { transactionInfo } from './transaction-info'; -import { fvkCtx } from '../ctx/full-viewing-key'; - -const mockTransactionInfo = vi.hoisted(() => vi.fn()); -vi.mock('@penumbra-zone/wasm/transaction', () => ({ - generateTransactionInfo: mockTransactionInfo, -})); - -describe('TransactionInfo request handler', () => { - let mockServices: MockServices; - let mockCtx: HandlerContext; - let mockIndexedDb: IndexedDbMock; - let req: TransactionInfoRequest; - - beforeEach(() => { - vi.resetAllMocks(); - - const mockIterateTransactionInfo = { - next: vi.fn(), - [Symbol.asyncIterator]: () => mockIterateTransactionInfo, - }; - - mockIndexedDb = { - iterateTransactions: () => mockIterateTransactionInfo, - constants: vi.fn(), - }; - - mockServices = { - getWalletServices: vi.fn(() => - Promise.resolve({ indexedDb: mockIndexedDb }), - ) as MockServices['getWalletServices'], - }; - - mockCtx = createHandlerContext({ - service: ViewService, - method: ViewService.methods.transactionInfo, - protocolName: 'mock', - requestMethod: 'MOCK', - url: '/mock', - contextValues: createContextValues() - .set(servicesCtx, () => Promise.resolve(mockServices as unknown as ServicesInterface)) - .set(fvkCtx, () => Promise.resolve(testFullViewingKey)), - }); - - mockTransactionInfo.mockReturnValue({ - txp: {}, - txv: {}, - }); - - for (const record of testData) { - mockIterateTransactionInfo.next.mockResolvedValueOnce({ - value: record, - }); - } - mockIterateTransactionInfo.next.mockResolvedValueOnce({ - done: true, - }); - req = new TransactionInfoRequest(); - }); - - test('should get all transactions if startHeight and endHeight are not set in request', async () => { - const responses: TransactionInfoResponse[] = []; - for await (const res of transactionInfo(req, mockCtx)) { - responses.push(new TransactionInfoResponse(res)); - } - expect(responses.length).toBe(4); - }); - - test('should get only transactions whose height is not greater than endHeight', async () => { - const responses: TransactionInfoResponse[] = []; - req.endHeight = 2525n; - for await (const res of transactionInfo(req, mockCtx)) { - responses.push(new TransactionInfoResponse(res)); - } - expect(responses.length).toBe(3); - }); - - test('should receive only transactions whose height is not less than startHeight', async () => { - const responses: TransactionInfoResponse[] = []; - req.startHeight = 2525n; - for await (const res of transactionInfo(req, mockCtx)) { - responses.push(new TransactionInfoResponse(res)); - } - expect(responses.length).toBe(2); - }); - - test('should receive only transactions whose height is between startHeight and endHeight inclusive', async () => { - const responses: TransactionInfoResponse[] = []; - req.startHeight = 998n; - req.endHeight = 2525n; - for await (const res of transactionInfo(req, mockCtx)) { - responses.push(new TransactionInfoResponse(res)); - } - expect(responses.length).toBe(2); - }); -}); - -const testData: TransactionInfo[] = [ - TransactionInfo.fromJson({ - height: '222', - id: { - inner: '1MI8IG5D3MQj3s1j0MXTwCQtAaVbwTlPkW8Qdz1EVIo=', - }, - transaction: {}, - }), - TransactionInfo.fromJson({ - height: '1000', - id: { - inner: '2MI8IG5D3MQj3s1j0MXTwCQtAaVbwTlPkW8Qdz1EVIo=', - }, - transaction: {}, - }), - TransactionInfo.fromJson({ - height: '2525', - id: { - inner: '3MI8IG5D3MQj3s1j0MXTwCQtAaVbwTlPkW8Qdz1EVIo=', - }, - transaction: {}, - }), - TransactionInfo.fromJson({ - height: '12255', - id: { - inner: '4MI8IG5D3MQj3s1j0MXTwCQtAaVbwTlPkW8Qdz1EVIo=', - }, - transaction: {}, - }), -]; diff --git a/packages/services/src/view-service/transaction-info.ts b/packages/services/src/view-service/transaction-info.ts deleted file mode 100644 index 02b562a1..00000000 --- a/packages/services/src/view-service/transaction-info.ts +++ /dev/null @@ -1,36 +0,0 @@ -import type { Impl } from '.'; -import { servicesCtx } from '../ctx/prax'; -import { TransactionInfo } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; -import { generateTransactionInfo } from '@penumbra-zone/wasm/transaction'; -import { fvkCtx } from '../ctx/full-viewing-key'; - -export const transactionInfo: Impl['transactionInfo'] = async function* (req, ctx) { - const services = await ctx.values.get(servicesCtx)(); - const { indexedDb } = await services.getWalletServices(); - - const fvk = ctx.values.get(fvkCtx); - - for await (const txRecord of indexedDb.iterateTransactions()) { - // filter transactions between startHeight and endHeight, inclusive - if ( - !txRecord.transaction || - txRecord.height < req.startHeight || - (req.endHeight && txRecord.height > req.endHeight) - ) - continue; - - const { txp: perspective, txv: view } = await generateTransactionInfo( - await fvk(), - txRecord.transaction, - indexedDb.constants(), - ); - const txInfo = new TransactionInfo({ - height: txRecord.height, - id: txRecord.id, - transaction: txRecord.transaction, - perspective, - view, - }); - yield { txInfo }; - } -}; diff --git a/packages/services/src/view-service/transaction-planner/assert-swap-assets-are-not-the-same.test.ts b/packages/services/src/view-service/transaction-planner/assert-swap-assets-are-not-the-same.test.ts deleted file mode 100644 index 49c0c98c..00000000 --- a/packages/services/src/view-service/transaction-planner/assert-swap-assets-are-not-the-same.test.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { describe, expect, it } from 'vitest'; -import { assertSwapAssetsAreNotTheSame } from './assert-swap-assets-are-not-the-same'; -import { - TransactionPlannerRequest, - TransactionPlannerRequest_Swap, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; - -const swapWithSameAssets = new TransactionPlannerRequest_Swap({ - value: { - assetId: { - inner: new Uint8Array([0, 1, 2, 3]), - }, - }, - targetAsset: { - inner: new Uint8Array([0, 1, 2, 3]), - }, -}); - -const swapWithDifferentAssets = new TransactionPlannerRequest_Swap({ - value: { - assetId: { - inner: new Uint8Array([0, 1, 2, 3]), - }, - }, - targetAsset: { - inner: new Uint8Array([4, 5, 6, 7]), - }, -}); - -const transactionPlanContainingSwapWithSameAssets = new TransactionPlannerRequest({ - swaps: [swapWithSameAssets], -}); - -const transactionPlanContainingSwapWithDifferentAssets = new TransactionPlannerRequest({ - swaps: [swapWithDifferentAssets], -}); - -const transactionPlanContainingBothSwapTypes = new TransactionPlannerRequest({ - swaps: [swapWithDifferentAssets, swapWithSameAssets], -}); - -describe('assertSwapAssetsAreNotTheSame()', () => { - it("does not throw if the swap's trading pair are different assets", () => { - expect(() => - assertSwapAssetsAreNotTheSame(transactionPlanContainingSwapWithDifferentAssets), - ).not.toThrow(); - }); - - it("throws if the swap's trading pair are the same assets", () => { - expect(() => - assertSwapAssetsAreNotTheSame(transactionPlanContainingSwapWithSameAssets), - ).toThrow( - 'Attempted to make a swap in which both assets were of the same type. A swap must be between two different asset types.', - ); - }); - - it("throws if there are multiple swaps, and only one swap's trading pair are the same assets", () => { - expect(() => assertSwapAssetsAreNotTheSame(transactionPlanContainingBothSwapTypes)).toThrow( - 'Attempted to make a swap in which both assets were of the same type. A swap must be between two different asset types.', - ); - }); -}); diff --git a/packages/services/src/view-service/transaction-planner/assert-swap-assets-are-not-the-same.ts b/packages/services/src/view-service/transaction-planner/assert-swap-assets-are-not-the-same.ts deleted file mode 100644 index 0a09ad84..00000000 --- a/packages/services/src/view-service/transaction-planner/assert-swap-assets-are-not-the-same.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { TransactionPlannerRequest } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; -import { Code, ConnectError } from '@connectrpc/connect'; -import { getAssetIdFromValue } from '@penumbra-zone/getters/value'; - -export const assertSwapAssetsAreNotTheSame = ( - transactionPlannerRequest: TransactionPlannerRequest, -) => { - transactionPlannerRequest.swaps.forEach(swap => { - const inputAssetId = getAssetIdFromValue(swap.value); - const outputAssetId = swap.targetAsset; - - if (inputAssetId.equals(outputAssetId)) { - throw new ConnectError( - 'Attempted to make a swap in which both assets were of the same type. A swap must be between two different asset types.', - Code.InvalidArgument, - ); - } - }); -}; diff --git a/packages/services/src/view-service/transaction-planner/index.test.ts b/packages/services/src/view-service/transaction-planner/index.test.ts deleted file mode 100644 index 18fe9e58..00000000 --- a/packages/services/src/view-service/transaction-planner/index.test.ts +++ /dev/null @@ -1,123 +0,0 @@ -import { beforeEach, describe, expect, test, vi } from 'vitest'; -import { TransactionPlannerRequest } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; -import { createContextValues, createHandlerContext, HandlerContext } from '@connectrpc/connect'; -import { ViewService } from '@penumbra-zone/protobuf'; -import { servicesCtx } from '../../ctx/prax'; -import { IndexedDbMock, MockServices, testFullViewingKey } from '../../test-utils'; -import type { ServicesInterface } from '@penumbra-zone/types/services'; -import { FmdParameters } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/shielded_pool/v1/shielded_pool_pb'; -import { AppParameters } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/app/v1/app_pb'; -import { SctParameters } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/sct/v1/sct_pb'; -import { GasPrices } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/fee/v1/fee_pb'; -import { transactionPlanner } from '.'; -import { fvkCtx } from '../../ctx/full-viewing-key'; - -const mockPlanTransaction = vi.hoisted(() => vi.fn()); -vi.mock('@penumbra-zone/wasm/planner', () => ({ - planTransaction: mockPlanTransaction, -})); -describe('TransactionPlanner request handler', () => { - let mockServices: MockServices; - let mockIndexedDb: IndexedDbMock; - let mockCtx: HandlerContext; - let req: TransactionPlannerRequest; - - beforeEach(() => { - vi.resetAllMocks(); - - mockIndexedDb = { - getFmdParams: vi.fn(), - getAppParams: vi.fn(), - getGasPrices: vi.fn(), - constants: vi.fn(), - }; - - mockServices = { - getWalletServices: vi.fn(() => - Promise.resolve({ - indexedDb: mockIndexedDb, - }), - ) as MockServices['getWalletServices'], - }; - - mockCtx = createHandlerContext({ - service: ViewService, - method: ViewService.methods.transactionPlanner, - protocolName: 'mock', - requestMethod: 'MOCK', - url: '/mock', - contextValues: createContextValues() - .set(servicesCtx, () => Promise.resolve(mockServices as unknown as ServicesInterface)) - .set(fvkCtx, () => Promise.resolve(testFullViewingKey)), - }); - - req = new TransactionPlannerRequest({}); - }); - - test('should create a transaction plan if all necessary data exists in indexed-db', async () => { - mockIndexedDb.getFmdParams?.mockResolvedValueOnce( - new FmdParameters({ - precisionBits: 12, - asOfBlockHeight: 2n, - }), - ); - mockIndexedDb.getAppParams?.mockResolvedValueOnce( - new AppParameters({ - chainId: 'penumbra-testnet-mock', - sctParams: new SctParameters({ - epochDuration: 719n, - }), - }), - ); - mockIndexedDb.getGasPrices?.mockResolvedValueOnce( - new GasPrices({ - verificationPrice: 22n, - executionPrice: 222n, - blockSpacePrice: 2n, - compactBlockSpacePrice: 120n, - }), - ); - await transactionPlanner(req, mockCtx); - - expect(mockPlanTransaction.mock.calls.length === 1).toBeTruthy(); - }); - - test('should throw error if FmdParameters not available', async () => { - await expect(transactionPlanner(req, mockCtx)).rejects.toThrow('FmdParameters not available'); - }); - - test('should throw error if SctParameters not available', async () => { - mockIndexedDb.getFmdParams?.mockResolvedValueOnce(new FmdParameters()); - mockIndexedDb.getAppParams?.mockResolvedValueOnce( - new AppParameters({ - chainId: 'penumbra-testnet-mock', - }), - ); - await expect(transactionPlanner(req, mockCtx)).rejects.toThrow('SctParameters not available'); - }); - - test('should throw error if ChainId not available', async () => { - mockIndexedDb.getFmdParams?.mockResolvedValueOnce(new FmdParameters()); - mockIndexedDb.getAppParams?.mockResolvedValueOnce( - new AppParameters({ - sctParams: new SctParameters({ - epochDuration: 719n, - }), - }), - ); - await expect(transactionPlanner(req, mockCtx)).rejects.toThrow('ChainId not available'); - }); - - test('should throw error if Gas prices is not available', async () => { - mockIndexedDb.getFmdParams?.mockResolvedValueOnce(new FmdParameters()); - mockIndexedDb.getAppParams?.mockResolvedValueOnce( - new AppParameters({ - chainId: 'penumbra-testnet-mock', - sctParams: new SctParameters({ - epochDuration: 719n, - }), - }), - ); - await expect(transactionPlanner(req, mockCtx)).rejects.toThrow('Gas prices is not available'); - }); -}); diff --git a/packages/services/src/view-service/transaction-planner/index.ts b/packages/services/src/view-service/transaction-planner/index.ts deleted file mode 100644 index f43753cc..00000000 --- a/packages/services/src/view-service/transaction-planner/index.ts +++ /dev/null @@ -1,48 +0,0 @@ -import type { Impl } from '..'; -import { servicesCtx } from '../../ctx/prax'; -import { planTransaction } from '@penumbra-zone/wasm/planner'; -import { Code, ConnectError } from '@connectrpc/connect'; -import { assertSwapAssetsAreNotTheSame } from './assert-swap-assets-are-not-the-same'; -import { TransactionPlannerRequest } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; -import { fvkCtx } from '../../ctx/full-viewing-key'; - -export const transactionPlanner: Impl['transactionPlanner'] = async (req, ctx) => { - const services = await ctx.values.get(servicesCtx)(); - const { indexedDb } = await services.getWalletServices(); - - const fvk = ctx.values.get(fvkCtx); - - assertValidRequest(req); - - const fmdParams = await indexedDb.getFmdParams(); - if (!fmdParams) throw new ConnectError('FmdParameters not available', Code.FailedPrecondition); - const { chainId, sctParams } = (await indexedDb.getAppParams()) ?? {}; - if (!sctParams) throw new ConnectError('SctParameters not available', Code.FailedPrecondition); - if (!chainId) throw new ConnectError('ChainId not available', Code.FailedPrecondition); - const gasPrices = await indexedDb.getGasPrices(); - if (!gasPrices) throw new ConnectError('Gas prices is not available', Code.FailedPrecondition); - - const idbConstants = indexedDb.constants(); - - const plan = await planTransaction(idbConstants, req, await fvk()); - return { plan }; -}; - -/** - * Makes a series of assertions that ensure the validity of the request, - * throwing an error if any of them fail. - * - * Add more assertions to this function as needed. - * - * NOTE: Assertions related to security should NOT be run here, but rather in - * the `CustodyService#authorize` implementation. That's because websites don't - * actually have to call `ViewService#transactionPlanner`: - * `ViewService#transactionPlanner` is just a convenience method for web apps - * that don't want to build the transaction plan themselves. But a malicious - * website could skip this step, build a transaction plan themselves, and submit - * it for authorization. Thus, it is at the authorization stage we should catch - * those issues, since there is no way to avoid that stage. - */ -const assertValidRequest = (req: TransactionPlannerRequest): void => { - assertSwapAssetsAreNotTheSame(req); -}; diff --git a/packages/services/src/view-service/unbonding-tokens-by-address-index/helpers.test.ts b/packages/services/src/view-service/unbonding-tokens-by-address-index/helpers.test.ts deleted file mode 100644 index 107caba2..00000000 --- a/packages/services/src/view-service/unbonding-tokens-by-address-index/helpers.test.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { describe, expect, it, vi } from 'vitest'; -import { getIsClaimable } from './helpers'; -import { - AppParametersResponse, - BalancesResponse, - StatusResponse, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; -import { createHandlerContext } from '@connectrpc/connect'; -import { ViewService } from '@penumbra-zone/protobuf'; - -const mockAppParameters = vi.hoisted(() => vi.fn()); -vi.mock('../app-parameters', () => ({ - appParameters: mockAppParameters, -})); - -const mockStatus = vi.hoisted(() => vi.fn()); -vi.mock('../status', () => ({ - status: mockStatus, -})); - -const mockCtx = createHandlerContext({ - service: ViewService, - method: ViewService.methods.unbondingTokensByAddressIndex, - protocolName: 'mock', - requestMethod: 'MOCK', - url: '/mock', -}); - -describe('getIsClaimable()', () => { - it("returns `true` when we've passed the unbonding delay period", async () => { - mockAppParameters.mockResolvedValue( - new AppParametersResponse({ - parameters: { - stakeParams: { - unbondingDelay: 100n, - }, - }, - }), - ); - - mockStatus.mockResolvedValue( - new StatusResponse({ - fullSyncHeight: 200n, - }), - ); - - const balancesResponse = new BalancesResponse({ - balanceView: { - valueView: { - case: 'knownAssetId', - value: { - metadata: { - display: 'unbonding_start_at_100_penumbravalid1abc123', - }, - }, - }, - }, - }); - - await expect(getIsClaimable(balancesResponse, mockCtx)).resolves.toBe(true); - }); - - it("returns `false` when we haven't yet passed the unbonding delay period", async () => { - mockAppParameters.mockResolvedValue( - new AppParametersResponse({ - parameters: { - stakeParams: { - unbondingDelay: 100n, - }, - }, - }), - ); - - mockStatus.mockResolvedValue( - new StatusResponse({ - fullSyncHeight: 200n, - }), - ); - - const balancesResponse = new BalancesResponse({ - balanceView: { - valueView: { - case: 'knownAssetId', - value: { - metadata: { - display: 'unbonding_start_at_150_penumbravalid1abc123', - }, - }, - }, - }, - }); - - await expect(getIsClaimable(balancesResponse, mockCtx)).resolves.toBe(false); - }); -}); diff --git a/packages/services/src/view-service/unbonding-tokens-by-address-index/helpers.ts b/packages/services/src/view-service/unbonding-tokens-by-address-index/helpers.ts deleted file mode 100644 index 69c8a571..00000000 --- a/packages/services/src/view-service/unbonding-tokens-by-address-index/helpers.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { - AppParametersRequest, - BalancesResponse, - StatusRequest, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; -import { PartialMessage } from '@bufbuild/protobuf'; -import { HandlerContext } from '@connectrpc/connect'; -import { assetPatterns } from '@penumbra-zone/types/assets'; -import { getDisplayFromBalancesResponse } from '@penumbra-zone/getters/balances-response'; -import { status } from '../status'; -import { appParameters } from '../app-parameters'; - -export const isUnbondingTokenBalance = (balancesResponse: PartialMessage) => { - const display = getDisplayFromBalancesResponse(new BalancesResponse(balancesResponse)); - return display ? assetPatterns.unbondingToken.matches(display) : false; -}; - -/** - * Given a `BalancesResponse`, resolves to a boolean indicating whether the - * value in the response is an unbonding token eligible for claiming. - * - * @todo This is currently a somewhat naive implementation -- it only takes into - * account whether the `unbondingDelay` from `AppParameters.stakeParams` has - * passed. This may mean that some users will have to wait longer than is - * strictly necessary to claim their unbonding tokens, since claiming of - * unbonding tokens can happen earlier in certain cases, like if a validator - * itself becomes unbonded. Once the core team has worked out the logic for - * earlier unbonding, this should be updated to account for those cases. - */ -export const getIsClaimable = async ( - balancesResponse: PartialMessage, - ctx: HandlerContext, -): Promise => { - const [{ fullSyncHeight }, { parameters }] = await Promise.all([ - status(new StatusRequest(), ctx), - appParameters(new AppParametersRequest(), ctx), - ]); - - if (!fullSyncHeight || !parameters?.stakeParams?.unbondingDelay) return false; - - const display = getDisplayFromBalancesResponse(new BalancesResponse(balancesResponse)); - if (!display) return false; - - const unbondingStartHeight = assetPatterns.unbondingToken.capture(display); - - if (unbondingStartHeight?.startAt) { - const blocksSinceUnbondingStarted = fullSyncHeight - BigInt(unbondingStartHeight.startAt); - return blocksSinceUnbondingStarted >= parameters.stakeParams.unbondingDelay; - } - - return false; -}; diff --git a/packages/services/src/view-service/unbonding-tokens-by-address-index/index.test.ts b/packages/services/src/view-service/unbonding-tokens-by-address-index/index.test.ts deleted file mode 100644 index 96bf221a..00000000 --- a/packages/services/src/view-service/unbonding-tokens-by-address-index/index.test.ts +++ /dev/null @@ -1,201 +0,0 @@ -import { - AppParametersResponse, - BalancesResponse, - StatusResponse, - UnbondingTokensByAddressIndexRequest, - UnbondingTokensByAddressIndexRequest_Filter, - UnbondingTokensByAddressIndexResponse, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; -import { ViewService } from '@penumbra-zone/protobuf'; -import { createContextValues, createHandlerContext, PromiseClient } from '@connectrpc/connect'; -import { beforeEach, describe, expect, it, vi } from 'vitest'; -import { unbondingTokensByAddressIndex } from '.'; -import Array from '@penumbra-zone/polyfills/Array.fromAsync'; -import { getDisplayDenomFromView } from '@penumbra-zone/getters/value-view'; -import { StakeService } from '@penumbra-zone/protobuf'; -import { stakeClientCtx } from '../../ctx/stake-client'; -import { ValidatorInfoResponse } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/stake/v1/stake_pb'; - -const mockBalances = vi.hoisted(() => vi.fn()); -vi.mock('../balances', () => ({ - balances: mockBalances, -})); - -const mockAppParameters = vi.hoisted(() => vi.fn()); -vi.mock('../app-parameters', () => ({ - appParameters: mockAppParameters, -})); - -const mockStatus = vi.hoisted(() => vi.fn()); -vi.mock('../status', () => ({ - status: mockStatus, -})); - -const mockStakingClient = { - getValidatorInfo: vi.fn(), -}; - -const mockCtx = createHandlerContext({ - service: ViewService, - method: ViewService.methods.unbondingTokensByAddressIndex, - protocolName: 'mock', - requestMethod: 'MOCK', - url: '/mock', - contextValues: createContextValues().set( - stakeClientCtx, - mockStakingClient as unknown as PromiseClient, - ), -}); - -const mockBalancesResponse1 = new BalancesResponse({ - balanceView: { - valueView: { - case: 'knownAssetId', - value: { - amount: { hi: 0n, lo: 1n }, - metadata: { - display: 'penumbra', - }, - }, - }, - }, -}); - -const mockBalancesResponse2 = new BalancesResponse({ - balanceView: { - valueView: { - case: 'knownAssetId', - value: { - amount: { hi: 0n, lo: 2n }, - metadata: { - display: - 'unbonding_start_at_100_penumbravalid1u2z9c75xcc2ny6jxccge6ehqtqkhgy4ltxms3ldappr06ekpguxqq48pdh', - }, - }, - }, - }, -}); - -const mockBalancesResponse3 = new BalancesResponse({ - balanceView: { - valueView: { - case: 'knownAssetId', - value: { - amount: { hi: 0n, lo: 3n }, - metadata: { - display: - 'unbonding_start_at_200_penumbravalid1ltltrqe7f2c0q8mqlsx3u74s0r6nm968f325njz4h8zzqh0gsgfq2g5d3m', - }, - }, - }, - }, -}); - -const mockBalancesResponse4 = new BalancesResponse({ - balanceView: { - valueView: { - case: 'unknownAssetId', - value: { - amount: { hi: 0n, lo: 3n }, - }, - }, - }, -}); - -describe('Unbonding Tokens by Address Index handler', () => { - beforeEach(() => { - vi.resetAllMocks(); - - mockAppParameters.mockResolvedValue( - new AppParametersResponse({ parameters: { stakeParams: { unbondingDelay: 100n } } }), - ); - - mockStakingClient.getValidatorInfo.mockResolvedValue( - new ValidatorInfoResponse({ - validatorInfo: { - validator: { - name: 'Validator 1', - }, - }, - }), - ); - mockStatus.mockResolvedValue(new StatusResponse({ fullSyncHeight: 250n })); - - const mockBalancesResponse = { - next: vi.fn(), - [Symbol.asyncIterator]: () => mockBalancesResponse, - }; - mockBalancesResponse.next.mockResolvedValueOnce({ - value: mockBalancesResponse1, - }); - mockBalancesResponse.next.mockResolvedValueOnce({ - value: mockBalancesResponse2, - }); - mockBalancesResponse.next.mockResolvedValueOnce({ - value: mockBalancesResponse3, - }); - mockBalancesResponse.next.mockResolvedValueOnce({ - value: mockBalancesResponse4, - }); - mockBalancesResponse.next.mockResolvedValueOnce({ done: true }); - - mockBalances.mockReturnValue(mockBalancesResponse); - }); - - describe('when passed no filter', () => { - it('returns all unbonding tokens, along with their claimable status', async () => { - const responses = await Array.fromAsync( - unbondingTokensByAddressIndex(new UnbondingTokensByAddressIndexRequest(), mockCtx), - ); - - expect(responses.length).toBe(2); - expect(responses[0]!.claimable).toBeTypeOf('boolean'); - expect(responses[1]!.claimable).toBeTypeOf('boolean'); - }); - }); - - describe('when filtering only for claimable tokens', () => { - it('returns only claimable unbonding tokens', async () => { - const responses = await Array.fromAsync( - unbondingTokensByAddressIndex( - new UnbondingTokensByAddressIndexRequest({ - filter: UnbondingTokensByAddressIndexRequest_Filter.CLAIMABLE, - }), - mockCtx, - ), - ); - - expect(responses.length).toBe(1); - expect(responses[0]!.claimable).toBe(true); - }); - }); - - describe('when filtering only for not-yet-claimable tokens', () => { - it('returns only not-yet-claimable unbonding tokens', async () => { - const responses = await Array.fromAsync( - unbondingTokensByAddressIndex( - new UnbondingTokensByAddressIndexRequest({ - filter: UnbondingTokensByAddressIndexRequest_Filter.NOT_YET_CLAIMABLE, - }), - mockCtx, - ), - ); - - expect(responses.length).toBe(1); - expect(responses[0]!.claimable).toBe(false); - }); - }); - - it("excludes any tokens that aren't unbonding tokens", async () => { - const responses = await Array.fromAsync( - unbondingTokensByAddressIndex(new UnbondingTokensByAddressIndexRequest(), mockCtx), - ); - const responseObjects = responses.map( - response => new UnbondingTokensByAddressIndexResponse(response), - ); - - expect(responses.length).toBe(2); - expect(getDisplayDenomFromView(responseObjects[0]!.valueView)).not.toBe('penumbra'); - expect(getDisplayDenomFromView(responseObjects[1]!.valueView)).not.toBe('penumbra'); - }); -}); diff --git a/packages/services/src/view-service/unbonding-tokens-by-address-index/index.ts b/packages/services/src/view-service/unbonding-tokens-by-address-index/index.ts deleted file mode 100644 index 9dece3e7..00000000 --- a/packages/services/src/view-service/unbonding-tokens-by-address-index/index.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { - BalancesRequest, - BalancesResponse, - UnbondingTokensByAddressIndexRequest_Filter, - UnbondingTokensByAddressIndexResponse, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; -import { Impl } from '..'; -import { balances } from '../balances'; -import { getIsClaimable, isUnbondingTokenBalance } from './helpers'; -import { Any } from '@bufbuild/protobuf'; -import { ValidatorInfo } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/stake/v1/stake_pb'; -import { stakeClientCtx } from '../../ctx/stake-client'; -import { getValidatorInfo } from '@penumbra-zone/getters/get-validator-info-response'; -import { assetPatterns } from '@penumbra-zone/types/assets'; -import { - getBalanceView, - getDisplayFromBalancesResponse, -} from '@penumbra-zone/getters/balances-response'; -import { identityKeyFromBech32m } from '@penumbra-zone/bech32m/penumbravalid'; - -export const unbondingTokensByAddressIndex: Impl['unbondingTokensByAddressIndex'] = - async function* (req, ctx) { - const stakeClient = ctx.values.get(stakeClientCtx); - if (!stakeClient) throw new Error('Staking context not found'); - for await (const balancesResponse of balances( - new BalancesRequest({ accountFilter: req.addressIndex }), - ctx, - )) { - if (!isUnbondingTokenBalance(balancesResponse)) continue; - const claimable = await getIsClaimable(balancesResponse, ctx); - - // See https://github.com/typescript-eslint/typescript-eslint/issues/7114 - // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison - if (req.filter === UnbondingTokensByAddressIndexRequest_Filter.CLAIMABLE && !claimable) { - continue; - } - - if ( - // See https://github.com/typescript-eslint/typescript-eslint/issues/7114 - // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison - req.filter === UnbondingTokensByAddressIndexRequest_Filter.NOT_YET_CLAIMABLE && - claimable - ) { - continue; - } - - const regexResult = assetPatterns.unbondingToken.capture( - getDisplayFromBalancesResponse(new BalancesResponse(balancesResponse)) ?? '', - ); - if (!regexResult) throw new Error('expected delegation token identity key not present'); - - const validatorInfoResponse = await stakeClient.getValidatorInfo({ - identityKey: identityKeyFromBech32m(regexResult.idKey), - }); - const validatorInfo = getValidatorInfo(validatorInfoResponse); - const extendedMetadata = new Any({ - typeUrl: ValidatorInfo.typeName, - value: validatorInfo.toBinary(), - }); - - const withValidatorInfo = getBalanceView(new BalancesResponse(balancesResponse)); - if (withValidatorInfo.valueView.case !== 'knownAssetId') - throw new Error(`Unexpected ValueView case: ${withValidatorInfo.valueView.case}`); - - withValidatorInfo.valueView.value.extendedMetadata = extendedMetadata; - - yield new UnbondingTokensByAddressIndexResponse({ - claimable, - valueView: withValidatorInfo, - }); - } - }; diff --git a/packages/services/src/view-service/unclaimed-swaps.test.ts b/packages/services/src/view-service/unclaimed-swaps.test.ts deleted file mode 100644 index 2d178f66..00000000 --- a/packages/services/src/view-service/unclaimed-swaps.test.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { ViewService } from '@penumbra-zone/protobuf'; -import { servicesCtx } from '../ctx/prax'; - -import { createContextValues, createHandlerContext, HandlerContext } from '@connectrpc/connect'; - -import { beforeEach, describe, expect, test, vi } from 'vitest'; - -import { - SwapRecord, - UnclaimedSwapsRequest, - UnclaimedSwapsResponse, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; -import { IndexedDbMock, MockServices } from '../test-utils'; -import type { ServicesInterface } from '@penumbra-zone/types/services'; -import { unclaimedSwaps } from './unclaimed-swaps'; - -describe('UnclaimedSwaps request handler', () => { - let mockServices: MockServices; - let mockCtx: HandlerContext; - let mockIndexedDb: IndexedDbMock; - let req: UnclaimedSwapsRequest; - - beforeEach(() => { - vi.resetAllMocks(); - - const mockIterateSwaps = { - next: vi.fn(), - [Symbol.asyncIterator]: () => mockIterateSwaps, - }; - - mockIndexedDb = { - iterateSwaps: () => mockIterateSwaps, - }; - - mockServices = { - getWalletServices: vi.fn(() => - Promise.resolve({ indexedDb: mockIndexedDb }), - ) as MockServices['getWalletServices'], - }; - - mockCtx = createHandlerContext({ - service: ViewService, - method: ViewService.methods.unclaimedSwaps, - protocolName: 'mock', - requestMethod: 'MOCK', - url: '/mock', - contextValues: createContextValues().set(servicesCtx, () => - Promise.resolve(mockServices as unknown as ServicesInterface), - ), - }); - - for (const record of testData) { - mockIterateSwaps.next.mockResolvedValueOnce({ - value: record, - }); - } - mockIterateSwaps.next.mockResolvedValueOnce({ - done: true, - }); - req = new UnclaimedSwapsRequest(); - }); - - test('should get all swaps with undefined heightClaimed', async () => { - const responses: UnclaimedSwapsResponse[] = []; - for await (const res of unclaimedSwaps(req, mockCtx)) { - responses.push(new UnclaimedSwapsResponse(res)); - } - expect(responses.length).toBe(2); - }); -}); - -const testData: SwapRecord[] = [ - SwapRecord.fromJson({ - swapCommitment: { inner: '16VBVkrk+s18q+Sjhl8uEGfS3i0dwF1FrkNm8Db6VAA=' }, - heightClaimed: 122, - nullifier: { inner: '1E7LbhBDgDXHiRvreFyCllcKOOQeuIVsbn2aw8uKhww=' }, - }), - SwapRecord.fromJson({ - swapCommitment: { inner: '26VBVkrk+s18q+Sjhl8uEGfS3i0dwF1FrkNm8Db6VAA=' }, - nullifier: { inner: '2E7LbhBDgDXHiRvreFyCllcKOOQeuIVsbn2aw8uKhww=' }, - }), - SwapRecord.fromJson({ - swapCommitment: { inner: '36VBVkrk+s18q+Sjhl8uEGfS3i0dwF1FrkNm8Db6VAA=' }, - nullifier: { inner: '3E7LbhBDgDXHiRvreFyCllcKOOQeuIVsbn2aw8uKhww=' }, - }), -]; diff --git a/packages/services/src/view-service/unclaimed-swaps.ts b/packages/services/src/view-service/unclaimed-swaps.ts deleted file mode 100644 index c8f77041..00000000 --- a/packages/services/src/view-service/unclaimed-swaps.ts +++ /dev/null @@ -1,13 +0,0 @@ -import type { Impl } from '.'; -import { servicesCtx } from '../ctx/prax'; - -export const unclaimedSwaps: Impl['unclaimedSwaps'] = async function* (_, ctx) { - const services = await ctx.values.get(servicesCtx)(); - - const { indexedDb } = await services.getWalletServices(); - - for await (const swap of indexedDb.iterateSwaps()) { - if (swap.heightClaimed !== 0n) continue; - yield { swap }; - } -}; diff --git a/packages/services/src/view-service/util/build-tx.ts b/packages/services/src/view-service/util/build-tx.ts deleted file mode 100644 index cca8387c..00000000 --- a/packages/services/src/view-service/util/build-tx.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { - AuthorizationData, - Transaction, - TransactionPlan, - WitnessData, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/transaction/v1/transaction_pb'; -import { buildParallel } from '@penumbra-zone/wasm/build'; -import { offscreenClient } from '../../offscreen-client'; -import { - AuthorizeAndBuildResponse, - WitnessAndBuildResponse, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; -import { PartialMessage } from '@bufbuild/protobuf'; -import { ConnectError } from '@connectrpc/connect'; - -import { FullViewingKey } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb'; - -export const optimisticBuild = async function* ( - transactionPlan: TransactionPlan, - witnessData: WitnessData, - authorizationRequest: PromiseLike, - fvk: FullViewingKey, -) { - // a promise that rejects if auth denies. raced with build tasks to cancel. - // if we raced auth directly, approval would complete the race. - const cancel = new Promise( - (_, reject) => - void Promise.resolve(authorizationRequest).catch((r: unknown) => - reject(ConnectError.from(r)), - ), - ); - - // kick off the parallel actions build - const offscreenTasks = offscreenClient.buildActions(transactionPlan, witnessData, fvk, cancel); - - // status updates - yield* progressStream(offscreenTasks, cancel); - - // final build is synchronous - const transaction: Transaction = buildParallel( - await Promise.all(offscreenTasks), - transactionPlan, - witnessData, - await authorizationRequest, - ); - - yield { - status: { - case: 'complete', - value: { transaction }, - }, - // TODO: satisfies type parameter? - } satisfies PartialMessage; -}; - -const progressStream = async function* (tasks: PromiseLike[], cancel: PromiseLike) { - // deliberately not a 'map' - tasks and promises have no direct relationship. - const tasksRemaining = Array.from(tasks, () => Promise.withResolvers()); - - // tasksRemaining will be consumed in order, as tasks complete in any order. - tasks.forEach(task => void task.then(() => tasksRemaining.shift()?.resolve())); - - // yield status when any task resolves the next 'remaining' promise - while (tasksRemaining.length) { - await Promise.race([cancel, tasksRemaining[0]?.promise]); - yield { - status: { - case: 'buildProgress', - // +1 to represent the final build step, which we aren't handling here - value: { progress: (tasks.length - tasksRemaining.length) / (tasks.length + 1) }, - }, - // TODO: satisfies type parameter? - } satisfies PartialMessage; - } -}; diff --git a/packages/services/src/view-service/util/custody-authorize.ts b/packages/services/src/view-service/util/custody-authorize.ts deleted file mode 100644 index 69137757..00000000 --- a/packages/services/src/view-service/util/custody-authorize.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { - AuthorizationData, - TransactionPlan, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/transaction/v1/transaction_pb'; -import { HandlerContext, ConnectError, Code } from '@connectrpc/connect'; -import { custodyClientCtx } from '../../ctx/custody-client'; - -export const custodyAuthorize = async ( - ctx: HandlerContext, - plan: TransactionPlan, -): Promise => { - const custodyClient = ctx.values.get(custodyClientCtx); - if (!custodyClient) - throw new ConnectError('Cannot access custody service', Code.FailedPrecondition); - const { data } = await custodyClient.authorize({ plan }); - if (!data) throw new ConnectError('No authorization data', Code.PermissionDenied); - return data; -}; diff --git a/packages/services/src/view-service/wallet-id.ts b/packages/services/src/view-service/wallet-id.ts deleted file mode 100644 index bc2410e2..00000000 --- a/packages/services/src/view-service/wallet-id.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { Impl } from '.'; -import { walletIdCtx } from '../ctx/wallet-id'; - -export const walletId: Impl['walletId'] = async (_, ctx) => { - const walletId = await ctx.values.get(walletIdCtx)(); - return { walletId }; -}; diff --git a/packages/services/src/view-service/witness-and-build.ts b/packages/services/src/view-service/witness-and-build.ts deleted file mode 100644 index e296541a..00000000 --- a/packages/services/src/view-service/witness-and-build.ts +++ /dev/null @@ -1,32 +0,0 @@ -import type { Impl } from '.'; -import { servicesCtx } from '../ctx/prax'; - -import { optimisticBuild } from './util/build-tx'; - -import { getWitness } from '@penumbra-zone/wasm/build'; - -import { Code, ConnectError } from '@connectrpc/connect'; -import { AuthorizationData } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/transaction/v1/transaction_pb'; -import { fvkCtx } from '../ctx/full-viewing-key'; - -export const witnessAndBuild: Impl['witnessAndBuild'] = async function* ( - { authorizationData, transactionPlan }, - ctx, -) { - const services = await ctx.values.get(servicesCtx)(); - if (!transactionPlan) throw new ConnectError('No tx plan', Code.InvalidArgument); - - const { indexedDb } = await services.getWalletServices(); - const fvk = ctx.values.get(fvkCtx); - - const sct = await indexedDb.getStateCommitmentTree(); - - const witnessData = getWitness(transactionPlan, sct); - - yield* optimisticBuild( - transactionPlan, - witnessData, - Promise.resolve(authorizationData ?? new AuthorizationData()), - await fvk(), - ); -}; diff --git a/packages/services/src/view-service/witness.test.ts b/packages/services/src/view-service/witness.test.ts deleted file mode 100644 index 6b373c76..00000000 --- a/packages/services/src/view-service/witness.test.ts +++ /dev/null @@ -1,173 +0,0 @@ -import { beforeEach, describe, expect, test, vi } from 'vitest'; -import { - WitnessRequest, - WitnessResponse, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; -import { createContextValues, createHandlerContext, HandlerContext } from '@connectrpc/connect'; -import { ViewService } from '@penumbra-zone/protobuf'; -import { servicesCtx } from '../ctx/prax'; -import { IndexedDbMock, MockServices } from '../test-utils'; -import { witness } from './witness'; -import { - TransactionPlan, - WitnessData, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/transaction/v1/transaction_pb'; -import type { ServicesInterface } from '@penumbra-zone/types/services'; - -describe('Witness request handler', () => { - let mockServices: MockServices; - let mockIndexedDb: IndexedDbMock; - let mockCtx: HandlerContext; - let req: WitnessRequest; - - beforeEach(() => { - vi.resetAllMocks(); - - mockIndexedDb = { - getStateCommitmentTree: vi.fn(), - }; - mockServices = { - getWalletServices: vi.fn(() => - Promise.resolve({ indexedDb: mockIndexedDb }), - ) as MockServices['getWalletServices'], - }; - mockCtx = createHandlerContext({ - service: ViewService, - method: ViewService.methods.witness, - protocolName: 'mock', - requestMethod: 'MOCK', - url: '/mock', - contextValues: createContextValues().set(servicesCtx, () => - Promise.resolve(mockServices as unknown as ServicesInterface), - ), - }); - req = new WitnessRequest({ - transactionPlan: testPlan, - }); - }); - - test('should successfully create witness data', async () => { - mockIndexedDb.getStateCommitmentTree?.mockResolvedValue(testSct); - const witnessResponse = new WitnessResponse(await witness(req, mockCtx)); - expect(witnessResponse.witnessData).instanceof(WitnessData); - }); - - test('should throw error if transaction plan is missing in request', async () => { - await expect(witness(new WitnessRequest(), mockCtx)).rejects.toThrow(); - }); -}); - -const testSct = { - last_position: { Position: { epoch: 5, block: 51, commitment: 0 } }, - last_forgotten: 0n, - hashes: [], - commitments: [ - { - position: { epoch: 5, block: 40, commitment: 1 }, - commitment: { - inner: '+et9QvGlWAzKXPYBEiUQ3zrACaOOoEZTdM0Ru+/22Q0=', - }, - }, - ], -}; -const testPlan = TransactionPlan.fromJson({ - actions: [ - { - output: { - value: { - amount: { - lo: '17000000', - }, - assetId: { - inner: 'KeqcLzNx9qSH5+lcJHBB9KNW+YPrBk5dKzvPMiypahA=', - }, - }, - destAddress: { - inner: - '0AI1VPl2Z2iM62nnBX+o00kL3Fcvcqm8zgp0ErDpw4hT2syB5TeaGJM8B+5KV+/3CS78toGM3WleoNgPh/7L9bKNOrmq7UEqBmfAb7MDI+w=', - }, - rseed: '/3i6n9kAwHRK7BglIH0QWZcwVjYeIhXcETFjgw4quNg=', - valueBlinding: 'oN/74T2n6BCbAD9fexKTYN7/EdgamOhzu0T1CaCyvwA=', - proofBlindingR: 'dx8BFun9Ecae4G5K35O+odpgIiW38Si/8af6v3BbiAI=', - proofBlindingS: 'tAK8dKHm4QfTmPDazgGeODGmz7NAcRZZqNjc5ngdsgA=', - }, - }, - { - spend: { - note: { - value: { - amount: { - lo: '999978000000', - }, - assetId: { - inner: 'KeqcLzNx9qSH5+lcJHBB9KNW+YPrBk5dKzvPMiypahA=', - }, - }, - rseed: 'H/Fy4tVGBPaCmYr7xskZ0cEhD79fj0bm/P2goI7NE+g=', - address: { - inner: - 'H54tVYCe2KONaws0+4Qt8jHSup2InYWauNEGtLa7+yQ8ssaP1Qc2bjsB7uyfQl3QKMXzfm3u70/CbK9tOiSXjDtDzx3AtQw2wKCeuht3Ono=', - }, - }, - position: '21477457921', - randomizer: 'H7NTioroyZVJ/axRjF9rFOTraMKY4/oI5rZ5ioc5XAI=', - valueBlinding: 'A8uFN42ZUkmm7K+mfMMIjrXWhQRR7gDSuFoHbUS63QI=', - proofBlindingR: 'oDcDqoOeA+cmJx9+85o3NjBO5F7czVTdpgZsd6AF0hE=', - proofBlindingS: 'AgGH9qmBSNerolyHPBfwjUn1hSR5o3asMrWflj4wrQk=', - }, - }, - { - output: { - value: { - amount: { - lo: '999961000000', - }, - assetId: { - inner: 'KeqcLzNx9qSH5+lcJHBB9KNW+YPrBk5dKzvPMiypahA=', - }, - }, - destAddress: { - inner: - 'H54tVYCe2KONaws0+4Qt8jHSup2InYWauNEGtLa7+yQ8ssaP1Qc2bjsB7uyfQl3QKMXzfm3u70/CbK9tOiSXjDtDzx3AtQw2wKCeuht3Ono=', - }, - rseed: 'fk7N8WEob+bgE/i0CZgmHGP8e0mGFHjKW2yzC7zKoUY=', - valueBlinding: 'TFPHBogTl0+n+aSf0X4ygrQ+i6Mc9s3a+6jbTTlidQA=', - proofBlindingR: 'uxySUkOiKig72CiH6q5Lx+5bDkGko4SxhJ+pZVuTohE=', - proofBlindingS: 'UKzlbj48dd24R2yl4UwB8vU8Lda1TN5+qGpQ8jFsIgQ=', - }, - }, - ], - transactionParameters: { - chainId: 'penumbra-testnet-deimos-2-38b9a683', - fee: { - amount: {}, - }, - }, - detectionData: { - cluePlans: [ - { - address: { - inner: - '0AI1VPl2Z2iM62nnBX+o00kL3Fcvcqm8zgp0ErDpw4hT2syB5TeaGJM8B+5KV+/3CS78toGM3WleoNgPh/7L9bKNOrmq7UEqBmfAb7MDI+w=', - }, - rseed: 'dDfkKQanWSTxc5w7su42ru+tTnD6xbJUJBhEGbpOY/8=', - }, - { - address: { - inner: - 'H54tVYCe2KONaws0+4Qt8jHSup2InYWauNEGtLa7+yQ8ssaP1Qc2bjsB7uyfQl3QKMXzfm3u70/CbK9tOiSXjDtDzx3AtQw2wKCeuht3Ono=', - }, - rseed: 'V3Vvhh7r9/1P/XmJrlwrFmeUhQ9JzbYbS+0GvhsHnIQ=', - }, - ], - }, - memo: { - plaintext: { - returnAddress: { - inner: - 'H54tVYCe2KONaws0+4Qt8jHSup2InYWauNEGtLa7+yQ8ssaP1Qc2bjsB7uyfQl3QKMXzfm3u70/CbK9tOiSXjDtDzx3AtQw2wKCeuht3Ono=', - }, - }, - key: 'y1Hc7R18awsR3rxn3EWaBDmWHYMiFVhC2gviFG7FA90=', - }, -}); diff --git a/packages/services/src/view-service/witness.ts b/packages/services/src/view-service/witness.ts deleted file mode 100644 index 0e1529a2..00000000 --- a/packages/services/src/view-service/witness.ts +++ /dev/null @@ -1,19 +0,0 @@ -import type { Impl } from '.'; -import { servicesCtx } from '../ctx/prax'; - -import { getWitness } from '@penumbra-zone/wasm/build'; - -import { Code, ConnectError } from '@connectrpc/connect'; - -export const witness: Impl['witness'] = async (req, ctx) => { - const services = await ctx.values.get(servicesCtx)(); - - if (!req.transactionPlan) throw new ConnectError('No tx plan in request', Code.InvalidArgument); - - const { indexedDb } = await services.getWalletServices(); - const sct = await indexedDb.getStateCommitmentTree(); - - const witnessData = getWitness(req.transactionPlan, sct); - - return { witnessData }; -}; diff --git a/packages/services/tests-setup.js b/packages/services/tests-setup.js deleted file mode 100644 index 3ff65b2c..00000000 --- a/packages/services/tests-setup.js +++ /dev/null @@ -1,24 +0,0 @@ -import { vi } from 'vitest'; - -// chrome.storage persistence middleware is run upon importing from `state/index.ts`. -// For tests, this is problematic as it uses globals. This mocks those out. -global.chrome = { - storage: { - onChanged: { - addListener: vi.fn(), - }, - - local: { - set: vi.fn(), - get: vi.fn().mockReturnValue({}), - remove: vi.fn(), - }, - session: { - set: vi.fn(), - get: vi.fn().mockReturnValue({}), - remove: vi.fn(), - }, - }, -}; - -global.DEFAULT_GRPC_URL = 'https://rpc.example.com/'; diff --git a/packages/services/tsconfig.json b/packages/services/tsconfig.json deleted file mode 100644 index 61a00fa2..00000000 --- a/packages/services/tsconfig.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "extends": "tsconfig/base.json", - "include": ["."], - "exclude": ["node_modules"] -} diff --git a/packages/services/vitest.config.ts b/packages/services/vitest.config.ts deleted file mode 100644 index 27e7e38e..00000000 --- a/packages/services/vitest.config.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { defineConfig } from 'vitest/config'; -import wasm from 'vite-plugin-wasm'; - -export default defineConfig({ - plugins: [wasm()], - test: { - setupFiles: ['./tests-setup.js'], - }, -}); diff --git a/packages/storage/CHANGELOG.md b/packages/storage/CHANGELOG.md deleted file mode 100644 index 687403ed..00000000 --- a/packages/storage/CHANGELOG.md +++ /dev/null @@ -1,177 +0,0 @@ -# @penumbra-zone/storage - -## 4.0.0 - -### Major Changes - -- 4012c48: remove chrome storage exports - -### Minor Changes - -- ab9d743: decouple service/rpc init -- e7d7ffc: 'chrome-extension': Add an onboarding screen for the default frontend selection - - '@penumbra-zone/storage': Remove the MINIFRONT_URL env usages - - '@penumbra-zone/ui': Don't show the image in SelectList.Option component if it is not passed - -### Patch Changes - -- adf3a28: Update to june 12 testnet registry -- Updated dependencies [6b06e04] - - @penumbra-zone/getters@6.1.0 - - @penumbra-zone/crypto-web@3.0.10 - -## 3.4.3 - -### Patch Changes - -- Updated dependencies [8fe4de6] - - @penumbra-zone/bech32m@5.0.0 - - @penumbra-zone/getters@6.0.0 - - @penumbra-zone/crypto-web@3.0.9 - -## 3.4.2 - -### Patch Changes - -- Updated dependencies [8b121ec] - - @penumbra-zone/bech32m@4.0.0 - - @penumbra-zone/getters@5.0.0 - - @penumbra-zone/crypto-web@3.0.8 - -## 3.4.1 - -### Patch Changes - -- a22d3a8: Update registry (noble/testnet channel update) - -## 3.4.0 - -### Minor Changes - -- 3ea1e6c: update buf types dependencies - -### Patch Changes - -- Updated dependencies [120b654] -- Updated dependencies [3ea1e6c] - - @penumbra-zone/getters@4.1.0 - - @penumbra-zone/bech32m@3.2.0 - - @penumbra-zone/crypto-web@3.0.7 - -## 3.3.0 - -### Minor Changes - -- e47a04e: Update registry to latest (fixes labs + adds starling) -- e4c9fce: Add features to handle auction withdrawals - -### Patch Changes - -- e35c6f7: Deps bumped to latest -- d6b8a23: Update registry -- Updated dependencies [146b48d] -- Updated dependencies [8ccaf30] -- Updated dependencies [8ccaf30] -- Updated dependencies [e35c6f7] -- Updated dependencies [cf63b30] -- Updated dependencies [8ccaf30] - - @penumbra-zone/getters@4.0.0 - - @penumbra-zone/bech32m@3.1.1 - - @penumbra-zone/crypto-web@3.0.6 - -## 3.2.0 - -### Minor Changes - -- v8.0.0 versioning and manifest - -### Patch Changes - -- 610a445: update osmosis channel for deimos-8 -- Updated dependencies - - @penumbra-zone/bech32m@3.1.0 - - @penumbra-zone/getters@3.0.2 - - @penumbra-zone/crypto-web@3.0.5 - -## 3.1.2 - -### Patch Changes - -- Updated dependencies [8410d2f] - - @penumbra-zone/bech32m@3.0.1 - - @penumbra-zone/getters@3.0.1 - - @penumbra-zone/crypto-web@3.0.4 - -## 3.1.1 - -### Patch Changes - -- @penumbra-zone/crypto-web@3.0.3 - -## 3.1.0 - -### Minor Changes - -- 55f31c9: Store sct positions of swaps - -### Patch Changes - -- Updated dependencies [3148375] -- Updated dependencies [fdd4303] - - @penumbra-zone/constants@4.0.0 - - @penumbra-zone/getters@3.0.0 - - @penumbra-zone/bech32m@3.0.0 - - @penumbra-zone/crypto-web@3.0.2 - -## 3.0.1 - -### Patch Changes - -- Updated dependencies [862283c] - - @penumbra-zone/constants@3.0.0 - - @penumbra-zone/getters@2.0.1 - - @penumbra-zone/crypto-web@3.0.1 - -## 3.0.0 - -### Major Changes - -- 76302da: Drop /src/ requirement for imports - -### Patch Changes - -- Updated dependencies [b4082b7] - - @penumbra-zone/crypto-web@3.0.0 - -## 2.0.1 - -### Patch Changes - -- 66c2407: v6.2.0 release - -## 2.0.0 - -### Major Changes - -- 929d278: barrel imports to facilitate better tree shaking - -### Patch Changes - -- 8933117: Account for changes to core -- Updated dependencies [8933117] -- Updated dependencies [929d278] - - @penumbra-zone/constants@2.0.0 - - @penumbra-zone/getters@2.0.0 - - @penumbra-zone/bech32@2.0.0 - - @penumbra-zone/crypto-web@2.0.0 - -## 1.0.2 - -### Patch Changes - -- Updated dependencies - - @penumbra-zone/constants@1.1.0 - - @penumbra-zone/getters@1.1.0 - - @penumbra-zone/crypto-web@1.0.1 diff --git a/packages/storage/eslint.config.mjs b/packages/storage/eslint.config.mjs deleted file mode 100644 index a53ed8e5..00000000 --- a/packages/storage/eslint.config.mjs +++ /dev/null @@ -1,13 +0,0 @@ -import { penumbraEslintConfig } from '@penumbra-zone/eslint-config'; -import { config, parser } from 'typescript-eslint'; - -export default config({ - ...penumbraEslintConfig, - languageOptions: { - parser, - parserOptions: { - project: true, - tsconfigRootDir: import.meta.dirname, - }, - }, -}); diff --git a/packages/storage/package.json b/packages/storage/package.json deleted file mode 100644 index de43fcff..00000000 --- a/packages/storage/package.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "name": "@penumbra-zone/storage", - "version": "4.0.0", - "private": true, - "license": "(MIT OR Apache-2.0)", - "type": "module", - "scripts": { - "lint": "eslint src", - "test": "vitest run" - }, - "files": [ - "src/", - "*.md", - "!**/*.test.ts", - "!src/chrome/test-utils/" - ], - "exports": { - "./chrome/*": "./src/chrome/*.ts", - "./indexed-db": "./src/indexed-db/index.ts", - "./indexed-db/*": "./src/indexed-db/*.ts" - }, - "dependencies": { - "@penumbra-labs/registry": "8.0.1", - "@penumbra-zone/bech32m": "workspace:*", - "@penumbra-zone/crypto-web": "workspace:*", - "@penumbra-zone/getters": "workspace:*", - "idb": "^8.0.0" - }, - "devDependencies": { - "@buf/penumbra-zone_penumbra.bufbuild_es": "1.9.0-20240528180215-8fe1c79485f8.1", - "@bufbuild/protobuf": "^1.10.0", - "@penumbra-zone/polyfills": "workspace:*", - "@penumbra-zone/types": "workspace:*", - "@penumbra-zone/wasm": "workspace:*" - }, - "peerDependencies": { - "@buf/penumbra-zone_penumbra.bufbuild_es": "1.9.0-20240528180215-8fe1c79485f8.1", - "@bufbuild/protobuf": "^1.10.0" - } -} diff --git a/packages/storage/src/indexed-db/index.ts b/packages/storage/src/indexed-db/index.ts deleted file mode 100644 index ea21ac78..00000000 --- a/packages/storage/src/indexed-db/index.ts +++ /dev/null @@ -1,827 +0,0 @@ -import { AppParameters } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/app/v1/app_pb'; -import { - AssetId, - EstimatedPrice, - Metadata, - Value, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; -import { - Position, - PositionId, - PositionState, - TradingPair, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/dex/v1/dex_pb'; -import { GasPrices } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/fee/v1/fee_pb'; -import { - Epoch, - Nullifier, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/sct/v1/sct_pb'; -import { FmdParameters } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/shielded_pool/v1/shielded_pool_pb'; -import { - AddressIndex, - IdentityKey, - WalletId, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb'; -import { TransactionId } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/txhash/v1/txhash_pb'; -import { StateCommitment } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/crypto/tct/v1/tct_pb'; -import { - NotesForVotingResponse, - SpendableNoteRecord, - SwapRecord, - TransactionInfo, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; -import { assetPatterns, PRICE_RELEVANCE_THRESHOLDS } from '@penumbra-zone/types/assets'; -import { IDBPDatabase, openDB, StoreNames } from 'idb'; -import { IbdUpdater, IbdUpdates } from './updater'; - -import { IdbCursorSource } from './stream'; - -import { ValidatorInfo } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/stake/v1/stake_pb'; -import { Transaction } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/transaction/v1/transaction_pb'; -import { bech32mAssetId } from '@penumbra-zone/bech32m/passet'; -import { bech32mIdentityKey, identityKeyFromBech32m } from '@penumbra-zone/bech32m/penumbravalid'; -import { bech32mWalletId } from '@penumbra-zone/bech32m/penumbrawalletid'; -import { getAssetId } from '@penumbra-zone/getters/metadata'; -import { getIdentityKeyFromValidatorInfo } from '@penumbra-zone/getters/validator-info'; -import '@penumbra-zone/polyfills/ReadableStream[Symbol.asyncIterator]'; -import { uint8ArrayToBase64 } from '@penumbra-zone/types/base64'; -import { uint8ArrayToHex } from '@penumbra-zone/types/hex'; -import { - IDB_TABLES, - IdbConstants, - IdbUpdate, - IndexedDbInterface, - PenumbraDb, -} from '@penumbra-zone/types/indexed-db'; -import type { Jsonified } from '@penumbra-zone/types/jsonified'; -import type { - ScanBlockResult, - StateCommitmentTree, -} from '@penumbra-zone/types/state-commitment-tree'; -import { sctPosition } from '@penumbra-zone/wasm/tree'; -import { - AuctionId, - DutchAuctionDescription, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/auction/v1/auction_pb'; -import { ChainRegistryClient } from '@penumbra-labs/registry'; -import { PartialMessage } from '@bufbuild/protobuf'; - -interface IndexedDbProps { - idbVersion: number; // Incremented during schema changes - chainId: string; - walletId: WalletId; - registryClient: ChainRegistryClient; -} - -export class IndexedDb implements IndexedDbInterface { - private constructor( - private readonly db: IDBPDatabase, - private readonly u: IbdUpdater, - private readonly c: IdbConstants, - private readonly chainId: string, - private readonly stakingTokenAssetId: AssetId, - ) {} - - static async initialize({ - idbVersion, - walletId, - chainId, - registryClient, - }: IndexedDbProps): Promise { - const bech32Id = bech32mWalletId(walletId); - const idbName = `viewdata/${chainId}/${bech32Id}`; - - const db = await openDB(idbName, idbVersion, { - upgrade(db: IDBPDatabase) { - // delete existing ObjectStores before re-creating them - // all existing indexed-db data will be deleted when version is increased - for (const objectStoreName of db.objectStoreNames) { - db.deleteObjectStore(objectStoreName); - } - - db.createObjectStore('FULL_SYNC_HEIGHT'); - db.createObjectStore('ASSETS', { keyPath: 'penumbraAssetId.inner' }); - db.createObjectStore('SPENDABLE_NOTES', { - keyPath: 'noteCommitment.inner', - }).createIndex('nullifier', 'nullifier.inner'); - db.createObjectStore('TRANSACTIONS', { keyPath: 'id.inner' }); - db.createObjectStore('TREE_LAST_POSITION'); - db.createObjectStore('TREE_LAST_FORGOTTEN'); - db.createObjectStore('TREE_COMMITMENTS', { keyPath: 'commitment.inner' }); - // No unique id for given tree hash and hash can be the same for different positions. Using `autoIncrement` to make the item key an incremented index. - db.createObjectStore('TREE_HASHES', { autoIncrement: true }); - db.createObjectStore('FMD_PARAMETERS'); - db.createObjectStore('APP_PARAMETERS'); - - db.createObjectStore('ADVICE_NOTES'); - db.createObjectStore('SWAPS', { - keyPath: 'swapCommitment.inner', - }).createIndex('nullifier', 'nullifier.inner'); - db.createObjectStore('GAS_PRICES'); - db.createObjectStore('POSITIONS', { keyPath: 'id.inner' }); - db.createObjectStore('EPOCHS', { autoIncrement: true }); - db.createObjectStore('VALIDATOR_INFOS'); - db.createObjectStore('PRICES', { - keyPath: ['pricedAsset.inner', 'numeraire.inner'], - }).createIndex('pricedAsset', 'pricedAsset.inner'); - db.createObjectStore('AUCTIONS'); - db.createObjectStore('AUCTION_OUTSTANDING_RESERVES'); - db.createObjectStore('REGISTRY_VERSION'); - }, - }); - const constants = { - name: idbName, - version: idbVersion, - tables: IDB_TABLES, - } satisfies IdbConstants; - - const instance = new this( - db, - new IbdUpdater(db), - constants, - chainId, - registryClient.get(chainId).stakingAssetId, - ); - await instance.saveRegistryAssets(registryClient, chainId); // Pre-load asset metadata from registry - - const existing0thEpoch = await instance.getEpochByHeight(0n); - if (!existing0thEpoch) await instance.addEpoch(0n); // Create first epoch - - // set non-zero gas prices in indexDB since the testnet has not yet enabled gas fees. - await instance.initGasPrices(); - - return instance; - } - - close(): void { - this.db.close(); - } - - constants(): IdbConstants { - return this.c; - } - - subscribe>( - table: StoreName, - ): AsyncGenerator, void> { - return this.u.subscribe(table); - } - - public async getStateCommitmentTree(): Promise { - const lastPosition = await this.db.get('TREE_LAST_POSITION', 'last_position'); - const lastForgotten = await this.db.get('TREE_LAST_FORGOTTEN', 'last_forgotten'); - const hashes = await this.db.getAll('TREE_HASHES'); - const commitments = await this.db.getAll('TREE_COMMITMENTS'); - - return { - last_position: lastPosition ?? { Position: { epoch: 0, block: 0, commitment: 0 } }, - last_forgotten: lastForgotten ?? 0n, - hashes, - commitments, - }; - } - - // All updates must be atomic in order to prevent invalid tree state - public async saveScanResult(updates: ScanBlockResult): Promise { - const txs = new IbdUpdates(); - - this.addSctUpdates(txs, updates.sctUpdates); - this.addNewNotes(txs, updates.newNotes); - await this.addNewSwaps(txs, updates.newSwaps, updates.height); - txs.add({ table: 'FULL_SYNC_HEIGHT', value: updates.height, key: 'height' }); - - await this.u.updateAll(txs); - } - - async getFullSyncHeight() { - return this.db.get('FULL_SYNC_HEIGHT', 'height'); - } - - async getSpendableNoteByNullifier( - nullifier: Nullifier, - ): Promise { - const key = uint8ArrayToBase64(nullifier.inner); - const json = await this.db.getFromIndex('SPENDABLE_NOTES', 'nullifier', key); - if (!json) return undefined; - return SpendableNoteRecord.fromJson(json); - } - - async getSpendableNoteByCommitment( - commitment: StateCommitment, - ): Promise { - const key = uint8ArrayToBase64(commitment.inner); - const json = await this.db.get('SPENDABLE_NOTES', key); - if (!json) return undefined; - return SpendableNoteRecord.fromJson(json); - } - - async saveSpendableNote(note: SpendableNoteRecord) { - await this.u.update({ - table: 'SPENDABLE_NOTES', - value: note.toJson() as Jsonified, - }); - } - - /** - * Gets metadata by asset ID. - * - * If possible, pass an `AssetId` with a populated `inner` property, as that - * is by far the fastest way to retrieve metadata. However, you can also pass - * an `AssetId` with either the `altBaseDenom` or `altBech32m` properties - * populated. In those cases, `getAssetsMetadata` will iterate over every - * metadata in the `ASSETS` table until it finds a match. - */ - async getAssetsMetadata(assetId: AssetId): Promise { - if (!assetId.inner.length && !assetId.altBaseDenom && !assetId.altBech32m) return undefined; - - if (assetId.inner.length) { - const key = uint8ArrayToBase64(assetId.inner); - const json = await this.db.get('ASSETS', key); - if (!json) return undefined; - return Metadata.fromJson(json); - } - - if (assetId.altBaseDenom || assetId.altBech32m) { - for await (const cursor of this.db.transaction('ASSETS').store) { - const metadata = Metadata.fromJson(cursor.value); - - if (metadata.base === assetId.altBaseDenom) return metadata; - - if ( - metadata.penumbraAssetId && - bech32mAssetId(metadata.penumbraAssetId) === assetId.altBech32m - ) { - return metadata; - } - } - } - - return undefined; - } - - async *iterateAssetsMetadata() { - yield* new ReadableStream( - new IdbCursorSource(this.db.transaction('ASSETS').store.openCursor(), Metadata), - ); - } - - async saveAssetsMetadata(metadata: Metadata) { - await this.u.update({ table: 'ASSETS', value: metadata.toJson() as Jsonified }); - } - - // creates a local copy of the asset list from registry (https://github.com/prax-wallet/registry) - async saveRegistryAssets(registryClient: ChainRegistryClient, chainId: string) { - const { commit } = registryClient.version(); - const lastPosition = await this.db.get('REGISTRY_VERSION', 'commit'); - - // Registry version already saved - if (lastPosition === commit) return; - - const assets = registryClient.get(chainId).getAllAssets(); - const saveLocalMetadata = assets.map(m => this.saveAssetsMetadata(m)); - await Promise.all(saveLocalMetadata); - await this.u.update({ table: 'REGISTRY_VERSION', key: 'commit', value: commit }); - } - - async *iterateSpendableNotes() { - yield* new ReadableStream( - new IdbCursorSource( - this.db.transaction('SPENDABLE_NOTES').store.openCursor(), - SpendableNoteRecord, - ), - ); - } - - async initGasPrices() { - const savedGasPrices = await this.getGasPrices(); - // These are arbitrarily set, but can take on any value. - // The gas prices set here will determine the fees to use Penumbra. - // - // Note: this is a temporary measure to enable gas prices in the web, but once - // https://github.com/penumbra-zone/penumbra/issues/4306 is merged, we can remove this. - if (!savedGasPrices) { - await this.saveGasPrices({ - verificationPrice: 1n, - executionPrice: 1n, - blockSpacePrice: 1n, - compactBlockSpacePrice: 1n, - }); - } - } - - async *iterateTransactions() { - yield* new ReadableStream( - new IdbCursorSource(this.db.transaction('TRANSACTIONS').store.openCursor(), TransactionInfo), - ); - } - - async saveTransaction( - id: TransactionId, - height: bigint, - transaction: Transaction, - ): Promise { - const tx = new TransactionInfo({ id, height, transaction }); - await this.u.update({ - table: 'TRANSACTIONS', - value: tx.toJson() as Jsonified, - }); - } - - async getTransaction(txId: TransactionId): Promise { - const key = uint8ArrayToBase64(txId.inner); - const jsonRecord = await this.db.get('TRANSACTIONS', key); - if (!jsonRecord) return undefined; - return TransactionInfo.fromJson(jsonRecord); - } - - async getFmdParams(): Promise { - const json = await this.db.get('FMD_PARAMETERS', 'params'); - if (!json) return undefined; - return FmdParameters.fromJson(json); - } - - async saveFmdParams(fmd: FmdParameters): Promise { - await this.u.update({ - table: 'FMD_PARAMETERS', - value: fmd.toJson() as Jsonified, - key: 'params', - }); - } - - async getAppParams(): Promise { - const json = await this.db.get('APP_PARAMETERS', 'params'); - if (!json) return undefined; - const appParams = AppParameters.fromJson(json); - if (!appParams.chainId) return undefined; - return appParams; - } - - async saveAppParams(app: AppParameters): Promise { - // chain id shouldn't change - if (app.chainId !== this.chainId) { - this.db.close(); - throw new Error(`Mismatched chainId: idb ${this.chainId} but new ${app.chainId}`); - } - await this.u.update({ - table: 'APP_PARAMETERS', - value: app.toJson() as Jsonified, - key: 'params', - }); - } - - async *iterateSwaps() { - yield* new ReadableStream( - new IdbCursorSource(this.db.transaction('SWAPS').store.openCursor(), SwapRecord), - ); - } - - async clear() { - for (const storeName of Object.values(this.db.objectStoreNames)) { - await this.db.clear(storeName); - } - } - - async getSwapByNullifier(nullifier: Nullifier): Promise { - const key = uint8ArrayToBase64(nullifier.inner); - const json = await this.db.getFromIndex('SWAPS', 'nullifier', key); - if (!json) return undefined; - return SwapRecord.fromJson(json); - } - - async saveSwap(swap: SwapRecord) { - await this.u.update({ table: 'SWAPS', value: swap.toJson() as Jsonified }); - } - - async getSwapByCommitment(commitment: StateCommitment): Promise { - const key = uint8ArrayToBase64(commitment.inner); - const json = await this.db.get('SWAPS', key); - if (!json) return undefined; - return SwapRecord.fromJson(json); - } - - async getGasPrices(): Promise { - const jsonGasPrices = await this.db.get('GAS_PRICES', 'gas_prices'); - if (!jsonGasPrices) return undefined; - return GasPrices.fromJson(jsonGasPrices); - } - - async saveGasPrices(value: PartialMessage): Promise { - await this.u.update({ - table: 'GAS_PRICES', - value: new GasPrices(value).toJson() as Jsonified, - key: 'gas_prices', - }); - } - - /** - * Only 'SpendableNotes' with delegation assets are eligible for voting - * This function is like a subquery in SQL: - * SELECT spendable_notes - * WHERE - * notes.asset_id IN ( SELECT asset_id FROM assets WHERE denom LIKE '_delegation\\_%' ESCAPE '\\') - * This means that we must first get a list of only delegation assets, and then use it to filter the notes - */ - async getNotesForVoting( - addressIndex: AddressIndex | undefined, - votableAtHeight: bigint, - ): Promise { - const delegationAssets = new Map(); - - for await (const assetCursor of this.db.transaction('ASSETS').store) { - const denomMetadata = Metadata.fromJson(assetCursor.value); - if ( - assetPatterns.delegationToken.matches(denomMetadata.display) && - denomMetadata.penumbraAssetId - ) { - delegationAssets.set(uint8ArrayToHex(denomMetadata.penumbraAssetId.inner), denomMetadata); - } - } - const notesForVoting: NotesForVotingResponse[] = []; - - for await (const noteCursor of this.db.transaction('SPENDABLE_NOTES').store) { - const note = SpendableNoteRecord.fromJson(noteCursor.value); - - if ( - (addressIndex && !note.addressIndex?.equals(addressIndex)) ?? - !note.note?.value?.assetId?.inner - ) { - continue; - } - - const isDelegationAssetNote = delegationAssets.has( - uint8ArrayToHex(note.note.value.assetId.inner), - ); - - // Only notes that have not been spent can be used for voting. - const noteNotSpentAtVoteHeight = - note.heightSpent === 0n || note.heightSpent > votableAtHeight; - - // Note must be created at a height lower than the height of the vote - const noteIsCreatedBeforeVote = note.heightCreated < votableAtHeight; - - if (isDelegationAssetNote && noteNotSpentAtVoteHeight && noteIsCreatedBeforeVote) { - const asset = delegationAssets.get(uint8ArrayToHex(note.note.value.assetId.inner)); - - // delegation asset denom consists of prefix 'delegation_' and validator identity key in bech32m encoding - // For example, in denom 'delegation_penumbravalid12s9lanucncnyasrsqgy6z532q7nwsw3aqzzeqqas55kkpyf6lhsqs2w0zar' - // 'penumbravalid12s9lanucncnyasrsqgy6z532q7nwsw3aqzzeqas55kkpyf6lhsqs2w0zar' is validator identity key. - const regexResult = assetPatterns.delegationToken.capture(asset?.display ?? ''); - if (!regexResult) throw new Error('expected delegation token identity key not present'); - - notesForVoting.push( - new NotesForVotingResponse({ - noteRecord: note, - identityKey: identityKeyFromBech32m(regexResult.idKey), - }), - ); - } - } - return Promise.resolve(notesForVoting); - } - - async *getOwnedPositionIds( - positionState: PositionState | undefined, - tradingPair: TradingPair | undefined, - ) { - yield* new ReadableStream({ - start: async cont => { - let cursor = await this.db.transaction('POSITIONS').store.openCursor(); - while (cursor) { - const position = Position.fromJson(cursor.value.position); - if ( - (!positionState || positionState.equals(position.state)) && - (!tradingPair || tradingPair.equals(position.phi?.pair)) - ) - cont.enqueue(PositionId.fromJson(cursor.value.id)); - cursor = await cursor.continue(); - } - cont.close(); - }, - }); - } - - async addPosition(positionId: PositionId, position: Position): Promise { - const positionRecord = { - id: positionId.toJson() as Jsonified, - position: position.toJson() as Jsonified, - }; - await this.u.update({ table: 'POSITIONS', value: positionRecord }); - } - - async updatePosition(positionId: PositionId, newState: PositionState): Promise { - const key = uint8ArrayToBase64(positionId.inner); - const positionRecord = await this.db.get('POSITIONS', key); - - if (!positionRecord) throw new Error('Position not found when trying to change its state'); - - const position = Position.fromJson(positionRecord.position); - position.state = newState; - - await this.u.update({ - table: 'POSITIONS', - value: { - id: positionId.toJson() as Jsonified, - position: position.toJson() as Jsonified, - }, - }); - } - - /** - * Adds a new epoch with the given start height. Automatically sets the epoch - * index by finding the previous epoch index, and adding 1n. - */ - async addEpoch(startHeight: bigint): Promise { - const cursor = await this.db.transaction('EPOCHS', 'readonly').store.openCursor(null, 'prev'); - const previousEpoch = cursor?.value ? Epoch.fromJson(cursor.value) : undefined; - const index = previousEpoch?.index !== undefined ? previousEpoch.index + 1n : 0n; - - // avoid saving the same epoch twice - if (previousEpoch?.startHeight === startHeight) return; - - const newEpoch = { - startHeight: startHeight.toString(), - index: index.toString(), - }; - - await this.u.update({ - table: 'EPOCHS', - value: newEpoch, - }); - } - - /** - * Get the epoch that contains the given block height. - */ - async getEpochByHeight( - /** - * The block height to query by. Will return the epoch with the largest - * start height smaller than `height` -- that is, the epoch that contains - * this height. - */ - height: bigint, - ): Promise { - let epoch: Epoch | undefined; - - /** - * Iterate over epochs and return the one with the largest start height - * smaller than `height`. - * - * Unfortunately, there doesn't appear to be a more efficient way of doing - * this. We tried using epochs' start heights as their key so that we could - * use a particular start height as a query bounds, but IndexedDB casts the - * `bigint` start height to a string, which messes up sorting (the string - * '11' is greater than the string '100', for example). For now, then, we - * have to just iterate over all epochs to find the correct starting height. - */ - for await (const cursor of this.db.transaction('EPOCHS', 'readonly').store) { - const currentEpoch = Epoch.fromJson(cursor.value); - - if (currentEpoch.startHeight <= height) epoch = currentEpoch; - else if (currentEpoch.startHeight > height) break; - } - - return epoch; - } - - /** - * Inserts the validator info into the database, or updates an existing - * validator info if one with the same identity key exists. - */ - async upsertValidatorInfo(validatorInfo: ValidatorInfo): Promise { - const identityKeyAsBech32 = bech32mIdentityKey(getIdentityKeyFromValidatorInfo(validatorInfo)); - - await this.u.update({ - table: 'VALIDATOR_INFOS', - key: identityKeyAsBech32, - value: validatorInfo.toJson() as Jsonified, - }); - } - - /** - * Iterates over all validator infos in the database. - */ - async *iterateValidatorInfos() { - yield* new ReadableStream( - new IdbCursorSource(this.db.transaction('VALIDATOR_INFOS').store.openCursor(), ValidatorInfo), - ); - } - - async getValidatorInfo(identityKey: IdentityKey): Promise { - const key = bech32mIdentityKey(identityKey); - const json = await this.db.get('VALIDATOR_INFOS', key); - if (!json) return undefined; - return ValidatorInfo.fromJson(json); - } - - async updatePrice( - /** - * The asset to save the price for in terms of the numeraire. - */ - pricedAsset: AssetId, - /** - * The numeraire is a standard against which to measure the value of the - * priced asset. - */ - numeraire: AssetId, - /** - * Multiply units of the priced asset by this value to get the value in the - * numeraire. - * - * This is a floating-point number since the price is approximate. - */ - numerairePerUnit: number, - /** - * If set, gives some idea of when the price was estimated. - */ - asOfHeight: bigint, - ) { - const estimatedPrice = new EstimatedPrice({ - pricedAsset, - numeraire, - numerairePerUnit, - asOfHeight, - }); - - await this.u.update({ - table: 'PRICES', - value: estimatedPrice.toJson() as Jsonified, - }); - } - - /** - * Uses priceRelevanceThreshold to return only actual prices - * If more than priceRelevanceThreshold blocks have passed since the price was saved, such price is not returned - * priceRelevanceThreshold depends on the type of assets, for example, for delegation tokens the relevance lasts longer - */ - async getPricesForAsset( - assetMetadata: Metadata, - latestBlockHeight: bigint, - ): Promise { - const base64AssetId = uint8ArrayToBase64(getAssetId(assetMetadata).inner); - const results = await this.db.getAllFromIndex('PRICES', 'pricedAsset', base64AssetId); - - const priceRelevanceThreshold = this.determinePriceRelevanceThresholdForAsset(assetMetadata); - const minHeight = latestBlockHeight - BigInt(priceRelevanceThreshold); - - return results - .map(price => EstimatedPrice.fromJson(price)) - .filter(price => price.asOfHeight >= minHeight); - } - - async clearSwapBasedPrices(): Promise { - const tx = this.db.transaction('PRICES', 'readwrite'); - const store = tx.objectStore('PRICES'); - - let cursor = await store.openCursor(); - while (cursor) { - const price = EstimatedPrice.fromJson(cursor.value); - if (!price.numeraire?.equals(this.stakingTokenAssetId)) { - await cursor.delete(); - } - cursor = await cursor.continue(); - } - await tx.done; - } - - private determinePriceRelevanceThresholdForAsset(assetMetadata: Metadata): number { - if (assetPatterns.delegationToken.capture(assetMetadata.display)) { - return PRICE_RELEVANCE_THRESHOLDS.delegationToken; - } - return PRICE_RELEVANCE_THRESHOLDS.default; - } - - private addSctUpdates(txs: IbdUpdates, sctUpdates: ScanBlockResult['sctUpdates']): void { - if (sctUpdates.set_position) { - txs.add({ - table: 'TREE_LAST_POSITION', - value: sctUpdates.set_position, - key: 'last_position', - }); - } - - if (sctUpdates.set_forgotten) { - txs.add({ - table: 'TREE_LAST_FORGOTTEN', - value: sctUpdates.set_forgotten, - key: 'last_forgotten', - }); - } - - for (const c of sctUpdates.store_commitments) { - txs.add({ table: 'TREE_COMMITMENTS', value: c }); - } - - for (const h of sctUpdates.store_hashes) { - txs.add({ table: 'TREE_HASHES', value: h }); - } - - // TODO: What about updates.delete_ranges? - } - - private addNewNotes(txs: IbdUpdates, notes: SpendableNoteRecord[]): void { - for (const n of notes) { - txs.add({ table: 'SPENDABLE_NOTES', value: n.toJson() as Jsonified }); - } - } - - private async addNewSwaps( - txs: IbdUpdates, - swaps: SwapRecord[], - blockHeight: bigint, - ): Promise { - if (!swaps.length) return; - - const epoch = - (await this.getEpochByHeight(blockHeight)) ?? new Epoch({ startHeight: 0n, index: 0n }); - - for (const n of swaps) { - if (!n.outputData) throw new Error('No output data in swap record'); - - // Adds position prefix to swap record. Needed to make swap claims. - n.outputData.sctPositionPrefix = sctPosition(blockHeight, epoch); - - txs.add({ table: 'SWAPS', value: n.toJson() as Jsonified }); - } - } - - // As more auction types are created, add them to T as a union type. - async upsertAuction( - auctionId: AuctionId, - value: { - auction?: T; - noteCommitment?: StateCommitment; - seqNum?: bigint; - outstandingReserves?: { input: Value; output: Value }; - }, - ): Promise { - const key = uint8ArrayToBase64(auctionId.inner); - const existingRecord = await this.db.get('AUCTIONS', key); - const auction = - (value.auction?.toJson() as Jsonified | undefined) ?? existingRecord?.auction; - const noteCommitment = - (value.noteCommitment?.toJson() as Jsonified | undefined) ?? - existingRecord?.noteCommitment; - const seqNum = value.seqNum ?? existingRecord?.seqNum; - - await this.u.update({ - table: 'AUCTIONS', - key, - value: { - auction, - noteCommitment, - seqNum, - }, - }); - } - - async getAuction(auctionId: AuctionId): Promise<{ - // Add more auction union types as they are created - auction?: DutchAuctionDescription; - noteCommitment?: StateCommitment; - seqNum?: bigint; - }> { - const result = await this.db.get('AUCTIONS', uint8ArrayToBase64(auctionId.inner)); - - return { - auction: result?.auction ? DutchAuctionDescription.fromJson(result.auction) : undefined, - noteCommitment: result?.noteCommitment - ? StateCommitment.fromJson(result.noteCommitment) - : undefined, - seqNum: result?.seqNum, - }; - } - - async addAuctionOutstandingReserves( - auctionId: AuctionId, - value: { input: Value; output: Value }, - ): Promise { - await this.db.add( - 'AUCTION_OUTSTANDING_RESERVES', - { - input: value.input.toJson() as Jsonified, - output: value.output.toJson() as Jsonified, - }, - uint8ArrayToBase64(auctionId.inner), - ); - } - - async deleteAuctionOutstandingReserves(auctionId: AuctionId): Promise { - await this.db.delete('AUCTION_OUTSTANDING_RESERVES', uint8ArrayToBase64(auctionId.inner)); - } - - async getAuctionOutstandingReserves( - auctionId: AuctionId, - ): Promise<{ input: Value; output: Value } | undefined> { - const result = await this.db.get( - 'AUCTION_OUTSTANDING_RESERVES', - uint8ArrayToBase64(auctionId.inner), - ); - - if (!result) return undefined; - - return { - input: Value.fromJson(result.input), - output: Value.fromJson(result.output), - }; - } -} diff --git a/packages/storage/src/indexed-db/indexed-db.test-data.ts b/packages/storage/src/indexed-db/indexed-db.test-data.ts deleted file mode 100644 index 3fe48935..00000000 --- a/packages/storage/src/indexed-db/indexed-db.test-data.ts +++ /dev/null @@ -1,718 +0,0 @@ -import { Metadata } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; -import { - SpendableNoteRecord, - SwapRecord, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; -import { - Position, - PositionId, - TradingPair, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/dex/v1/dex_pb'; -import { Epoch } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/sct/v1/sct_pb'; -import { TransactionId } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/txhash/v1/txhash_pb'; -import { Transaction } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/transaction/v1/transaction_pb'; -import type { ScanBlockResult } from '@penumbra-zone/types/state-commitment-tree'; - -export const emptyScanResult: ScanBlockResult = { - height: 1092n, - newNotes: [], - newSwaps: [], - sctUpdates: { - delete_ranges: [], - store_commitments: [], - store_hashes: [], - }, -}; - -export const scanResultWithSctUpdates: ScanBlockResult = { - height: 1092n, - newNotes: [], - newSwaps: [], - sctUpdates: { - delete_ranges: [], - store_commitments: [ - { - commitment: { inner: 'qs3wdffdg34sfv' }, - position: { block: 2, commitment: 11, epoch: 1 }, - }, - ], - store_hashes: [ - { - essential: false, - hash: new Uint8Array([33, 12, 33, 22, 98]), - height: 1090, - position: { - block: 3, - commitment: 12, - epoch: 1, - }, - }, - ], - set_forgotten: 12n, - set_position: { Position: { block: 2, commitment: 10, epoch: 1 } }, - }, -}; - -export const scanResultWithNewSwaps: ScanBlockResult = { - height: 1092n, - newNotes: [], - newSwaps: [ - SwapRecord.fromJson({ - swapCommitment: { inner: 'A6VBVkrk+s18q+Sjhl8uEGfS3i0dwF1FrkNm8Db6VAA=' }, - swap: { - tradingPair: { - asset1: { inner: 'HW2Eq3UZVSBttoUwUi/MUtE7rr2UU7/UH500byp7OAc=' }, - asset2: { inner: 'KeqcLzNx9qSH5+lcJHBB9KNW+YPrBk5dKzvPMiypahA=' }, - }, - delta1I: {}, - delta2I: { lo: '1000000' }, - claimFee: { amount: {} }, - claimAddress: { - inner: - '2VQ9nQKqga8RylgOq+wAY3/Hmxg96mGnI+Te/BRnXWpr5bSxpLShbpOmzO4pPULf+tGjaBum6InyEpipJ+8wk+HufrvSBa43H9o2ir5WPbk=', - }, - rseed: 'RPuhZ9q2F3XHbTcDPRTHnJjJaMxv8hes4TzJuMbsA/k=', - }, - position: '2383742304257', - nullifier: { inner: 'dE7LbhBDgDXHiRvreFyCllcKOOQeuIVsbn2aw8uKhww=' }, - outputData: { - delta1: {}, - delta2: { lo: '1000000' }, - lambda1: { lo: '2665239' }, - lambda2: {}, - unfilled1: {}, - unfilled2: {}, - height: '356591', - tradingPair: { - asset1: { inner: 'HW2Eq3UZVSBttoUwUi/MUtE7rr2UU7/UH500byp7OAc=' }, - asset2: { inner: 'KeqcLzNx9qSH5+lcJHBB9KNW+YPrBk5dKzvPMiypahA=' }, - }, - epochStartingHeight: '356050', - }, - source: { - transaction: { - id: '9e1OaxysQAzHUUKsroXMNRCzlPxd6hBWLrqURgNBrmE=', - }, - }, - }), - ], - sctUpdates: { - delete_ranges: [], - store_commitments: [ - { - commitment: { inner: 'qs3wdffdg34sfv' }, - position: { block: 2, commitment: 11, epoch: 1 }, - }, - ], - store_hashes: [ - { - essential: false, - hash: new Uint8Array([33, 12, 33, 22, 98]), - height: 1090, - position: { - block: 3, - commitment: 12, - epoch: 1, - }, - }, - ], - set_forgotten: 12n, - set_position: { Position: { block: 2, commitment: 10, epoch: 1 } }, - }, -}; - -export const metadataA = Metadata.fromJson({ - denomUnits: [{ denom: 'mars', exponent: 6 }, { denom: 'mmars', exponent: 3 }, { denom: 'umars' }], - base: 'umars', - display: 'mars', - penumbraAssetId: { inner: 'cGFzc2V0MTgyODQ3MjgxODQzMTg3NDg=' }, -}); - -export const metadataB = Metadata.fromJson({ - denomUnits: [ - { denom: 'jupiter', exponent: 6 }, - { denom: 'mjupiter', exponent: 3 }, - { denom: 'ujupiter' }, - ], - base: 'ujupiter', - display: 'jupiter', - penumbraAssetId: { inner: 'cGFzc2V0OTQ5MjgyODQ1OTg0NTc2' }, -}); - -export const metadataC = Metadata.fromJson({ - denom_units: [ - { - aliases: [], - denom: 'pluto', - exponent: 6, - }, - { - aliases: [], - denom: 'mpluto', - exponent: 3, - }, - { - aliases: [], - denom: 'upluto', - exponent: 0, - }, - ], - description: '', - base: 'upluto', - display: 'pluto', - name: '', - symbol: '', - penumbra_asset_id: { - inner: 'cGFzc2V0MTIzMjEyNDEyMzEyNDIy', - alt_bech32m: '', - alt_base_denom: '', - }, -}); - -export const delegationMetadataA = Metadata.fromJson({ - denomUnits: [ - { - denom: 'delegation_penumbravalid12s9lanucncnyasrsqgy6z532q7nwsw3aqzzeqas55kkpyf6lhsqs2w0zar', - exponent: 6, - }, - { - denom: 'mdelegation_penumbravalid12s9lanucncnyasrsqgy6z532q7nwsw3aqzzeqas55kkpyf6lhsqs2w0zar', - exponent: 3, - }, - { - denom: 'udelegation_penumbravalid12s9lanucncnyasrsqgy6z532q7nwsw3aqzzeqas55kkpyf6lhsqs2w0zar', - }, - ], - base: 'udelegation_penumbravalid12s9lanucncnyasrsqgy6z532q7nwsw3aqzzeqas55kkpyf6lhsqs2w0zar', - display: 'delegation_penumbravalid12s9lanucncnyasrsqgy6z532q7nwsw3aqzzeqas55kkpyf6lhsqs2w0zar', - penumbraAssetId: { inner: '9gOwzeyGwav8YydzDGlEZyZkN8ITX2IerjVy0YjAIw8=' }, -}); - -export const delegationMetadataB = Metadata.fromJson({ - denomUnits: [ - { - denom: 'delegation_penumbravalid15ex9m38fl5gv48vwszyhgsvp9q83wc7nl4z274u6atyfwtlaeqgqpjwkkm', - exponent: 6, - }, - { - denom: 'mdelegation_penumbravalid15ex9m38fl5gv48vwszyhgsvp9q83wc7nl4z274u6atyfwtlaeqgqpjwkkm', - exponent: 3, - }, - { - denom: 'udelegation_penumbravalid15ex9m38fl5gv48vwszyhgsvp9q83wc7nl4z274u6atyfwtlaeqgqpjwkkm', - }, - ], - base: 'udelegation_penumbravalid15ex9m38fl5gv48vwszyhgsvp9q83wc7nl4z274u6atyfwtlaeqgqpjwkkm', - display: 'delegation_penumbravalid15ex9m38fl5gv48vwszyhgsvp9q83wc7nl4z274u6atyfwtlaeqgqpjwkkm', - penumbraAssetId: { inner: 'brSeAgTVPCTJsjLKNFWhRSnJOJQgumMRksEe34sJfgc=' }, -}); - -export const newNote = SpendableNoteRecord.fromJson({ - noteCommitment: { - inner: 'pXS1k2kvlph+vuk9uhqeoP1mZRc+f526a06/bg3EBwQ=', - }, - note: { - value: { - amount: { - lo: '12000000', - }, - assetId: { - inner: 'KeqcLzNx9qSH5+lcJHBB9KNW+YPrBk5dKzvPMiypahA=', - }, - }, - rseed: 'h04XyitXpY1Q77M+vSzPauf4ZPx9NNRBAuUcVqP6pWo=', - address: { - inner: - '874bHlYDfy3mT57v2bXQWm3SJ7g8LI3cZFKob8J8CfrP2aqVGo6ESrpGScI4t/B2/KgkjhzmAasx8GM1ejNz0J153vD8MBVM9FUZFACzSCg=', - }, - }, - addressIndex: { - account: 12, - randomizer: 'AAAAAAAAAAAAAAAA', - }, - nullifier: { - inner: 'fv/wPZDA5L96Woc+Ry2s7u9IrwNxTFjSDYInZj3lRA8=', - }, - heightCreated: '7197', - position: '42986962944', - source: { - transaction: { - id: '3CBS08dM9eLHH45Z9loZciZ9RaG9x1fc26Qnv0lQlto=', - }, - }, -}); - -export const noteWithDelegationAssetA = SpendableNoteRecord.fromJson({ - noteCommitment: { inner: 'n86D13I1rRUDoLCkX7LKl/AG8/F+2MV76p4XgPD++xA=' }, - note: { - value: { - amount: { lo: '2000000' }, - assetId: { inner: '9gOwzeyGwav8YydzDGlEZyZkN8ITX2IerjVy0YjAIw8=' }, - }, - rseed: 'iA0WPnLr254gAxIacHFjFgKd7khUJzTv6LOkLUhYl4g=', - address: { - inner: - '2VQ9nQKqga8RylgOq+wAY3/Hmxg96mGnI+Te/BRnXWpr5bSxpLShbpOmzO4pPULf+tGjaBum6InyEpipJ+8wk+HufrvSBa43H9o2ir5WPbk=', - }, - }, - addressIndex: {}, - nullifier: { inner: 'HuLT6I5OLUScFLaPPFrZe6JmJe3ul3InQ4LvuB/5fgE=' }, - heightCreated: '43', - position: '2818048', - source: { transaction: { id: 'i++POrLfH1e5t+ys2ytLAJKi41HLt1s39Rj/bCFrMTI=' } }, -}); - -export const noteWithDelegationAssetB = SpendableNoteRecord.fromJson({ - noteCommitment: { inner: 'O5vXQyhaImbVKHuhpZqT5QYVA6HDlY4P+Hz/z3Xc5gU=' }, - note: { - value: { - amount: { lo: '1000000' }, - assetId: { inner: 'brSeAgTVPCTJsjLKNFWhRSnJOJQgumMRksEe34sJfgc=' }, - }, - rseed: 'GpSXUcRiiu4DlKm4ICInrGQ14+qB3ETzCryE+j3iEas=', - address: { - inner: - '2VQ9nQKqga8RylgOq+wAY3/Hmxg96mGnI+Te/BRnXWpr5bSxpLShbpOmzO4pPULf+tGjaBum6InyEpipJ+8wk+HufrvSBa43H9o2ir5WPbk=', - }, - }, - addressIndex: {}, - nullifier: { inner: 'vFKjF23omWRoBCRP2lvVqe2su7eUntW4S5glizS3pAY=' }, - heightCreated: '53', - position: '3473408', - source: { transaction: { id: 'OVtt3KUg5v+yF/O/2pwE1/740EhFGZ3mK74LUvRfcL0=' } }, -}); - -export const noteWithGmAsset = SpendableNoteRecord.fromJson({ - noteCommitment: { inner: 'HPA48ggmSUsVVm5u871Y2qpURUZ60ic7/eL32ej0gQo=' }, - note: { - value: { - amount: { lo: '10000000' }, - assetId: { inner: 'HW2Eq3UZVSBttoUwUi/MUtE7rr2UU7/UH500byp7OAc=' }, - }, - rseed: 'J7YlPuY8pb3aa1qHKrOHs0Eb5ahgFdN8U/qwU8G6OoM=', - address: { - inner: - '2VQ9nQKqga8RylgOq+wAY3/Hmxg96mGnI+Te/BRnXWpr5bSxpLShbpOmzO4pPULf+tGjaBum6InyEpipJ+8wk+HufrvSBa43H9o2ir5WPbk=', - }, - }, - addressIndex: {}, - nullifier: { inner: 'PbSX9/S83gUsT4/l4Fw6W2r2JPzeuiYpEZM2que+RxE=' }, - heightCreated: '17', - position: '1114112', - source: { transaction: { id: 'NNKqIUJRgSI1dS1VbWLNZeQpmQUG6pInn3sFqPNrFDA=' } }, -}); - -export const transactionId = TransactionId.fromJson({ - inner: '9MI8IG5D3MQj3s1j0MXTwCQtAaVbwTlPkW8Qdz1EVIo=', -}); - -export const transaction = Transaction.fromJson({ - body: { - actions: [ - { - spend: { - body: { - balanceCommitment: { - inner: 'mLSHGBzim3wSsFOn431tR9fsD+RcPXK1hn7FtxYOlws=', - }, - nullifier: { - inner: 'knpvZH3soGxnNVQZcvlA+VMuvCZWVCgknts1mowDSgg=', - }, - rk: { - inner: 'cmAa4EqbtHC5lhoVU6PGJfJl06QpBga4eO3cuF/8MAU=', - }, - }, - authSig: { - inner: - 'GJo9VlwKrGKwwbRW6rTfZk6pIWYL0UEct3NTCFx7YhEnzeNg1l5zx9hfnxJysEBSU63OmG3NsLp+GABIsboTAA==', - }, - proof: { - inner: - 'OvLGAV9gAH3n5r/MV+nRkLMATFHpM6zubwdP6J1aJbBj7Ir1wteZg7OiXE3F4HkBg2dMaVLUUkTnLe1zyu9fIvLR5eMKLgCNI6MUfHZm0ax14fmMInQxv5JCijZe4WIBGpSxDFyGBAFaMoYOtbspGyeby7skgy9rAX7OMGrLGhrFp7YlevcgByRxbyEBqVABlptYxE/RLVP64ovO8pkSx7bJiK3NSfdC7RsxqqzaS+yGYK7biB24tGn1BG8z1EUA', - }, - }, - }, - { - spend: { - body: { - balanceCommitment: { - inner: 'LnUs6kKZ+9MO+J+bHiDFm+WRnHEWgIjkw7ieivpQ7xE=', - }, - nullifier: { inner: 'iKtEKV32USvsFJINbWs8WlpGrf4ISt+D61LkVzAyPwY=' }, - rk: { - inner: 'oIpHfSwEialuU436KIw9tXR3wWpgk0NHIcc17dRnYQM=', - }, - }, - authSig: { - inner: - '5vBg2TjWbJuG6XYG+D8vky7wrXv+2spahENVpQRFWQmVwhHEhdbKSa94LswbMsiuVC0UipX11ezgCWXpuDq6AA==', - }, - proof: { - inner: - 'bJixhv1Lr5D0uMeieXID9ESaFEKxv3pDb8Hppovl0kWc1fWtnESWhOXBmh7l+8EAehSUrZiEcNLJahtXP05xPy4qdBVfPPOYsFMiTTXyCsdgg/I+/21rBP99LBJAJU8A+WgWvu6TL84YRepUPOC56KsOnaP6hSEajt8liL3lTHeYYerbzGfzsESwjyPKuJEB+UJjTH419Mq5fXd5swY+3sqXB4/hDq/wVk9SuPGkDXvNUUZH6T1WqXSOXeaJOiGB', - }, - }, - }, - { - spend: { - body: { - balanceCommitment: { - inner: 'yI14CUmNVu+N5+0/rgQdAMU5RBikcCQQzWaWHStfSAs=', - }, - nullifier: { inner: 'B3XzzNvAuT3hMVqTfAAN6m9UlODZ9fldv3OyA55ABAs=' }, - rk: { inner: 'vhkNUmggYaQRaIb1f0tT1RWapAcvF+i4NmuJPNi/iwo=' }, - }, - authSig: { - inner: - 'MhWvmocns1opnTDOuPT6NL6dSL7aeZEZV6I2A+ayJwqeRVK3kaFtOqo4vxnummdw/ydsPiAvVQnCHtnUXCmpAA==', - }, - proof: { - inner: - '20w8HjUS/fthqz7vYcwvKyAbmONpCAm5QMYyMF+39EcHwGIanxNesVjoxKg/WTQBj/vO2fae6cR8bPZM+FzGzClDJx0Zn6zn6rKSPV6DAxxoK/ZvP/l7oNO9zVz56RgBEmfpuUwYEdc3jzQ2ND887zw/2lxTXYc1n+NWxBrm8SA9p5gENkfTEDkKK4iEF/EAMXz5kWx3jQ5OsxPj5XMFJ279P3LrR9a1jFx1ChMv9lROcpqGsLvuyQkXWsEvMFUB', - }, - }, - }, - { - spend: { - body: { - balanceCommitment: { - inner: 'drR8MmEnfMs0CkY9QRaxiAGSZmM9lpU4+metaRt3UxA=', - }, - nullifier: { - inner: 'x40Dz0PFP84vJ3cswSdiKFJJCWuLtYxapRXSey/+wgQ=', - }, - rk: { - inner: 'pujbFovCIVxlF5hCJ/+PlvBeCG0jHelV7im2Li+uTQI=', - }, - }, - authSig: { - inner: - 'BrZoeKQXBpQD+E6EJ2OxzvEhW5RVZYGE5euvDeRNKwerXNmEuGpxFD8XsFqaA98kooJnHc35uP+ARYB9YOnDAw==', - }, - proof: { - inner: - 'PtvZI64TyNA0j2aHy31mz7sTOPkXVvGJJHImPfecYTag4K8ahmeCGjXx/5wTjWaBsiAnuVJD63mFlKr8MhmK9rp7llprkM8ehRGA0S9tB/IHJ0da46YDzH8XGyG4UHcBuoK03fuq+4V84TAOzAs5+Ca/NSnV1Z0C7HTqd1M86tdo2mC1Gs5Ys/EM+ItleHoACY+cqDrWZVbiuONHAq7HE9/gKx9kiTCDCFDK05kawUBK1scKQG5jiybFebVkik2A', - }, - }, - }, - { - output: { - body: { - notePayload: { - noteCommitment: { - inner: '3WvedSSpq4kX951dVMMMeKR2OepBTPqGpF8QOO//fgw=', - }, - ephemeralKey: '+kGNLsbePwgL6LuINJqnV4l/y2AwbBDI224/1nq5xgk=', - encryptedNote: { - inner: - 'R/Gf/zakltAbRg0shbrd85bP4phrFZ4Msuw+gUjD3qGgsChIVIrLpSSOTtMlJpKCGhAmxDn3oCvdk5ASU3HkPVLaL90RniZ2ZJ1nGgij0pA2XbVcdotRdRfw6ZHxB0SAB2EWSv9oV/K7vNAtR+SpNAMG6bbQsLjqVJCbZMmSVhhnojoQV6/KeYEfa/R8T7LUBwEBR4MY3qO4SxLfPIQQulxo6qoYm462wUF1njA1pIE=', - }, - }, - balanceCommitment: { - inner: 'mBZDCVkBXzFEdebcHD1QPqn5xuAIpoF+SMa4IRxvZww=', - }, - wrappedMemoKey: 'tfvqFYlHGJ7x0R1ch7sThXGPGLL/jYSK9My1ngipfdLtIjbOQRZoO/oty0jGXYjZ', - ovkWrappedKey: 'v40iQUFriHfiy8sSjfuQlc7P7fU6VfknPgMEGiC1cJxRHRRCBknbxlCG+99GKZAG', - }, - proof: { - inner: - '7mya0y4ZcnHrtHA9xuMmtf+6V1jfpA8GNrtQoxPaDnAuMN9Qe2h6K9MtoDTOpC0AVN5DZVt7zITsVZLPMZ70sQ+XlS2fivUNIk6/20Twkev4xc809nebdr3AqSoNoIIAor1ZbGQNIdqaNItvp3DQ4S0FguaGcS1TBwebiJTeUwfL4TH9D6QL6YvkGp1JSg0Bv0q7psIptEdI5WtSZZjR8kY11QXlPr0bwDiyc15CFIhlHGAj3RqhlH0fsNmEGZUB', - }, - }, - }, - { - output: { - body: { - notePayload: { - noteCommitment: { - inner: '5LGElYM7UCex9oVWgBfgfo1iQkTSm5Z1DZAPFUW+NQo=', - }, - ephemeralKey: '0g8xqLhvfT+h/dfX90f7xF7Jyyv4tCXzLCBKXhUyKRI=', - encryptedNote: { - inner: - 'p4051rDIv7tVLIqGk7cagA6O+Km2Byo0yscU1DFCgJkkdQnkEFabmJS601rLQ7tsyh/+FPEnb0dSIi00S1rmLCya2tRlRS4ru6WtBjchw6vn9To/S5qbGVMD6l3siIxJo9RVrAaNFE35ForqpZpCXqPctiHKC30dSMHG0+O9MPKzRqlwCJKDOezUR1rrPZV+ukvB1KU6QUpHnZtQFLQnMW7cZmOzp5SraYksZqhoTy4=', - }, - }, - balanceCommitment: { - inner: 'jttI7PeS8mE1wp+COaVNuu7HOBFkrTCWThyZLrobvww=', - }, - wrappedMemoKey: 'nyv6CdQkZqOMTGP0mBAv3ec01+g4v4HCmUKuup7cG+Dz6M5Jb1welFOmicaImiM+', - ovkWrappedKey: 'i9FMZLMduuTBQQ2t3QXSXAgf4aWHA1eTJAsGEKcoQPDXReWdVNC1/V2OXhiXLxcp', - }, - proof: { - inner: - 'fW2/mxyDh+X5bxGeOzSp/OoGyqDkd2///6wzQZaIEZRyHSpG1+/8ZGZ8EI0YU7KAPjzCqPd7Nkb+nTHp/KWFV3Uu4IxNs4mbAKIyeYII2NybTphQdC3MzRZg+oTkH2IABdqP4X2hdBZ28zntxXSdicA3lq+fQfD6KxfrJpA80d9BLTqJsrFI0dRwCSF6LLOAgXpvlsM16IYtb0ykQ9q5cBmvsXdvPliAIAq5Pi40j05XX/tb+msZ6RLhdXnqkgMA', - }, - }, - }, - { - output: { - body: { - notePayload: { - noteCommitment: { - inner: 'GuHzSMZYeSJvb07AgErw50TH13xxE5SMD7fPmH8N+gA=', - }, - ephemeralKey: 'ZAQfdUWQRWFSaCGVeThQtiWQWE2BXPqr+45L+3Rqlw0=', - encryptedNote: { - inner: - '96BGfrpJL3ir7pO4GW6YKZjlqR/qf5Fa+qxFpqH+rRJg7JDXL525HpZy8VoQWLsXaTsnGVERwyPoGZG291LAY5rUZDGMIs8v5Pyfn4mLnTPzeH6abr/cOvVTmJ4h4642z7KhdGyo5IbXdGyCkbgWydTePv0KmD9M8s4UW/F15rpds+gQIGz2AE4+12+4jPr++oangCNLf4pEmwiKjBlx0IihrNxk1/6kTRuAfL4VI8g=', - }, - }, - balanceCommitment: { - inner: 'IvBWZSjXNrtEFuLlbawHFN61dglil7l55i+GwG8PbgY=', - }, - wrappedMemoKey: 'U3llcLx+1omlkP+/C1QQAMDoyuRaAcBwDjIQjtDQL6F1q4JF9PRTvrYikhdtOJZJ', - ovkWrappedKey: 'CFRgB/mTvu+MpaoLzJ7iEqs3ndKsMNA9eGE3rPJLcIWRbCWpv7YMx9szPzTmZAQ1', - }, - proof: { - inner: - 'CzpdU4xERq3c+XtOPYvEZkvvQZOBK7uLoBoBqJGeDnzDonmaOXh4KR93f3VzMniA3KEeT46K+KxDTQ54pKQU8gk7OeYtQzbTLEiMTIIcmNLnZ2Ec2//zLOi0d7M/TXgBi3H4g6rLqbRcU7W7cxHyYvbNOBmM6Oi+SMMuLAKpRzBT8ygmIvMDnwxa1o5zeG0B1TWh2HLQFzGVUgT4517B+6nOj4/gJy7lofIiOvr8pAZsz2InVDNoxwf13DttoxcA', - }, - }, - }, - { - output: { - body: { - notePayload: { - noteCommitment: { - inner: 'VZvk7tv1zn/hSti2nLpL6x7gAHzJUbdkIy5LDR70kBE=', - }, - ephemeralKey: 'HnWYIW5yBrSjxzgGf3fNLY3C3RkwrX6XuW7/RO8qqhE=', - encryptedNote: { - inner: - 'N4VY6GxAOfDo/CtV3TggMTnS9qdp8ixYkJktrrw3YtmsQusyVd8BQPggnbpC3XyhOabe0phE5+BFr07EwCDH71bGO/7FglAPV3zCA2G1rKLGge5GeRz7mlorDvueAx/T9286Vx8DN2dRBfgLEGw5YmLjsUISVH9hAPk4KzjBgAQqBeNxATv7PROUhjnp8fO8DrEe9fL7lWnjhtTd7Id1s23aIshpTIEOQG21CgOQxdY=', - }, - }, - balanceCommitment: { - inner: 'dOxUDjSlcIAL+W5YtUKpodErvfz7S53YlR6uke1iWwk=', - }, - wrappedMemoKey: 'DJUfS5jfFyoBb6E4H/ATFpG5CjcPJPC9RmuzKrDIzVG+it+/Y7KBpN2ABGrJL5WC', - ovkWrappedKey: 'l6YPHV8bxB1oPbAcBLtDAc1Aq20kD5U4+oZRpYj59bviXUzfCIvnITfuanhJtrOG', - }, - proof: { - inner: - 'xxwfTg9Reb/WGu4wmUkWUarpLeU2vRXAE8Btc6QHExK398wytGzxlsyNY2S7qXoBJHFVcRv6Tx3oC6dZ5fAoGpzJI7uEN70i/eJOSZbHLTA6XY0VOrkA2P3zIbgLZu8A6cyW3hl7uMBphf6bqLyxsGFUZu7noSHUb4AnW5Wfod2giwsIm9/kzjpBDf3iQ9kASJBJTffLAvszNUVrR3mrJC0wEdqPTtoz84Iyy7VUzkcAJmi/P+AIJJIRtdnp7IqB', - }, - }, - }, - { - output: { - body: { - notePayload: { - noteCommitment: { - inner: 'v00WG4eq2UfFceMbEePaWakxAEuyXkNpiR/RhUIP3gw=', - }, - ephemeralKey: 'IN7b2urD0lenpjQHDqfcc3d8XXCgsKpASqyJDoPZzws=', - encryptedNote: { - inner: - 'me0HxTd9Ca5SRXOPTCC9zbJ4fi75eYgjNIDA/7Uf6jcntYij6lMg5OoUBr1MKNYG44mJWxUBNmaG0iZ1k/P+KNVc9aCqCAdZJBT/72Cw9KCOa4Z3dYhmwW9JVwFEVN4taeNi81xi+nLd/0BzrKAMJCCLkH5z7tUztCXvZGcK26AGsqUa5M3JadsmwtAmAa0mhtP8Nvj1GCxtfnyxFiOTw6iF4xnRxcT97LkrF43jPPM=', - }, - }, - balanceCommitment: { - inner: 'xhEvO8D8VosI/rXowFT18XKphHx2KE/flhsueexl4hE=', - }, - wrappedMemoKey: 'aqV0AB1qGm+H7MANkV7GOf+gy9yol9Zeq1KJCiwv2P+JxrCneSMnNYod3eAToWGn', - ovkWrappedKey: '86CR823j7a/R8PTy9KmlXBPoRVDtqmjuuSWgSRa9Lv5lxHuS0N5aSDQ7udlhgx9M', - }, - proof: { - inner: - 'l8neFhNDPbJ1AqemLyIdMbwAtUBrs60ea36j9upZKo7gtTsryYDYhCimNLlt2SgAQDrAAW+t6Do4DDv14x9GLFifBiw2bnbbtf97JUDGKZJ8T8H5RQdpfOCEIiC5lAUB82DDjN8LeAjkfUHybqBytvsNCRuULznIbKTT8LJm8OJXsbH60/F/lkuI38KyI78AWjZks2sdX141IT51czpMGNs1NepX/d739+dcdsmoQSMU8OSrVNns4eZNvknS+3SA', - }, - }, - }, - { - output: { - body: { - notePayload: { - noteCommitment: { - inner: 'WinDFqc8CqAxkr/NOQHNtSO+6Ro7u/lGD6slOYR1lg0=', - }, - ephemeralKey: 'pBtwFCcA/FC22GzngcQrvWk/+2++b+2uo3QahfjkMgQ=', - encryptedNote: { - inner: - '6Gqpf/x3cd1g1hQ1U2b4nNok5SpYuEwwWg5nUtDHYS9CZz35+dg9XbqDUtFP74mVjYbxVB4+qXr2F2HiT8WrX0artkKS4/iWNxe4KlxnG1g/cLcTreZ1S36OH7rVXzcMQWFEgYH8HCKkTvIuMNnQr6E+uTUaX1qIj0gpKCMMfqzFtFAPQVKlHTNkHB+2gY9c6MOa3r/HfGehDgnk5t7S+hYha/hYmcV193GYSIIalE0=', - }, - }, - balanceCommitment: { - inner: 'wsJeHMoAbyf/NTCUwX0kOLUxEOQF303v2WlFOkzkGAw=', - }, - wrappedMemoKey: 'gMvMDEebtNu2MgbaSESx0X5NoIHgBjnd7EFVQF6wPorDV3Zxn8QrXHIUqfhQX7tB', - ovkWrappedKey: '9z9jH7JMS+/0uOQ+wGbQnir+YUWZHXGOGtMG6O7GZYz7SCMCyMweiwk/Tu0ATnZv', - }, - proof: { - inner: - 'Q2Oberg+JGR2QrG+3lxCkcVko7XDlbQBPWe1DeytG7rdco7NVPZw7mGMDmqhfOGA+QMeo4xXV+vFmpP8e2qS5E5kJW3MVMs/QFhs8nptPNqm14aF27U9vsPVJpeio4MBlDVi+TAsjVk2zQ/lFw33l5Dla4fne1cMFrYPaG6WrwH5YQYZuaJzz5bUX+FGnlQBtfZl3YlGDYZHL0NijuM9jujzpjAh/p6ROIKNZahMXSxsSHp7iQsO0cwQFw4y87gA', - }, - }, - }, - { - output: { - body: { - notePayload: { - noteCommitment: { - inner: 'mycDZGRmawM/gn5mcSLdekUcwayLwCBaPNdvVhL41Qk=', - }, - ephemeralKey: 'MAraIMUu/UiY5oQeo6Jh6Tm3sS3a5uqqGXiGDKmc/AM=', - encryptedNote: { - inner: - '3pJ7goLAX/kHPRPqzhPJ3fYMrS0PvKxESdfcvxWB7b8MPByC34G/HkMDqjx6/DO599ubAJM5LsFpGrnhGPtE0hg+GNu8W+d54oRd3qJ2Uh5LtvXfGK0zM0qBXSXKIkXBEOGODZJ6f2L+m9qX6roK1J59VodCIa1wEBVuPbXogcq/CYn3L0A3ot7Yj9MWYQnZ0QcW1s0g/NkaNonHnhz6UWsK1U3zaPRih10p/GoapXg=', - }, - }, - balanceCommitment: { - inner: 'PKW0VKrMuencxQGVVUq5Rjp0OQZvrpXHlanBwyVC1gU=', - }, - wrappedMemoKey: 'gbYRvDj2DmvyqB0MrVqAydcOmCcFbmOF4wrFNaZtx/stz7n0CjEuUdH4LJV99LZ+', - ovkWrappedKey: 'A/2JWy9UhF3xx7wXfhf8735w7HlzT5KBWT6V4yKJNw8xirQ7luzpGs+lyQkw7+Ke', - }, - proof: { - inner: - 'm+yVsZSP2w0SvlakWAyypRI8zZFZ000XwA3lf6UF8xDP/b7wZyHiyZof8dMy2TwBwodfNx2D9vxBax73RVBovUjceqGhYU5MqxFkjIlREH1U0rKgMqRVayzzStnzbdUA4Lf7ByeQAjm7DlyK03tfedaiXV4jkPyEoyI9m78A74O0qPzCdUExFoDUx3/XC2+Bog1NvDN5NFmP/XBOl3ZMJDH1rcBkskHipdGiSE92V+c9Mtdea3vWX7C+ebD5sSEA', - }, - }, - }, - { - output: { - body: { - notePayload: { - noteCommitment: { - inner: '/mmvwP2dPRNkX4IJiq+7ZfXsubsoCY9gp2N/9ugHqRI=', - }, - ephemeralKey: 'xhgPCiRjN6snO5qlsdRpA7oCUVRWxpE8n7/Z2uU60gw=', - encryptedNote: { - inner: - 'ayaHlEzPbu8QJwtLea/WxhucXytntgXhLFfrIf8YrHkuYewBDEIuMjyQJ1q6zHjXVt46QF0bcXDi5rfnFepdVyLiS0z3ZQAO73SGuPOJegiwgz0iPgngMpqE39S2m5VH8saFzRzywkTQpWsR//naWB5oqfS3/AVpNUwzm9Mnvme4LImyR3vWT4dbvsYVsmQgcXK/mYjb5KRtTyxzqe3PnLFTIRbGCKeRFEZ7My0QgG8=', - }, - }, - balanceCommitment: { - inner: 'aqUqgKx/4+12S6yk6hUCurgMTxiJ286AcfjVGPiORAM=', - }, - wrappedMemoKey: 'hu4iFAe9hP7zBAOw5xaBWv2TSaLzhQ/1oJhkSp5Ug2M2pr/EZhJGSLOvix501AcM', - ovkWrappedKey: 'uZYJSJUbd9R6LB5ii508XyxLJtIvWjZ6co88VTKEL/33lkMvhsIxTZyp+RZKS4cF', - }, - proof: { - inner: - 'TTjJyg3Wo8a5IYfhwCynxLuY25413eUpl17F6ZBw6tbBKzCBcPCESpcwhEZSmNGAjFM8v5H7Wh6qmDa/gG3AIJANB0ZDShaMO/tlaBBRc+vTmDU9xMvsnfZtAlMa2YoBuwmjkjFcu2bz0c08jjp6Tg3K9RkjPWA685UDZVnHjDzVet+lVeCeah1IDiYiBKQAAjpa2vXwC6kGCACV6I8HXSMx27faqX7mQMFVNve9p8isXbyQWqzJax+z24Kjh08A', - }, - }, - }, - ], - transactionParameters: { - chainId: 'penumbra-testnet-rhea', - }, - detectionData: { - fmdClues: [ - { - inner: - 'vCPE22JFgv8JPOWri+IknthYYx5bbUBwqrSnL2Ko2hGtDfh7NRI3lI8Co5Zei8+4jUcaJctQkGrYD0uXwI5SBAAAAAA=', - }, - { - inner: - 'FCuaszw2jXO9bjcKHtXBTNpK80fg4qF1RuV8o19kHgJCh0Gg+OfHjuds5Qpnp73oZBr4zOrxVojO3cCRNv5KAQAAAAA=', - }, - { - inner: - 'CnlKAo3MOrejUQJYobus9R0mx0s5B2N3RD9KHCy+1gZipbCHMWsxQtNI4Aq6mne0lEpjimOkJBoIfV7rd4dsAgAAAAA=', - }, - { - inner: - 'EtmIfw5uII1WoDURC9Fwt5XvWOUNSYmhz4IvdMZocwO9783PQd+DcfnjBkT2JRUj8ZWRlULSxmoUemdyrnWWAAAAAAA=', - }, - { - inner: - 'MHMLUbB/CJasfDn5SrNzU86/ADJ80vRlp14fp5BACg4+5TST+rgMVxWI4G65Z/TT3NEFU/od8WSCSwrBPFB1BAAAAAA=', - }, - { - inner: - 'TLjYWauiUprJeZvQm7pn7qhGgQqGpdUO8XY168bUFgbIaGZAucv8+Ih9oprdDJtwu+u6XMOthV0lxXcExWAJAAAAAAA=', - }, - { - inner: - 'rpz7S5DAzY+vBfnpx6v+XGeQGIAVQHJdfPDX0GM1FxHN++wjE99MUgQWj7PQ/xor8Bq78LXCyFV4sBqAe9rzAgAAAAA=', - }, - { - inner: - 'go/zUaQciHzEjoBJcwZw7hAr3nGoscaPxnRg5iiUYwTlE3kMXx6RfbQqkMrzSz+cVR0j8d9FzMk3+I+efM0EAwAAAAA=', - }, - ], - }, - memo: { - inner: - 'NGJ0T7iaorVP2ApR/78bejqFVn87DO+2vcaogbZYf5VvL6HvazSfYGiLq52c24n4ZfYGtN1z8dTyVknbJ9JawwComzYZ7kkWlQyUbXuKIGCowgxuv0dZ+5QXPuL7acycgnVXlzkfPH6CJylHKhWPb1Wskdk5KJaM+I2ofKi69LPtkIQhYcy3Prc7/nAwytxdjcWjsvS3bjRfry+F4ch8n+2EcUklygz2wnAr21crV6Hd855q+/OZKyEpWkODTB4wuYetm4b8laFklWKWDhFzezdmIUXgf/RSVIgk51H5hThVauH8m1dg4kW/5wklVCrzJjrem2/T/KnIIJEcxzuQ85Smk86fWycgnraQ80Sy9G1nU8rqwBE4KUFLQ6OVu5z0pfYH3DaYKTpVmOsvwCz2l2+me9U6JIB5jiQRvdcjjmPquDIhPbOSNlKRmLa6tmvEqM0Y7rxT1MnbR3Cdzp+30gwruLg0oiTm80N1Ltdkwv2+0uR8iSAfSVmW9o05/Lnqt548hGS/bW3LDX7BHV/Jq464prPUOejEqiFPHjohHlC3hs4T3k8if9euY5DIBwk5evwQ+rNE2E/x8g/wjJyWLp+Nslms8E66ecHWUNgQb5i6NiLwZ8f15/kdrG+ioZj1d/S0hTC9JgZCTEmcvfNBKxOw7ge93cxRmv7Sj688QA5acUDAejinEZmvXXyRV2AD', - }, - }, - bindingSig: { - inner: - 'VDwfYSlhod90QLBvTdIM+T+WdscTjqecFp4PSeRhhwQX2Al3CHo0Bikx3hix0iO4zF/EnRIuz4J70clixI9VAg==', - }, - anchor: { - inner: 'mrchwun83TOMYsdXtkBSdUYXXMzlg6N2NYfEcqWmfwE=', - }, -}); - -export const positionGmPenumbraBuy = Position.fromJson({ - phi: { - component: { p: { lo: '1000000' }, q: { lo: '1000000' } }, - pair: { - asset1: { inner: 'HW2Eq3UZVSBttoUwUi/MUtE7rr2UU7/UH500byp7OAc=' }, - asset2: { inner: 'KeqcLzNx9qSH5+lcJHBB9KNW+YPrBk5dKzvPMiypahA=' }, - }, - }, - nonce: 'QvdZ/22Fhufk9ea3nxSedhYP3C0LHW5HtbMlp27aIpY=', - state: { state: 'POSITION_STATE_ENUM_OPENED' }, - reserves: { r1: {}, r2: { lo: '1000000' } }, -}); -export const positionIdGmPenumbraBuy = PositionId.fromJson({ - inner: 'qE/PCp65S+GHi2HFO74G8Gx5ansmxeMwEdNUgn3GXYE=', -}); - -export const positionGnPenumbraSell = Position.fromJson({ - phi: { - component: { p: { lo: '2000000' }, q: { lo: '2000000' } }, - pair: { - asset1: { inner: 'KeqcLzNx9qSH5+lcJHBB9KNW+YPrBk5dKzvPMiypahA=' }, - asset2: { inner: 'nwPDkQq3OvLnBwGTD+nmv1Ifb2GEmFCgNHrU++9BsRE=' }, - }, - }, - nonce: 't2atgDbEni8gZFhSiYZiKygHgOM7F593qLWgrc9CPA0=', - state: { state: 'POSITION_STATE_ENUM_OPENED' }, - reserves: { r1: {}, r2: { lo: '2000000' } }, -}); -export const positionIdGnPenumbraSell = PositionId.fromJson({ - inner: 'jPb6+hLkYgwIs4sVxhyYUmpbvIyPOXATqL/hiKGwhbg=', -}); - -export const positionGmGnSell = Position.fromJson({ - phi: { - component: { p: { lo: '2000000' }, q: { lo: '4000000' } }, - pair: { - asset1: { inner: 'HW2Eq3UZVSBttoUwUi/MUtE7rr2UU7/UH500byp7OAc=' }, - asset2: { inner: 'nwPDkQq3OvLnBwGTD+nmv1Ifb2GEmFCgNHrU++9BsRE=' }, - }, - }, - nonce: 'fs5uy8JKrLpQiY7ShUgNCgJA+ljdByDIafdi99lPG0U=', - state: { state: 'POSITION_STATE_ENUM_CLOSED' }, - reserves: { r1: {}, r2: { lo: '2000000' } }, -}); -export const positionIdGmGnSell = PositionId.fromJson({ - inner: '8hpmQDWRJFAqYI1NaKltjbFqCRiI4eEQT5DzzNUkDXQ=', -}); - -export const tradingPairGmGn = TradingPair.fromJson({ - asset1: { inner: 'HW2Eq3UZVSBttoUwUi/MUtE7rr2UU7/UH500byp7OAc=' }, - asset2: { inner: 'nwPDkQq3OvLnBwGTD+nmv1Ifb2GEmFCgNHrU++9BsRE=' }, -}); - -export const epoch1 = new Epoch({ - index: 1n, - startHeight: 100n, -}); - -export const epoch2 = new Epoch({ - index: 2n, - startHeight: 200n, -}); - -export const epoch3 = new Epoch({ - index: 3n, - startHeight: 300n, -}); diff --git a/packages/storage/src/indexed-db/indexed-db.test.ts b/packages/storage/src/indexed-db/indexed-db.test.ts deleted file mode 100644 index 47f57c35..00000000 --- a/packages/storage/src/indexed-db/indexed-db.test.ts +++ /dev/null @@ -1,799 +0,0 @@ -import { FmdParameters } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/shielded_pool/v1/shielded_pool_pb'; -import { - SpendableNoteRecord, - SwapRecord, - TransactionInfo, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; -import { beforeEach, describe, expect, it } from 'vitest'; -import { IndexedDb } from '.'; -import { - delegationMetadataA, - delegationMetadataB, - emptyScanResult, - epoch1, - epoch2, - epoch3, - metadataA, - metadataB, - metadataC, - newNote, - noteWithDelegationAssetA, - noteWithDelegationAssetB, - noteWithGmAsset, - positionGmGnSell, - positionGmPenumbraBuy, - positionGnPenumbraSell, - positionIdGmGnSell, - positionIdGmPenumbraBuy, - positionIdGnPenumbraSell, - scanResultWithNewSwaps, - scanResultWithSctUpdates, - tradingPairGmGn, - transaction, - transactionId, -} from './indexed-db.test-data'; -import { GasPrices } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/fee/v1/fee_pb'; -import { - AddressIndex, - WalletId, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb'; -import { - PositionId, - PositionState, - PositionState_PositionStateEnum, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/dex/v1/dex_pb'; -import { - AssetId, - EstimatedPrice, - Metadata, - Value, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; -import type { IdbUpdate, PenumbraDb } from '@penumbra-zone/types/indexed-db'; -import { - AuctionId, - DutchAuctionDescription, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/auction/v1/auction_pb'; -import { StateCommitment } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/crypto/tct/v1/tct_pb'; -import { ChainRegistryClient } from '@penumbra-labs/registry'; - -describe('IndexedDb', () => { - // uses different wallet ids so no collisions take place - const registryClient = new ChainRegistryClient(); - const chainId = 'penumbra-testnet-deimos-6'; - const generateInitialProps = () => ({ - chainId, - idbVersion: 1, - walletId: new WalletId({ - inner: Uint8Array.from({ length: 32 }, () => Math.floor(Math.random() * 256)), - }), - registryClient, - }); - - describe('initializing', () => { - it('sets up as expected in initialize()', async () => { - const db = await IndexedDb.initialize(generateInitialProps()); - await expect(db.getFullSyncHeight()).resolves.not.toThrow(); - }); - - it('different chain ids result in different databases', async () => { - const testnetDb = await IndexedDb.initialize(generateInitialProps()); - const mainnetDb = await IndexedDb.initialize({ - ...generateInitialProps(), - chainId: 'penumbra-testnet-deimos-7', - }); - - await testnetDb.saveAssetsMetadata(metadataA); - await mainnetDb.saveAssetsMetadata(metadataB); - - expect(await testnetDb.getAssetsMetadata(metadataA.penumbraAssetId!)).toEqual(metadataA); - expect(await mainnetDb.getAssetsMetadata(metadataB.penumbraAssetId!)).toEqual(metadataB); - }); - - it('same version uses same db', async () => { - const props = generateInitialProps(); - const dbA = await IndexedDb.initialize(props); - await dbA.saveAssetsMetadata(metadataA); - - const dbB = await IndexedDb.initialize(props); - expect((await dbB.getAssetsMetadata(metadataA.penumbraAssetId!))?.name).toBe(metadataA.name); - }); - - it('increasing version should re-create object stores', async () => { - const version1Props = generateInitialProps(); - const dbA = await IndexedDb.initialize(version1Props); - await dbA.saveAssetsMetadata(metadataA); - dbA.close(); - - const version2Props = { - chainId, - idbVersion: 2, - walletId: version1Props.walletId, - registryClient: new ChainRegistryClient(), - }; - const dbB = await IndexedDb.initialize(version2Props); - expect((await dbB.getAssetsMetadata(metadataA.penumbraAssetId!))?.name).toBeUndefined(); - }); - }); - - describe('Updater', () => { - it('emits events on update', async () => { - const db = await IndexedDb.initialize(generateInitialProps()); - const subscription = db.subscribe('SPENDABLE_NOTES'); - - // Save the new note and wait for the next update in parallel - const [, resA] = await Promise.all([db.saveSpendableNote(newNote), subscription.next()]); - const updateA = resA.value as IdbUpdate; - expect(SpendableNoteRecord.fromJson(updateA.value)).toEqual(newNote); - expect(resA.done).toBeFalsy(); - - // Try a second time - const [, resB] = await Promise.all([db.saveSpendableNote(newNote), subscription.next()]); - const updateB = resB.value as IdbUpdate; - expect(SpendableNoteRecord.fromJson(updateB.value)).toEqual(newNote); - expect(resB.done).toBeFalsy(); - }); - }); - - describe('Clear', () => { - it('object store should be empty after clear', async () => { - const db = await IndexedDb.initialize({ ...generateInitialProps() }); - await db.saveSpendableNote(newNote); - - const notes: SpendableNoteRecord[] = []; - for await (const note of db.iterateSpendableNotes()) { - notes.push(note); - } - expect(notes.length).toBe(1); - - await db.saveAssetsMetadata(metadataA); - - const assets: Metadata[] = []; - for await (const asset of db.iterateAssetsMetadata()) { - assets.push(asset); - } - const registryLength = registryClient.get(chainId).getAllAssets().length; - expect(assets.length).toBe(registryLength + 1); - - await db.saveTransaction(transactionId, 1000n, transaction); - const txs: TransactionInfo[] = []; - for await (const tx of db.iterateTransactions()) { - txs.push(tx); - } - expect(txs.length).toBe(1); - - const scanResult = { - height: 1000n, - sctUpdates: { - delete_ranges: [], - set_forgotten: undefined, - set_position: { - Position: { - epoch: 119, - block: 179, - commitment: 0, - }, - }, - store_commitments: [], - store_hashes: [], - }, - newNotes: [], - newSwaps: [], - }; - - await db.saveScanResult(scanResult); - expect(await db.getFullSyncHeight()).toBe(1000n); - - await db.clear(); - - const notesAfterClear: SpendableNoteRecord[] = []; - for await (const note of db.iterateSpendableNotes()) { - notesAfterClear.push(note); - } - expect(notesAfterClear.length).toBe(0); - - const assetsAfterClear: Metadata[] = []; - for await (const asset of db.iterateAssetsMetadata()) { - assetsAfterClear.push(asset); - } - expect(assetsAfterClear.length).toBe(0); - - const txsAfterClean: TransactionInfo[] = []; - for await (const tx of db.iterateTransactions()) { - txsAfterClean.push(tx); - } - expect(txsAfterClean.length).toBe(0); - expect(await db.getFullSyncHeight()).toBeUndefined(); - }); - }); - - describe('fmd params', () => { - it('should be able to set/get', async () => { - const db = await IndexedDb.initialize({ ...generateInitialProps() }); - - const fmdParams = new FmdParameters({ asOfBlockHeight: 1n, precisionBits: 0 }); - await db.saveFmdParams(fmdParams); - const savedParmas = await db.getFmdParams(); - - expect(fmdParams.equals(savedParmas)).toBeTruthy(); - }); - }); - - describe('last block', () => { - it('should be able to set/get', async () => { - const db = await IndexedDb.initialize({ ...generateInitialProps() }); - - await db.saveScanResult(emptyScanResult); - const savedLastBlock = await db.getFullSyncHeight(); - - expect(emptyScanResult.height === savedLastBlock).toBeTruthy(); - }); - }); - - describe('spendable notes', () => { - it('should be able to set/get note by nullifier', async () => { - const db = await IndexedDb.initialize({ ...generateInitialProps() }); - - await db.saveSpendableNote(newNote); - const savedSpendableNote = await db.getSpendableNoteByNullifier(newNote.nullifier!); - - expect(newNote.equals(savedSpendableNote)).toBeTruthy(); - }); - - it('should be able to set/get all', async () => { - const db = await IndexedDb.initialize({ ...generateInitialProps() }); - - await db.saveSpendableNote(newNote); - - const notes: SpendableNoteRecord[] = []; - for await (const note of db.iterateSpendableNotes()) { - notes.push(note); - } - expect(notes.length === 1).toBeTruthy(); - expect(newNote.equals(notes[0])).toBeTruthy(); - }); - - it('should be able to set/get by commitment', async () => { - const db = await IndexedDb.initialize({ ...generateInitialProps() }); - - await db.saveSpendableNote(newNote); - const noteByCommitment = await db.getSpendableNoteByCommitment(newNote.noteCommitment!); - - expect(newNote.equals(noteByCommitment)).toBeTruthy(); - }); - - it('should return undefined by commitment', async () => { - const db = await IndexedDb.initialize({ ...generateInitialProps() }); - - const noteByCommitment = await db.getSpendableNoteByCommitment(newNote.noteCommitment!); - - expect(noteByCommitment).toBeUndefined(); - }); - }); - - describe('state commitment tree', () => { - it('should be able to set/get', async () => { - const db = await IndexedDb.initialize({ ...generateInitialProps() }); - - await db.saveScanResult(scanResultWithSctUpdates); - - const stateCommitmentTree = await db.getStateCommitmentTree(); - - expect(stateCommitmentTree.hashes.length === 1).toBeTruthy(); - expect(stateCommitmentTree.commitments.length === 1).toBeTruthy(); - expect(stateCommitmentTree.last_forgotten === 12n).toBeTruthy(); - expect(stateCommitmentTree.last_position).toBeTruthy(); - }); - }); - - describe('assets', () => { - it('should be pre-loaded with hardcoded assets', async () => { - const propsWithAssets = { - chainId, - idbVersion: 2, - walletId: new WalletId({ - inner: Uint8Array.from({ length: 32 }, () => Math.floor(Math.random() * 256)), - }), - registryClient: new ChainRegistryClient(), - }; - const db = await IndexedDb.initialize(propsWithAssets); - - const savedAssets: Metadata[] = []; - for await (const asset of db.iterateAssetsMetadata()) { - savedAssets.push(asset); - } - - const registryLength = registryClient.get(chainId).getAllAssets().length; - expect(savedAssets.length === registryLength).toBeTruthy(); - }); - - it('should be able to set/get by id', async () => { - const db = await IndexedDb.initialize({ ...generateInitialProps() }); - - await db.saveAssetsMetadata(metadataC); - const savedDenomMetadata = await db.getAssetsMetadata(metadataC.penumbraAssetId!); - - expect(metadataC.equals(savedDenomMetadata)).toBeTruthy(); - }); - - it('should be able to set/get all', async () => { - const db = await IndexedDb.initialize({ ...generateInitialProps() }); - - await db.saveAssetsMetadata(metadataA); - await db.saveAssetsMetadata(metadataB); - await db.saveAssetsMetadata(metadataC); - - const savedAssets: Metadata[] = []; - for await (const asset of db.iterateAssetsMetadata()) { - savedAssets.push(asset); - } - const registryLength = registryClient.get(chainId).getAllAssets().length; - expect(savedAssets.length === registryLength + 3).toBeTruthy(); - }); - }); - - describe('transactions', () => { - it('should be able to set/get by note source', async () => { - const db = await IndexedDb.initialize({ ...generateInitialProps() }); - await db.saveTransaction(transactionId, 1000n, transaction); - - const savedTransaction = await db.getTransaction(transactionId); - expect(transaction.equals(savedTransaction?.transaction)).toBeTruthy(); - }); - - it('should be able to set/get all', async () => { - const db = await IndexedDb.initialize({ ...generateInitialProps() }); - - await db.saveTransaction(transactionId, 1000n, transaction); - const savedTransactions: TransactionInfo[] = []; - for await (const tx of db.iterateTransactions()) { - savedTransactions.push(tx); - } - expect(savedTransactions.length === 1).toBeTruthy(); - expect(transaction.equals(savedTransactions[0]?.transaction)).toBeTruthy(); - }); - }); - - describe('swaps', () => { - it('should be able to set/get all', async () => { - const db = await IndexedDb.initialize({ ...generateInitialProps() }); - - await db.saveScanResult(scanResultWithNewSwaps); - const savedSwaps: SwapRecord[] = []; - for await (const swap of db.iterateSwaps()) { - savedSwaps.push(swap); - } - expect(savedSwaps.length === 1).toBeTruthy(); - expect(savedSwaps[0]!.equals(scanResultWithNewSwaps.newSwaps[0])).toBeTruthy(); - }); - - it('should be able to set/get by nullifier', async () => { - const db = await IndexedDb.initialize({ ...generateInitialProps() }); - - await db.saveScanResult(scanResultWithNewSwaps); - const swapByNullifier = await db.getSwapByNullifier( - scanResultWithNewSwaps.newSwaps[0]!.nullifier!, - ); - - expect(swapByNullifier!.equals(scanResultWithNewSwaps.newSwaps[0])).toBeTruthy(); - }); - - it('should be able to set/get by commitment', async () => { - const db = await IndexedDb.initialize({ ...generateInitialProps() }); - - await db.saveScanResult(scanResultWithNewSwaps); - const swapByCommitment = await db.getSwapByCommitment( - scanResultWithNewSwaps.newSwaps[0]!.swapCommitment!, - ); - - expect(swapByCommitment!.equals(scanResultWithNewSwaps.newSwaps[0])).toBeTruthy(); - }); - }); - - describe('gas prices', () => { - it('should be able to set/get', async () => { - const db = await IndexedDb.initialize({ ...generateInitialProps() }); - - const gasPrices = new GasPrices({ - blockSpacePrice: 0n, - compactBlockSpacePrice: 0n, - verificationPrice: 0n, - executionPrice: 0n, - }); - await db.saveGasPrices(gasPrices); - const savedPrices = await db.getGasPrices(); - - expect(gasPrices.equals(savedPrices)).toBeTruthy(); - }); - }); - - describe('notes for voting', () => { - // 'noteWithDelegationAssetA' and 'noteWithDelegationAssetB' can be votable at height 222, - // but 'noteWithGmAsset' should not be used for voting since 'Gm' is not a delegation asset. - it('should be able to get all notes for voting', async () => { - const db = await IndexedDb.initialize({ ...generateInitialProps() }); - - await db.saveAssetsMetadata(delegationMetadataA); - await db.saveAssetsMetadata(delegationMetadataB); - - await db.saveAssetsMetadata(metadataB); - - await db.saveSpendableNote(noteWithDelegationAssetA); - await db.saveSpendableNote(noteWithDelegationAssetB); - - await db.saveSpendableNote(noteWithGmAsset); - - const notesForVoting = await db.getNotesForVoting(undefined, 222n); - - expect(notesForVoting.length).toBe(2); - }); - - // 'noteWithDelegationAssetB' has a creation height of 53 and cannot be votable at height 50 - it('votable_at_height parameter should screen out noteWithDelegationAssetB', async () => { - const db = await IndexedDb.initialize({ ...generateInitialProps() }); - - await db.saveAssetsMetadata(delegationMetadataA); - await db.saveAssetsMetadata(delegationMetadataB); - - await db.saveSpendableNote(noteWithDelegationAssetA); - await db.saveSpendableNote(noteWithDelegationAssetB); - - const notesForVoting = await db.getNotesForVoting(undefined, 50n); - - expect(notesForVoting.length).toBe(1); - }); - - // For all notes addressIndex=0, so we should get an empty list - it('addressIndex parameter should screen out all notes', async () => { - const db = await IndexedDb.initialize({ ...generateInitialProps() }); - - await db.saveAssetsMetadata(delegationMetadataA); - await db.saveAssetsMetadata(delegationMetadataB); - - await db.saveSpendableNote(noteWithDelegationAssetA); - await db.saveSpendableNote(noteWithDelegationAssetB); - - const notesForVoting = await db.getNotesForVoting(new AddressIndex({ account: 2 }), 222n); - - expect(notesForVoting.length === 0).toBeTruthy(); - }); - }); - - describe('positions', () => { - it('position should be added and their state should change', async () => { - const db = await IndexedDb.initialize({ ...generateInitialProps() }); - - await db.addPosition(positionIdGmPenumbraBuy, positionGmPenumbraBuy); - await db.updatePosition( - positionIdGmPenumbraBuy, - new PositionState({ state: PositionState_PositionStateEnum.CLOSED }), - ); - const ownedPositions: PositionId[] = []; - for await (const positionId of db.getOwnedPositionIds(undefined, undefined)) { - ownedPositions.push(positionId as PositionId); - } - expect(ownedPositions.length).toBe(1); - expect(ownedPositions[0]?.equals(positionIdGmPenumbraBuy)).toBeTruthy(); - }); - - it('attempt to change state of a non-existent position should throw an error', async () => { - const db = await IndexedDb.initialize({ ...generateInitialProps() }); - await expect( - db.updatePosition( - positionIdGmPenumbraBuy, - new PositionState({ state: PositionState_PositionStateEnum.CLOSED }), - ), - ).rejects.toThrow('Position not found when trying to change its state'); - }); - - it('should get all position ids', async () => { - const db = await IndexedDb.initialize({ ...generateInitialProps() }); - await db.addPosition(positionIdGmPenumbraBuy, positionGmPenumbraBuy); - await db.addPosition(positionIdGnPenumbraSell, positionGnPenumbraSell); - await db.addPosition(positionIdGmGnSell, positionGmGnSell); - - const ownedPositions: PositionId[] = []; - for await (const positionId of db.getOwnedPositionIds(undefined, undefined)) { - ownedPositions.push(positionId as PositionId); - } - expect(ownedPositions.length).toBe(3); - }); - - it('should get all position with given position state', async () => { - const db = await IndexedDb.initialize({ ...generateInitialProps() }); - await db.addPosition(positionIdGmPenumbraBuy, positionGmPenumbraBuy); - await db.addPosition(positionIdGnPenumbraSell, positionGnPenumbraSell); - await db.addPosition(positionIdGmGnSell, positionGmGnSell); - - const ownedPositions: PositionId[] = []; - for await (const positionId of db.getOwnedPositionIds( - new PositionState({ state: PositionState_PositionStateEnum.CLOSED }), - undefined, - )) { - ownedPositions.push(positionId as PositionId); - } - expect(ownedPositions.length).toBe(1); - }); - - it('should get all position with given trading pair', async () => { - const db = await IndexedDb.initialize({ ...generateInitialProps() }); - await db.addPosition(positionIdGmPenumbraBuy, positionGmPenumbraBuy); - await db.addPosition(positionIdGnPenumbraSell, positionGnPenumbraSell); - await db.addPosition(positionIdGmGnSell, positionGmGnSell); - - const ownedPositions: PositionId[] = []; - for await (const positionId of db.getOwnedPositionIds(undefined, tradingPairGmGn)) { - ownedPositions.push(positionId as PositionId); - } - expect(ownedPositions.length).toBe(1); - }); - }); - - describe('epochs', () => { - let db: IndexedDb; - - beforeEach(async () => { - db = await IndexedDb.initialize({ ...generateInitialProps() }); - }); - - it('prepopulates the 0th epoch', async () => { - const epoch = await db.getEpochByHeight(0n); - expect(epoch?.index).toBe(0n); - expect(epoch?.startHeight).toBe(0n); - }); - - describe('addEpoch', () => { - beforeEach(async () => { - await db.addEpoch(epoch1.startHeight); - await db.addEpoch(epoch2.startHeight); - await db.addEpoch(epoch3.startHeight); - }); - - it('auto-increments the epoch index', async () => { - const [result1, result2, result3] = await Promise.all([ - db.getEpochByHeight(150n), - db.getEpochByHeight(250n), - db.getEpochByHeight(350n), - ]); - - expect(result1?.index).toBe(1n); - expect(result2?.index).toBe(2n); - expect(result3?.index).toBe(3n); - }); - - it('should not save the epoch with the same startHeight twice', async () => { - await db.addEpoch(epoch3.startHeight); - - const result = await db.getEpochByHeight(350n); - expect(result?.index).toBe(3n); - }); - }); - - describe('getEpochByHeight', () => { - beforeEach(async () => { - await db.addEpoch(epoch1.startHeight); - await db.addEpoch(epoch2.startHeight); - await db.addEpoch(epoch3.startHeight); - }); - - it('returns the epoch containing the given block height', async () => { - const [result1, result2, result3] = await Promise.all([ - db.getEpochByHeight(150n), - db.getEpochByHeight(250n), - db.getEpochByHeight(350n), - ]); - - expect(result1?.toJson()).toEqual(epoch1.toJson()); - expect(result2?.toJson()).toEqual(epoch2.toJson()); - expect(result3?.toJson()).toEqual(epoch3.toJson()); - }); - }); - }); - - describe('prices', () => { - let db: IndexedDb; - - const numeraireAssetId = new AssetId({ inner: new Uint8Array([5, 6, 7, 8]) }); - - const stakingAssetId = AssetId.fromJson({ - inner: 'KeqcLzNx9qSH5+lcJHBB9KNW+YPrBk5dKzvPMiypahA=', - }); - beforeEach(async () => { - db = await IndexedDb.initialize({ ...generateInitialProps() }); - await db.updatePrice(delegationMetadataA.penumbraAssetId!, stakingAssetId, 1.23, 50n); - await db.updatePrice(metadataA.penumbraAssetId!, numeraireAssetId, 22.15, 40n); - }); - - it('saves and gets a price in the database', async () => { - // This effectively tests both the save and the get, since we saved via - // `updatePrice()` in the `beforeEach` above. - await expect(db.getPricesForAsset(delegationMetadataA, 50n)).resolves.toEqual([ - new EstimatedPrice({ - pricedAsset: delegationMetadataA.penumbraAssetId!, - numeraire: stakingAssetId, - numerairePerUnit: 1.23, - asOfHeight: 50n, - }), - ]); - }); - - it('should not return too old price', async () => { - await expect(db.getPricesForAsset(metadataA, 241n)).resolves.toEqual([]); - }); - - it('different types of assets should have different price relevance thresholds', async () => { - await expect(db.getPricesForAsset(metadataA, 241n)).resolves.toEqual([]); - await expect(db.getPricesForAsset(delegationMetadataA, 241n)).resolves.toEqual([ - new EstimatedPrice({ - pricedAsset: delegationMetadataA.penumbraAssetId!, - numeraire: stakingAssetId, - numerairePerUnit: 1.23, - asOfHeight: 50n, - }), - ]); - }); - - it('should delete only prices with a numeraires different from the staking token', async () => { - await db.clearSwapBasedPrices(); - await expect(db.getPricesForAsset(metadataA, 50n)).resolves.toEqual([]); - }); - }); - - describe('upsertAuction()', () => { - let db: IndexedDb; - - beforeEach(async () => { - db = await IndexedDb.initialize({ ...generateInitialProps() }); - }); - - it('inserts an auction', async () => { - const auctionId = new AuctionId({ inner: new Uint8Array([0, 1, 2, 3]) }); - const auction = new DutchAuctionDescription({ startHeight: 1234n }); - await db.upsertAuction(auctionId, { auction }); - - const fetchedAuction = await db.getAuction(auctionId); - expect(fetchedAuction).toEqual({ - auction, - }); - }); - - it('inserts a note commitment', async () => { - const auctionId = new AuctionId({ inner: new Uint8Array([0, 1, 2, 3]) }); - const noteCommitment = new StateCommitment({ inner: new Uint8Array([0, 1, 2, 3]) }); - await db.upsertAuction(auctionId, { noteCommitment }); - - const fetchedAuction = await db.getAuction(auctionId); - expect(fetchedAuction).toEqual({ - noteCommitment, - }); - }); - - it('inserts both an auction and a note commitment', async () => { - const auctionId = new AuctionId({ inner: new Uint8Array([0, 1, 2, 3]) }); - const auction = new DutchAuctionDescription({ startHeight: 1234n }); - const noteCommitment = new StateCommitment({ inner: new Uint8Array([0, 1, 2, 3]) }); - await db.upsertAuction(auctionId, { auction, noteCommitment }); - - const fetchedAuction = await db.getAuction(auctionId); - expect(fetchedAuction).toEqual({ - auction, - noteCommitment, - }); - }); - - it('inserts an auction and sequence number, and then updates with a note commitment when given the same auction ID', async () => { - const auctionId = new AuctionId({ inner: new Uint8Array([0, 1, 2, 3]) }); - const auction = new DutchAuctionDescription({ startHeight: 1234n }); - const seqNum = 0n; - await db.upsertAuction(auctionId, { auction, seqNum }); - - let fetchedAuction = await db.getAuction(auctionId); - expect(fetchedAuction).toBeTruthy(); - - const noteCommitment = new StateCommitment({ inner: new Uint8Array([0, 1, 2, 3]) }); - await db.upsertAuction(auctionId, { noteCommitment }); - - fetchedAuction = await db.getAuction(auctionId); - expect(fetchedAuction).toBeTruthy(); - - expect(fetchedAuction).toEqual({ - auction, - noteCommitment, - seqNum, - }); - }); - - it('inserts a note commitment and then updates with an auction and sequence number when given the same auction ID', async () => { - const auctionId = new AuctionId({ inner: new Uint8Array([0, 1, 2, 3]) }); - const noteCommitment = new StateCommitment({ inner: new Uint8Array([0, 1, 2, 3]) }); - await db.upsertAuction(auctionId, { noteCommitment }); - - let fetchedAuction = await db.getAuction(auctionId); - expect(fetchedAuction).toBeTruthy(); - - const auction = new DutchAuctionDescription({ startHeight: 1234n }); - const seqNum = 0n; - await db.upsertAuction(auctionId, { auction, seqNum }); - - fetchedAuction = await db.getAuction(auctionId); - expect(fetchedAuction).toBeTruthy(); - - expect(fetchedAuction).toEqual({ - auction, - noteCommitment, - seqNum, - }); - }); - - it('inserts all data, and then updates with a sequence number when given the same auction ID', async () => { - const auctionId = new AuctionId({ inner: new Uint8Array([0, 1, 2, 3]) }); - const auction = new DutchAuctionDescription({ startHeight: 1234n }); - const noteCommitment = new StateCommitment({ inner: new Uint8Array([0, 1, 2, 3]) }); - await db.upsertAuction(auctionId, { auction, noteCommitment, seqNum: 0n }); - - let fetchedAuction = await db.getAuction(auctionId); - expect(fetchedAuction).toBeTruthy(); - - await db.upsertAuction(auctionId, { seqNum: 1n }); - - fetchedAuction = await db.getAuction(auctionId); - expect(fetchedAuction).toBeTruthy(); - - expect(fetchedAuction).toEqual({ - auction, - noteCommitment, - seqNum: 1n, - }); - }); - }); - - describe('addAuctionOutstandingReserves()', () => { - let db: IndexedDb; - - beforeEach(async () => { - db = await IndexedDb.initialize({ ...generateInitialProps() }); - }); - - it('saves the outstanding reserves', async () => { - const auctionId = new AuctionId({ inner: new Uint8Array([0, 1, 2, 3]) }); - const input = new Value({ - amount: { hi: 0n, lo: 1n }, - assetId: { inner: new Uint8Array([1, 1, 1, 1]) }, - }); - const output = new Value({ - amount: { hi: 0n, lo: 2n }, - assetId: { inner: new Uint8Array([2, 2, 2, 2]) }, - }); - await db.addAuctionOutstandingReserves(auctionId, { input, output }); - - await expect(db.getAuctionOutstandingReserves(auctionId)).resolves.toEqual({ input, output }); - }); - }); - - describe('deleteAuctionOutstandingReserves()', () => { - let db: IndexedDb; - - beforeEach(async () => { - db = await IndexedDb.initialize({ ...generateInitialProps() }); - }); - - it('deletes the reserves', async () => { - const auctionId = new AuctionId({ inner: new Uint8Array([0, 1, 2, 3]) }); - const input = new Value({ - amount: { hi: 0n, lo: 1n }, - assetId: { inner: new Uint8Array([1, 1, 1, 1]) }, - }); - const output = new Value({ - amount: { hi: 0n, lo: 2n }, - assetId: { inner: new Uint8Array([2, 2, 2, 2]) }, - }); - await db.addAuctionOutstandingReserves(auctionId, { input, output }); - - // Make sure this test is actually deleting an existing record - await expect(db.getAuctionOutstandingReserves(auctionId)).resolves.toBeTruthy(); - - await db.deleteAuctionOutstandingReserves(auctionId); - - await expect(db.getAuctionOutstandingReserves(auctionId)).resolves.toBeUndefined(); - }); - }); -}); diff --git a/packages/storage/src/indexed-db/stream.ts b/packages/storage/src/indexed-db/stream.ts deleted file mode 100644 index eb760f70..00000000 --- a/packages/storage/src/indexed-db/stream.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { AnyMessage, JsonValue, Message, MessageType } from '@bufbuild/protobuf'; -import { IDBPCursorWithValue } from 'idb'; -import type { PenumbraDb, PenumbraStoreNames } from '@penumbra-zone/types/indexed-db'; - -export class IdbCursorSource = AnyMessage> - implements UnderlyingDefaultSource -{ - constructor( - private cursor: Promise | null>, - private messageType: MessageType, - ) {} - - start(cont: ReadableStreamDefaultController) { - // immediately stream as fast as possible, to prevent idb from closing the tx - void (async () => { - let cursor = await this.cursor; - while (cursor) { - cont.enqueue(this.messageType.fromJson(cursor.value as JsonValue)); - cursor = await cursor.continue(); - } - cont.close(); - })(); - } -} diff --git a/packages/storage/src/indexed-db/updater.ts b/packages/storage/src/indexed-db/updater.ts deleted file mode 100644 index c9655f3f..00000000 --- a/packages/storage/src/indexed-db/updater.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { IDBPDatabase, StoreNames } from 'idb'; -import type { IdbUpdate, PenumbraDb } from '@penumbra-zone/types/indexed-db'; - -export class IbdUpdates { - constructor(readonly all: IdbUpdate>[] = []) {} - - add>( - update: IdbUpdate, - ) { - this.all.push(update); - } -} - -type Resolver = (value: IdbUpdate>) => void; - -export class IbdUpdater { - private readonly subscribers: Map, Resolver[]>; - - constructor(private readonly db: IDBPDatabase) { - this.subscribers = new Map(); - } - - subscribe>( - table: StoreName, - ): AsyncGenerator, void> { - // Need a local binding - // eslint-disable-next-line @typescript-eslint/no-this-alias - const bind = this; - const subscriber = async function* () { - while (true) { - const update = await new Promise>(resolve => { - const resolversForTable = bind.subscribers.get(table) ?? []; - resolversForTable.push(resolve as Resolver); - bind.subscribers.set(table, resolversForTable); - }); - yield update; - } - }; - - return subscriber(); - } - - async updateAll(updates: IbdUpdates): Promise { - const tables = updates.all.map(u => u.table); - const tx = this.db.transaction(tables, 'readwrite'); - - for (const update of updates.all) { - await tx.objectStore(update.table).put(update.value, update.key); - this.notifySubscribers(update); - } - - await tx.done; - } - - async update>( - update: IdbUpdate, - ): Promise { - const updates = new IbdUpdates(); - updates.add(update); - await this.updateAll(updates); - } - - private notifySubscribers>( - update: IdbUpdate, - ) { - const resolversForTable = this.subscribers.get(update.table); - if (resolversForTable) { - for (const resolve of resolversForTable) { - resolve(update); - } - this.subscribers.set(update.table, []); // Clear the resolvers for this table after notifying all of them - } - } -} diff --git a/packages/storage/tsconfig.json b/packages/storage/tsconfig.json deleted file mode 100644 index 61a00fa2..00000000 --- a/packages/storage/tsconfig.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "extends": "tsconfig/base.json", - "include": ["."], - "exclude": ["node_modules"] -} diff --git a/packages/storage/vitest.config.ts b/packages/storage/vitest.config.ts deleted file mode 100644 index fc65e61c..00000000 --- a/packages/storage/vitest.config.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { defineConfig } from 'vitest/config'; -import wasm from 'vite-plugin-wasm'; -import topLevelAwait from 'vite-plugin-top-level-await'; - -export default defineConfig({ - plugins: [wasm(), topLevelAwait()], - test: { - include: ['**/*.test.ts'], - browser: { - name: 'chromium', - provider: 'playwright', - enabled: true, - headless: true, - }, - }, -}); diff --git a/packages/tailwind-config/package.json b/packages/tailwind-config/package.json index d01ced29..cf28e6e7 100644 --- a/packages/tailwind-config/package.json +++ b/packages/tailwind-config/package.json @@ -1,11 +1,11 @@ { - "name": "@penumbra-zone/tailwind-config", + "name": "@repo/tailwind-config", "version": "2.0.1", "private": true, "license": "(MIT OR Apache-2.0)", "main": "index.ts", "dependencies": { - "tailwindcss": "^3.4.3", + "tailwindcss": "^3.4.4", "tailwindcss-animate": "^1.0.7" } } diff --git a/packages/tailwind-config/resolved-tailwind-config.ts b/packages/tailwind-config/resolved-tailwind-config.ts index 6a8ac2ce..f1dc872c 100644 --- a/packages/tailwind-config/resolved-tailwind-config.ts +++ b/packages/tailwind-config/resolved-tailwind-config.ts @@ -1,4 +1,4 @@ import resolveConfig from 'tailwindcss/resolveConfig'; -import tailwindConfig from '@penumbra-zone/tailwind-config'; +import tailwindConfig from '@repo/tailwind-config'; export const RESOLVED_TAILWIND_CONFIG = resolveConfig(tailwindConfig); diff --git a/packages/transport-chrome/CHANGELOG.md b/packages/transport-chrome/CHANGELOG.md deleted file mode 100644 index d1618081..00000000 --- a/packages/transport-chrome/CHANGELOG.md +++ /dev/null @@ -1,64 +0,0 @@ -# @penumbra-zone/transport-chrome - -## 2.2.2 - -### Patch Changes - -- Updated dependencies [8fe4de6] - - @penumbra-zone/transport-dom@6.0.0 - -## 2.2.1 - -### Patch Changes - -- Updated dependencies [8b121ec] - - @penumbra-zone/transport-dom@5.0.0 - -## 2.2.0 - -### Minor Changes - -- 3ea1e6c: update buf types dependencies - -### Patch Changes - -- Updated dependencies [3ea1e6c] - - @penumbra-zone/transport-dom@4.1.0 - -## 2.1.2 - -### Patch Changes - -- Updated dependencies [fc500af] - - @penumbra-zone/transport-dom@4.0.0 - -## 2.1.1 - -### Patch Changes - -- Updated dependencies [3148375] - - @penumbra-zone/transport-dom@3.0.0 - -## 2.1.0 - -### Minor Changes - -- 13d0bc5: - -## 2.0.0 - -### Major Changes - -- 929d278: barrel imports to facilitate better tree shaking - -### Patch Changes - -- Updated dependencies [929d278] - - @penumbra-zone/transport-dom@2.0.0 - -## 1.0.1 - -### Patch Changes - -- Updated dependencies - - @penumbra-zone/transport-dom@1.1.0 diff --git a/packages/transport-chrome/eslint.config.mjs b/packages/transport-chrome/eslint.config.mjs deleted file mode 100644 index a53ed8e5..00000000 --- a/packages/transport-chrome/eslint.config.mjs +++ /dev/null @@ -1,13 +0,0 @@ -import { penumbraEslintConfig } from '@penumbra-zone/eslint-config'; -import { config, parser } from 'typescript-eslint'; - -export default config({ - ...penumbraEslintConfig, - languageOptions: { - parser, - parserOptions: { - project: true, - tsconfigRootDir: import.meta.dirname, - }, - }, -}); diff --git a/packages/transport-chrome/package.json b/packages/transport-chrome/package.json deleted file mode 100644 index 9d08b263..00000000 --- a/packages/transport-chrome/package.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "name": "@penumbra-zone/transport-chrome", - "version": "2.2.2", - "private": true, - "license": "(MIT OR Apache-2.0)", - "description": "Tools for adapting `@penumbra-zone/transport` to Chrome's extension runtime messaging API", - "scripts": { - "lint": "eslint src", - "test": "vitest run" - }, - "files": [ - "src/", - "*.md", - "!**/*.test.ts" - ], - "exports": { - "./channel-names": "./src/channel-names.ts", - "./message": "./src/message.ts", - "./session-client": "./src/session-client.ts", - "./session-manager": "./src/session-manager.ts", - "./stream": "./src/stream.ts" - }, - "dependencies": { - "@penumbra-zone/transport-dom": "workspace:*" - }, - "devDependencies": { - "@bufbuild/protobuf": "^1.10.0", - "@connectrpc/connect": "^1.4.0" - }, - "peerDependencies": { - "@bufbuild/protobuf": "^1.10.0", - "@connectrpc/connect": "^1.4.0" - } -} diff --git a/packages/transport-chrome/src/channel-names.test.ts b/packages/transport-chrome/src/channel-names.test.ts deleted file mode 100644 index aa8dcf8e..00000000 --- a/packages/transport-chrome/src/channel-names.test.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { describe, it, expect } from 'vitest'; -import { nameConnection, parseConnectionName, ChannelLabel } from './channel-names'; - -describe('nameConnection', () => { - it('should generate channel names with the specified prefix and label', () => { - const prefix = 'test'; - const label = ChannelLabel.TRANSPORT; - const name = nameConnection(prefix, label); - const segments = name.split(' '); - expect(segments.length).toBe(3); - expect(segments[0]).toBe(prefix); - expect(segments[1]).toBe(label); - expect(segments[2].length).toBe(36); - }); -}); - -describe('parseConnectionName', () => { - it('should parse the prefix and label from a channel name', () => { - const prefix = 'test'; - const label = ChannelLabel.TRANSPORT; - const name = nameConnection(prefix, label); - const parsed = parseConnectionName(prefix, name); - expect(parsed).not.toBe(undefined); - expect(parsed!.label).toBe(label); - expect(parsed!.uuid.length).toBe(36); - }); -}); diff --git a/packages/transport-chrome/src/channel-names.ts b/packages/transport-chrome/src/channel-names.ts deleted file mode 100644 index 23d4c96a..00000000 --- a/packages/transport-chrome/src/channel-names.ts +++ /dev/null @@ -1,62 +0,0 @@ -/* - * This file contains simple utilities for creating and parsing chrome runtime - * channel names containing transport metadata. Channel names identify the - * purpose of channels involved in transport. - * - * Any script with access to the chrome runtime may initiate a connection with - * any arbitrary name. Some scripts with access to the browser runtime may be - * able to access any channel they can identify by name. - * - * Content scripts and extension pages - * - create names to establish clients - * - create names to initiate client-streaming requests - * - accept names to receive server-streaming responses - * - * Content scripts should only act on connection names appearing via an - * established connection to the extension. - * - * The background connection manager - * - parses names to accept client connections - * - parses names to handle client-streaming requests - * - creates names to satisfy server-streaming responses - * - */ - -// TODO: check delimiter for label substring? -export enum ChannelLabel { - TRANSPORT = 'TRANSPORT', - STREAM = 'STREAM', -} - -const delimiter = ' '; - -const isChannelLabel = (label: string): label is ChannelLabel => label in ChannelLabel; - -// types package indicates `${string}-${string}-${string}-${string}-${string}` -const reUUIDv4 = /^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}$/i; -type UUID = ReturnType; -const isUUID = (uuid: string): uuid is UUID => reUUIDv4.test(uuid); - -/** - * Utility for generating channel names. - * - * @param label type/purpose of connection - */ -export const nameConnection = (prefix: string, label: ChannelLabel) => { - if (prefix.includes(delimiter)) throw TypeError(`Prefix cannot contain delimiter "${delimiter}"`); - return `${prefix}${delimiter}${label}${delimiter}${crypto.randomUUID()}`; -}; - -export const parseConnectionName = (prefix: string, name: string) => { - if (prefix.includes(delimiter)) throw TypeError(`Prefix cannot contain delimiter "${delimiter}"`); - const segments = name.split(delimiter); - if (segments.length !== 3) return undefined; - - const [parsedPrefix, label, uuid] = segments as [string, string, string]; - if (parsedPrefix !== prefix || !isChannelLabel(label) || !isUUID(uuid)) return undefined; - - return { - label, - uuid, - }; -}; diff --git a/packages/transport-chrome/src/message.ts b/packages/transport-chrome/src/message.ts deleted file mode 100644 index ce5e7ed7..00000000 --- a/packages/transport-chrome/src/message.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { isTransportEvent, TransportEvent } from '@penumbra-zone/transport-dom/messages'; - -export const isTransportInitChannel = (c: unknown): c is TransportInitChannel => - isTransportEvent(c) && 'channel' in c && typeof c.channel === 'string'; // sub-channel stream - -export interface TransportInitChannel extends TransportEvent { - channel: string; -} diff --git a/packages/transport-chrome/src/session-client.ts b/packages/transport-chrome/src/session-client.ts deleted file mode 100644 index 15e71aa8..00000000 --- a/packages/transport-chrome/src/session-client.ts +++ /dev/null @@ -1,107 +0,0 @@ -/** - * CRSessionClient is a Chrome runtime session client: it handles channel - * Transport client sessions in the Chrome runtime. Intended for use as a - * document singleton, in a content script. - * - * Simple handlers unconditionally forward messages back and forth. Chrome - * runtime disconnect is detected and surfaced as an error. - * - * Only a basic same-window origin check and structural typing are performed. - * Content scripts are ultimately untrusted, so services are responsible for - * confirming legitimacy. - * - * A `ReadableStream` or `AsyncIterable` cannot cross the runtime, so streaming - * methods sink/source a dedicated `chrome.runtime.Port` at this boundary. - */ - -import { - isTransportError, - isTransportMessage, - isTransportStream, - TransportStream, -} from '@penumbra-zone/transport-dom/messages'; -import { ChannelLabel, nameConnection } from './channel-names'; -import { isTransportInitChannel, TransportInitChannel } from './message'; -import { PortStreamSink, PortStreamSource } from './stream'; -import { Code, ConnectError } from '@connectrpc/connect'; -import { errorToJson } from '@connectrpc/connect/protocol-connect'; - -export class CRSessionClient { - private static singleton?: CRSessionClient; - private servicePort: chrome.runtime.Port; - - private constructor( - private prefix: string, - private clientPort: MessagePort, - ) { - if (CRSessionClient.singleton) throw new Error('Already constructed'); - - this.servicePort = chrome.runtime.connect({ - includeTlsChannelId: true, - name: nameConnection(prefix, ChannelLabel.TRANSPORT), - }); - - this.servicePort.onMessage.addListener(this.serviceListener); - this.servicePort.onDisconnect.addListener(this.disconnect); - this.clientPort.addEventListener('message', this.clientListener); - this.clientPort.start(); - } - - /** - * Establishes a new connection from this document to the extension. - * - * @param prefix a string containing no spaces - * @returns a `MessagePort` that can be provided to DOM channel transports - */ - public static init(prefix: string): MessagePort { - const { port1, port2 } = new MessageChannel(); - CRSessionClient.singleton ??= new CRSessionClient(prefix, port1); - return port2; - } - - private disconnect = () => { - this.clientPort.removeEventListener('message', this.clientListener); - this.clientPort.postMessage({ - error: errorToJson(new ConnectError('Connection closed', Code.Unavailable), undefined), - }); - this.clientPort.close(); - }; - - private clientListener = (ev: MessageEvent) => { - try { - if (isTransportMessage(ev.data)) this.servicePort.postMessage(ev.data); - else if (isTransportStream(ev.data)) - this.servicePort.postMessage(this.requestChannelStream(ev.data)); - else console.warn('Unknown item from client', ev.data); - } catch (e) { - this.clientPort.postMessage({ error: errorToJson(ConnectError.from(e), undefined) }); - } - }; - - private serviceListener = (m: unknown) => { - try { - if (isTransportError(m) || isTransportMessage(m)) this.clientPort.postMessage(m); - else if (isTransportInitChannel(m)) - this.clientPort.postMessage(...this.acceptChannelStreamResponse(m)); - else console.warn('Unknown item from service', m); - } catch (e) { - this.clientPort.postMessage({ error: errorToJson(ConnectError.from(e), undefined) }); - } - }; - - private acceptChannelStreamResponse = ({ requestId, channel: name }: TransportInitChannel) => { - const stream = new ReadableStream(new PortStreamSource(chrome.runtime.connect({ name }))); - return [{ requestId, stream }, [stream]] satisfies [TransportStream, [Transferable]]; - }; - - private requestChannelStream = ({ requestId, stream }: TransportStream) => { - const channel = nameConnection(this.prefix, ChannelLabel.STREAM); - const sinkListener = (p: chrome.runtime.Port) => { - if (p.name !== channel) return; - chrome.runtime.onConnect.removeListener(sinkListener); - void stream.pipeTo(new WritableStream(new PortStreamSink(p))).catch(() => null); - }; - chrome.runtime.onConnect.addListener(sinkListener); - return { requestId, channel } satisfies TransportInitChannel; - }; -} diff --git a/packages/transport-chrome/src/session-manager.ts b/packages/transport-chrome/src/session-manager.ts deleted file mode 100644 index 100ab5e0..00000000 --- a/packages/transport-chrome/src/session-manager.ts +++ /dev/null @@ -1,178 +0,0 @@ -import { ConnectError } from '@connectrpc/connect'; -import { errorToJson } from '@connectrpc/connect/protocol-connect'; -import { ChannelLabel, nameConnection, parseConnectionName } from './channel-names'; -import { isTransportInitChannel, TransportInitChannel } from './message'; -import { PortStreamSink, PortStreamSource } from './stream'; -import { ChannelHandlerFn } from '@penumbra-zone/transport-dom/adapter'; -import { - isTransportMessage, - TransportEvent, - TransportMessage, - TransportStream, -} from '@penumbra-zone/transport-dom/messages'; - -interface CRSession { - clientId: string; - acont: AbortController; - port: chrome.runtime.Port; - origin: string; -} - -/** - * Only for use as an extension-level singleton by the extension's main - * background worker. - * - * Currently this supports - * - connections from content scripts (and thus webpages) - * - connections from pages in this extension - * - connections from workers in this extension - * - * This does not support - * - connections from a script back to itself - * - * In the future we may want to support - * - connections directly from webpages - * - connections from native applications - * - connections from other extensions - * - * If you are connecting from the same worker running this script (currently, - * service-to-service communication) you cannot make a `chrome.runtime.connect` - * call that activates this manager, and you should use normal DOM messaging. - */ - -export class CRSessionManager { - private static singleton?: CRSessionManager; - private sessions = new Map(); - - private constructor( - private prefix: string, - private handler: ChannelHandlerFn, - ) { - if (CRSessionManager.singleton) throw new Error('Already constructed'); - chrome.runtime.onConnect.addListener(this.transportConnection); - } - - /** - * - * @param prefix a string containing no spaces, matching the prefix used in your content script - * @param handler your router entry function - */ - public static init = (prefix: string, handler: ChannelHandlerFn) => { - CRSessionManager.singleton ??= new CRSessionManager(prefix, handler); - }; - - /** - * This handler is called when a new connection is opened from any document - * with access to the chrome runtime. - * - * Here we make an effort to identify these connections. If the name indicates - * the connection is for this manager, a handler is connected to the port. - */ - private transportConnection = (port: chrome.runtime.Port) => { - // require an identified origin - const sender = port.sender; - if (!sender?.origin) return; - - // fast and simple name test, parse later - if (!port.name.startsWith(this.prefix)) return; - - // origin restrictions - const fromThisExtension = sender.id === chrome.runtime.id; - // frameId == 0 for top-level documents - const fromPageHttps = !sender.frameId && sender.tab?.id && sender.origin.startsWith('https://'); - if (!(fromThisExtension || fromPageHttps)) return; - - // parse the name - const { label: channelLabel, uuid: clientId } = - parseConnectionName(this.prefix, port.name) ?? {}; - if (channelLabel !== ChannelLabel.TRANSPORT || !clientId) return; - - if (this.sessions.has(clientId)) throw new Error(`Session collision: ${clientId}`); - const session = { - clientId, - acont: new AbortController(), - origin: sender.origin, - port: port, - }; - this.sessions.set(clientId, session); - - session.acont.signal.addEventListener('abort', () => port.disconnect()); - port.onDisconnect.addListener(() => session.acont.abort('Disconnect')); - - port.onMessage.addListener((i, p) => { - void (async () => { - try { - if (isTransportMessage(i)) { - p.postMessage(await this.clientMessageHandler(session.acont.signal, i)); - } else if (isTransportInitChannel(i)) { - console.warn('Client streaming unimplemented', this.acceptChannelStreamRequest(i)); - } else { - console.warn('Unknown item in transport', i); - } - } catch (e) { - session.acont.abort(e); - } - })(); - }); - }; - - /** - * This method enters the router, and returns a response. - * - * It expects a single message, so only supports unary requests and - * server-streaming requests. This should *always successfully return* a - * `TransportEvent`, containing json representing a response or json - * representing an error. - */ - private clientMessageHandler( - signal: AbortSignal, - { requestId, message }: TransportMessage, - ): Promise { - return this.handler(message) - .then(response => - response instanceof ReadableStream - ? this.responseChannelStream(signal, { - requestId, - stream: response as unknown, - } as TransportStream) - : ({ requestId, message: response as unknown } as TransportEvent), - ) - .catch((error: unknown) => ({ - requestId, - error: errorToJson(ConnectError.from(error), undefined), - })); - } - - /** - * Streams are not jsonifiable, so this function sinks a response stream - * into a dedicated chrome runtime channel, for reconstruction by the - * client. - * - * A jsonifiable message identifying a unique connection name is returned - * and should be transported to the client. The client should open a - * connection bearing this name to source the stream. - * - * TODO: time out if the client fails to initiate a connection - */ - private responseChannelStream( - signal: AbortSignal, - { requestId, stream }: TransportStream, - ): TransportInitChannel { - const channel = nameConnection(this.prefix, ChannelLabel.STREAM); - const sinkListener = (p: chrome.runtime.Port) => { - if (p.name !== channel) return; - chrome.runtime.onConnect.removeListener(sinkListener); - void stream.pipeTo(new WritableStream(new PortStreamSink(p)), { signal }).catch(() => null); - }; - chrome.runtime.onConnect.addListener(sinkListener); - return { requestId, channel }; - } - - private acceptChannelStreamRequest = ({ - requestId, - channel: name, - }: TransportInitChannel): TransportStream => ({ - requestId, - stream: new ReadableStream(new PortStreamSource(chrome.runtime.connect({ name }))), - }); -} diff --git a/packages/transport-chrome/src/stream.ts b/packages/transport-chrome/src/stream.ts deleted file mode 100644 index aeb0a7e0..00000000 --- a/packages/transport-chrome/src/stream.ts +++ /dev/null @@ -1,93 +0,0 @@ -/** - * @see https://developer.mozilla.org/en-US/docs/Web/API/Streams_API - * - * This source and sink provide a way to stream json through the chrome runtime. - */ - -import type { JsonValue } from '@bufbuild/protobuf'; -import { Code, ConnectError } from '@connectrpc/connect'; -import { errorFromJson, errorToJson } from '@connectrpc/connect/protocol-connect'; - -export class PortStreamSource implements UnderlyingDefaultSource { - constructor(private incoming: chrome.runtime.Port) {} - - // A port can't pull like a normal source, so handlers are attached at start - start(cont: ReadableStreamDefaultController) { - this.incoming.onDisconnect.addListener(port => - cont.error(new ConnectError('Source disconnected', Code.Aborted, undefined, undefined, port)), - ); - this.incoming.onMessage.addListener(chunk => { - if (isStreamAbort(chunk)) - cont.error(errorFromJson(chunk.abort, undefined, ConnectError.from(chunk.abort))); - else if (isStreamValue(chunk)) cont.enqueue(chunk.value); - else if (isStreamEnd(chunk)) { - this.incoming.disconnect(); - cont.close(); - } else - cont.error( - new ConnectError( - 'Unexpected subchannel transport', - Code.Unimplemented, - undefined, - undefined, - chunk, - ), - ); - }); - } - - cancel() { - this.incoming.disconnect(); - } -} - -export class PortStreamSink implements UnderlyingSink { - /** - * @param outgoing port to write to - * @param reasonToJson abort reason to jsonifiable - */ - constructor(private outgoing: chrome.runtime.Port) {} - - write(chunk: JsonValue) { - this.outgoing.postMessage({ - value: chunk, - } satisfies StreamValue); - } - - close() { - this.outgoing.postMessage({ - done: true, - } satisfies StreamEnd); - this.outgoing.disconnect(); - } - - abort(reason?: unknown) { - this.outgoing.postMessage({ - abort: errorToJson(ConnectError.from(reason), undefined), - } satisfies StreamAbort); - this.outgoing.disconnect(); - } -} - -// control message types below - -interface StreamValue { - value: JsonValue; -} - -interface StreamEnd { - done: true; -} - -interface StreamAbort { - abort: JsonValue; -} - -const isStreamValue = (s: unknown): s is StreamValue => - s != null && typeof s === 'object' && 'value' in s; - -const isStreamEnd = (s: unknown): s is StreamEnd => - s != null && typeof s === 'object' && 'done' in s && s.done === true; - -const isStreamAbort = (s: unknown): s is StreamAbort => - s != null && typeof s === 'object' && 'abort' in s; diff --git a/packages/transport-chrome/tsconfig.json b/packages/transport-chrome/tsconfig.json deleted file mode 100644 index 61a00fa2..00000000 --- a/packages/transport-chrome/tsconfig.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "extends": "tsconfig/base.json", - "include": ["."], - "exclude": ["node_modules"] -} diff --git a/packages/transport-dom/CHANGELOG.md b/packages/transport-dom/CHANGELOG.md deleted file mode 100644 index 5c12dd96..00000000 --- a/packages/transport-dom/CHANGELOG.md +++ /dev/null @@ -1,43 +0,0 @@ -# @penumbra-zone/transport-dom - -## 6.0.0 - -### Major Changes - -- 8fe4de6: correct ordering of default export - -## 5.0.0 - -### Major Changes - -- 8b121ec: change package exports to use 'default' field - -## 4.1.0 - -### Minor Changes - -- 3ea1e6c: update buf types dependencies - -## 4.0.0 - -### Major Changes - -- fc500af: correctly build transport-dom - -## 3.0.0 - -### Major Changes - -- 3148375: remove `/src/` path segment from exports - -## 2.0.0 - -### Major Changes - -- 929d278: barrel imports to facilitate better tree shaking - -## 1.1.0 - -### Minor Changes - -- Initial changest. Git tag v5.0.0 updates. diff --git a/packages/transport-dom/eslint.config.mjs b/packages/transport-dom/eslint.config.mjs deleted file mode 100644 index a53ed8e5..00000000 --- a/packages/transport-dom/eslint.config.mjs +++ /dev/null @@ -1,13 +0,0 @@ -import { penumbraEslintConfig } from '@penumbra-zone/eslint-config'; -import { config, parser } from 'typescript-eslint'; - -export default config({ - ...penumbraEslintConfig, - languageOptions: { - parser, - parserOptions: { - project: true, - tsconfigRootDir: import.meta.dirname, - }, - }, -}); diff --git a/packages/transport-dom/package.json b/packages/transport-dom/package.json deleted file mode 100644 index ef9e2dcd..00000000 --- a/packages/transport-dom/package.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "name": "@penumbra-zone/transport-dom", - "version": "6.0.0", - "private": true, - "license": "(MIT OR Apache-2.0)", - "type": "module", - "scripts": { - "build": "tsc && vite build", - "clean": "rm -rfv dist package penumbra-zone-transport-dom-*.tgz", - "lint": "eslint src", - "prebuild": "$npm_execpath run clean", - "prepack": "$npm_execpath run build", - "test": "vitest run" - }, - "files": [ - "dist" - ], - "exports": { - "./*": "./src/*.ts" - }, - "publishConfig": { - "exports": { - "./*": { - "types": "./dist/*.d.ts", - "default": "./dist/*.js" - } - } - }, - "devDependencies": { - "@buf/connectrpc_eliza.bufbuild_es": "1.9.0-20230913231627-233fca715f49.1", - "@buf/connectrpc_eliza.connectrpc_es": "1.4.0-20230913231627-233fca715f49.2", - "@bufbuild/protobuf": "^1.10.0", - "@connectrpc/connect": "^1.4.0", - "@penumbra-zone/polyfills": "workspace:*" - }, - "peerDependencies": { - "@bufbuild/protobuf": "^1.10.0", - "@connectrpc/connect": "^1.4.0" - } -} diff --git a/packages/transport-dom/src/adapter.ts b/packages/transport-dom/src/adapter.ts deleted file mode 100644 index e0c483c6..00000000 --- a/packages/transport-dom/src/adapter.ts +++ /dev/null @@ -1,210 +0,0 @@ -import { - Code as ConnectErrorCode, - ConnectError, - ConnectRouter, - ConnectRouterOptions, - ContextValues, - createConnectRouter, - StreamResponse, - UnaryResponse, -} from '@connectrpc/connect'; -import { - Any, - JsonReadOptions, - JsonValue, - JsonWriteOptions, - MethodInfo, - MethodKind, - ServiceType, -} from '@bufbuild/protobuf'; -import { - CommonTransportOptions, - createAsyncIterable, - createUniversalHandlerClient, - UniversalHandler, - UniversalHandlerFn, - UniversalServerRequest, -} from '@connectrpc/connect/protocol'; -import { createTransport } from '@connectrpc/connect/protocol-connect'; -import { MessageToJson } from './stream'; -import ReadableStream from '@penumbra-zone/polyfills/ReadableStream.from'; - -// see https://github.com/connectrpc/connect-es/pull/925 -// hopefully also simplifies transport call soon -type MethodType = MethodInfo & { service: { typeName: string } }; - -type ChannelRequest = JsonValue; -type ChannelResponse = JsonValue | ReadableStream; - -export type ChannelHandlerFn = (r: ChannelRequest) => Promise; -export type ChannelContextFn = ( - h: UniversalServerRequest, -) => Promise; - -export interface ChannelAdapterOptions { - router?: Omit; - transport?: Omit; - - routes: (router: ConnectRouter) => void; - jsonOptions: Required & Partial; - createRequestContext: ChannelContextFn; -} - -// these 'force' options objects are used to negatively define the options -// available in ChannelAdapter options, and to provide defaults. in -// particular the transportOption httpClient is generated internally, and should -// never be passed as an option. - -const forceRouterOptions = { - connect: true, - grpc: false, - grpcWeb: false, -}; - -// keys of CommonTransportOptions -const forceTransportOptions = { - httpClient: null as never, - baseUrl: 'https://in-memory', - useBinaryFormat: true, - acceptCompression: [], - sendCompression: null, - compressMinBytes: Number.MAX_SAFE_INTEGER, - readMaxBytes: Number.MAX_SAFE_INTEGER, - writeMaxBytes: Number.MAX_SAFE_INTEGER, -}; - -/** - * This creates returns a simple service entry function. - * - * You should provide a context function that creates all the context required - * by the implementations to which you are routing. - * - * The returned handler accepts 'Any'-packed json message requests, hopefully - * annotated with types present in your provided typeRegistry, hopefully mapping - * to endpoints present in your router. - * - * The entry function will respond with a single message or a ReadableStream. - */ -export const connectChannelAdapter = (opt: ChannelAdapterOptions): ChannelHandlerFn => { - const jsonOptions = opt.jsonOptions; - - const routerOpts: ConnectRouterOptions = { - ...opt.router, - ...forceRouterOptions, - }; - - const router = createConnectRouter(routerOpts); - opt.routes(router); - - /** - * We're creating a router transport to provide service entry. Some of this - * is very much like what happens in createRouterTransport, but we can't use - * createRouterTransport because it does not provide any ContextValues to the - * router. - * - * Connectrpc enforces a separation between client-side ContextValues and - * server-side ContextValues, even though they use the same types. You can't - * simply provide contextValues to a client's CallOptions - those are only for - * Interceptors running in your client-side Transport. They won't be forwarded - * to the server. - * - * Server framework adapters are responsible for applying context values to - * the implemenation. Normally, this would be a simple parameter in a call to - * the function connectNodeAdapter. But, we're not using node. - * - * And unfortunately, createUniversalHandlerClient which createRouterTransport - * uses internally doesn't pass a context parameter at all when it calls a - * handler - meaning every HandlerContext has no contextValues. So the only - * way to get context to the implementation is to either createHandlerContext - * yourself and call the Impl directly, or createContextValues yourself and - * call the router directly. - * - * I've chosen to reimplement the simple createRouterTransport, but wrap the - * router's handlers, inserting contextValues into the requests made by the - * UniversalClient. At request time, this kind of context injector only has - * access to data present in the UniversalServerRequest (parameter to - * UniversalHandlerFn). - * - * Ideally, this should happen at a lower level (write our own handler - * factory) but this is less work. - * - * See https://github.com/connectrpc/connect-es/blob/main/packages/connect-node/src/node-universal-handler.ts - */ - const injectRequestContext = createUniversalHandlerClient( - router.handlers.map((handler: UniversalHandler): UniversalHandler => { - // disaggregate the handler into actual function and keyed attributes - const handlerFn = handler as UniversalHandlerFn; - const handlerMeta = Object.fromEntries( - Object.entries(handler) as [keyof UniversalHandler, unknown][], - ) as { [k in keyof UniversalHandler]: UniversalHandler[k] }; - // wrap the handler function to generate and apply context - const wrappedFn: UniversalHandlerFn = req => opt.createRequestContext(req).then(handlerFn); - // replace attributes onto the wrapped handler - return Object.assign(wrappedFn, handlerMeta); - }), - ); - - // TODO: alternatively, we could have the channelClient provide a requestPath - const I_MethodType = new Map( - router.handlers.map(({ method, service }) => [ - method.I.typeName, - { ...method, service: { typeName: service.typeName } }, - ]), - ); - - // TODO: connectrpc interceptors, typically a client feature, likely work here - // with no further effort, but haven't been tested. we could investigate using - // them as service middleware. - // https://connectrpc.com/docs/web/interceptors/ - const transport = createTransport({ - // order matters :) - interceptors: [], - ...opt.transport, - ...forceTransportOptions, - httpClient: injectRequestContext, - }); - - return async function channelHandler(message: ChannelRequest) { - const request = Any.fromJson(message, jsonOptions).unpack(jsonOptions.typeRegistry)!; - const requestType = request.getType(); - - const methodType = I_MethodType.get(requestType.typeName); - if (!methodType) - throw new ConnectError(`Method ${requestType.typeName} not found`, ConnectErrorCode.NotFound); - - let response: UnaryResponse | StreamResponse | undefined; - switch (methodType.kind) { - case MethodKind.Unary: - response = await transport.unary( - // only uses service.typeName, so this cast is ok - methodType.service as ServiceType, - methodType satisfies MethodInfo, - undefined, // TODO abort - undefined, // TODO timeout - undefined, // TODO headers - request, - ); - break; - case MethodKind.ServerStreaming: - response = await transport.stream( - // only uses service.typeName, so this cast is ok - methodType.service as ServiceType, - methodType satisfies MethodInfo, - undefined, // TODO abort - undefined, // TODO timeout - undefined, // TODO headers - createAsyncIterable([request]), - ); - break; - default: - throw new ConnectError( - `Unimplemented method kind ${methodType.kind}`, - ConnectErrorCode.Unimplemented, - ); - } - - if (response.stream) - return ReadableStream.from(response.message).pipeThrough(new MessageToJson(jsonOptions)); - else return Any.pack(response.message).toJson(jsonOptions); - }; -}; diff --git a/packages/transport-dom/src/any-impl.ts b/packages/transport-dom/src/any-impl.ts deleted file mode 100644 index 5f052e54..00000000 --- a/packages/transport-dom/src/any-impl.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { MethodInfo, ServiceType } from '@bufbuild/protobuf'; -import { MethodImpl, ServiceImpl } from '@connectrpc/connect'; - -export type CreateAnyMethodImpl = ( - methodInfo: S['methods'][N], - localName: N, -) => MethodImpl; - -export const makeAnyServiceImpl = ( - service: S, - createMethod: CreateAnyMethodImpl, -): ServiceImpl => { - const impl = {} as ServiceImpl; - let localName: keyof S['methods']; - let methodInfo: MethodInfo & S['methods'][typeof localName]; - for ([localName, methodInfo] of Object.entries(service.methods)) - impl[localName] = createMethod(methodInfo, localName); - return impl; -}; diff --git a/packages/transport-dom/src/create.test.ts b/packages/transport-dom/src/create.test.ts deleted file mode 100644 index 095b8662..00000000 --- a/packages/transport-dom/src/create.test.ts +++ /dev/null @@ -1,207 +0,0 @@ -import { describe, expect, it } from 'vitest'; - -import { createChannelTransport } from './create'; -import { ElizaService } from '@buf/connectrpc_eliza.connectrpc_es/connectrpc/eliza/v1/eliza_connect'; -import { - IntroduceRequest, - SayRequest, - SayResponse, -} from '@buf/connectrpc_eliza.bufbuild_es/connectrpc/eliza/v1/eliza_pb'; -import { createRegistry } from '@bufbuild/protobuf'; -import { TransportMessage } from './messages'; - -import ReadableStream from '@penumbra-zone/polyfills/ReadableStream.from'; -import Array from '@penumbra-zone/polyfills/Array.fromAsync'; - -const typeRegistry = createRegistry(ElizaService); - -describe('createChannelClient', () => { - it('should return a transport', () => { - const { port2 } = new MessageChannel(); - - const transportOptions = { - getPort: () => Promise.resolve(port2), - defaultTimeoutMs: 5000, - jsonOptions: { typeRegistry }, - }; - - const transport = createChannelTransport(transportOptions); - - expect(transport).toBeDefined(); - }); - - it('should send and receive unary messages', async () => { - const { port1, port2 } = new MessageChannel(); - - const transportOptions = { - getPort: () => Promise.resolve(port2), - defaultTimeoutMs: 5000, - jsonOptions: { typeRegistry }, - }; - - const transport = createChannelTransport(transportOptions); - - const input = new SayRequest({ sentence: 'hello' }); - - const unaryRequest = transport.unary( - ElizaService, - ElizaService.methods.say, - undefined, - undefined, - undefined, - input, - ); - - const otherEnd = new Promise((resolve, reject) => { - port1.onmessage = (event: MessageEvent) => { - try { - const { requestId, message } = event.data as TransportMessage; - - expect(requestId).toBeTypeOf('string'); - expect(message).toMatchObject({ - sentence: 'hello', - '@type': 'type.googleapis.com/connectrpc.eliza.v1.SayRequest', - }); - - port1.postMessage({ - requestId, - message: { - sentence: 'world', - '@type': 'type.googleapis.com/connectrpc.eliza.v1.SayResponse', - }, - }); - - resolve(true); - } catch (e) { - // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors - reject(e); - } - }; - }); - - await expect(otherEnd).resolves.toBe(true); - - await expect(unaryRequest).resolves.toBeTruthy(); - const { message: unaryResponse } = await unaryRequest; - expect(new SayResponse({ sentence: 'world' }).equals(unaryResponse)).toBeTruthy(); - }); - - it('should send and receive streaming requests', async () => { - const { port1, port2 } = new MessageChannel(); - const transportOptions = { - getPort: () => Promise.resolve(port2), - defaultTimeoutMs: 5000, - jsonOptions: { typeRegistry }, - }; - - const transport = createChannelTransport(transportOptions); - - const input = new IntroduceRequest({ name: 'Prax' }); - - const streamRequest = transport.stream( - ElizaService, - ElizaService.methods.introduce, - undefined, - undefined, - undefined, - ReadableStream.from([input]), - ); - - const otherEnd = new Promise((resolve, reject) => { - port1.onmessage = (event: MessageEvent) => { - try { - const { requestId, message } = event.data as TransportMessage; - - expect(requestId).toBeTypeOf('string'); - expect(message).toMatchObject({ - name: 'Prax', - '@type': 'type.googleapis.com/connectrpc.eliza.v1.IntroduceRequest', - }); - - const stream = ReadableStream.from([ - { - sentence: 'Yo', - '@type': 'type.googleapis.com/connectrpc.eliza.v1.IntroduceResponse', - }, - { - sentence: 'This', - '@type': 'type.googleapis.com/connectrpc.eliza.v1.IntroduceResponse', - }, - { - sentence: 'Streams', - '@type': 'type.googleapis.com/connectrpc.eliza.v1.IntroduceResponse', - }, - ]); - - port1.postMessage( - { - requestId, - stream, - }, - [stream], - ); - - resolve(true); - } catch (e) { - // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors - reject(e); - } - }; - }); - - await expect(otherEnd).resolves.toBe(true); - - await expect(streamRequest).resolves.toMatchObject({ stream: true }); - const { message: streamResponse } = await streamRequest; - - const res = Array.fromAsync(streamResponse); - await expect(res).resolves.toBeTruthy(); - }); - - it('should require streaming requests to contain at least one message', async () => { - const { port2 } = new MessageChannel(); - const transportOptions = { - getPort: () => Promise.resolve(port2), - defaultTimeoutMs: 5000, - jsonOptions: { typeRegistry }, - }; - - const transport = createChannelTransport(transportOptions); - - const streamRequest = transport.stream( - ElizaService, - ElizaService.methods.introduce, - undefined, - undefined, - undefined, - // eslint-disable-next-line @typescript-eslint/no-empty-function - (async function* () {})(), - ); - - await expect(streamRequest).rejects.toThrow(); - }); - - it('should require server-streaming requests to contain only one message', async () => { - const { port2 } = new MessageChannel(); - const transportOptions = { - getPort: () => Promise.resolve(port2), - defaultTimeoutMs: 5000, - jsonOptions: { typeRegistry }, - }; - - const transport = createChannelTransport(transportOptions); - - const input = new IntroduceRequest({ name: 'Prax' }); - - const streamRequest = transport.stream( - ElizaService, - ElizaService.methods.introduce, - undefined, - undefined, - undefined, - ReadableStream.from([input, input]), - ); - - await expect(streamRequest).rejects.toThrow(); - }); -}); diff --git a/packages/transport-dom/src/create.ts b/packages/transport-dom/src/create.ts deleted file mode 100644 index 879f2e55..00000000 --- a/packages/transport-dom/src/create.ts +++ /dev/null @@ -1,213 +0,0 @@ -import { - Any, - AnyMessage, - JsonReadOptions, - type JsonValue, - JsonWriteOptions, - Message, - MethodInfo, - MethodKind, - PartialMessage, - ServiceType, -} from '@bufbuild/protobuf'; -import { Code, ConnectError, StreamResponse, UnaryResponse } from '@connectrpc/connect'; -import { CommonTransportOptions } from '@connectrpc/connect/protocol'; -import { errorFromJson } from '@connectrpc/connect/protocol-connect'; -import { - isTransportError, - isTransportEvent, - isTransportMessage, - isTransportStream, - TransportEvent, - TransportMessage, - TransportStream, -} from './messages'; - -import '@penumbra-zone/polyfills/ReadableStream[Symbol.asyncIterator]'; -import ReadableStream from '@penumbra-zone/polyfills/ReadableStream.from'; - -const forceTransportOptions = { - httpClient: null as never, - baseUrl: 'https://in-memory', - useBinaryFormat: false, - acceptCompression: [], - sendCompression: null, - compressMinBytes: Number.MAX_SAFE_INTEGER, - readMaxBytes: Number.MAX_SAFE_INTEGER, - writeMaxBytes: Number.MAX_SAFE_INTEGER, - interceptors: [], -}; - -export interface ChannelTransportOptions - extends Omit { - jsonOptions?: CommonTransportOptions['jsonOptions'] & { - typeRegistry: NonNullable<(JsonReadOptions & JsonWriteOptions)['typeRegistry']>; - }; - getPort: () => PromiseLike; -} - -export const createChannelTransport = ({ - getPort, - jsonOptions, - defaultTimeoutMs = 10_000, -}: ChannelTransportOptions) => { - const pending = new Map void>(); - - // this is used to recover errors that couldn't be thrown at a caller - const listenerError = Promise.withResolvers(); - - // port returned by the penumbra global - let port: MessagePort | undefined; - - /** - * This function is called on the first request. It begins channel init at - * that moment, using the `getPort` function from options. Message listeners - * are attached during this process. Failure will reject the first request. - * - * @returns A promise that resolves when the channel is acquired. - */ - const connect = async () => { - const initTimeout = new Promise( - (_, reject) => - defaultTimeoutMs && - setTimeout( - reject, - defaultTimeoutMs, - new ConnectError('Channel connection request timed out', Code.Unavailable), - ), - ); - - const gotPort = await Promise.race([getPort(), initTimeout]); - - gotPort.addEventListener('message', transportListener); - gotPort.start(); - - return gotPort; - }; - - const transportListener = ({ data }: MessageEvent) => { - if (isTransportEvent(data)) { - // this is a response to a specific request. the port may be shared, so it - // may contain a requestId we don't know about. the response may be - // successful, or contain an error conveyed only to the caller. - const respond = pending.get(data.requestId); - if (respond) respond(data); - } else if (isTransportError(data)) { - // this is a channel-level error, corresponding to no specific request. - // this will fail this transport, and every client using this transport. - // every transport sharing this port will fail independently. - listenerError.reject( - errorFromJson(data.error, data.metadata, new ConnectError('Transport failed')), - ); - } else - listenerError.reject( - new ConnectError( - 'Unknown item in transport', - Code.Unimplemented, - undefined, - undefined, - data, - ), - ); - }; - - return { - async unary = AnyMessage, O extends Message = AnyMessage>( - service: ServiceType, - method: MethodInfo, - _signal: AbortSignal | undefined, // TODO - _timeoutMs: number | undefined, // TODO - header: HeadersInit | undefined, - input: PartialMessage, - ): Promise> { - port ??= await connect(); - - const requestId = crypto.randomUUID(); - const { promise: response, resolve, reject } = Promise.withResolvers(); - pending.set(requestId, (tev: TransportEvent) => { - if (isTransportMessage(tev, requestId)) resolve(tev); - else if (isTransportError(tev)) - reject(errorFromJson(tev.error, tev.metadata, new ConnectError('Unary failed'))); - else reject(ConnectError.from(tev)); - }); - - const message = Any.pack(new method.I(input)).toJson(jsonOptions); - port.postMessage({ requestId, message, header }); - - const success = Promise.race([response, listenerError.promise]); - - return { - service, - method, - stream: false, - header: new Headers((await success).header), - trailer: new Headers((await success).trailer), - message: await success.then(({ message }) => { - const o = new method.O(); - Any.fromJson(message, jsonOptions).unpackTo(o); - return o; - }), - }; - }, - - async stream = AnyMessage, O extends Message = AnyMessage>( - service: ServiceType, - method: MethodInfo, - _signal: AbortSignal | undefined, // TODO - _timeoutMs: number | undefined, // TODO - header: HeadersInit | undefined, - input: AsyncIterable>, - ): Promise> { - port ??= await connect(); - - const requestId = crypto.randomUUID(); - const { promise: response, resolve, reject } = Promise.withResolvers(); - pending.set(requestId, (tev: TransportEvent) => { - if (isTransportStream(tev, requestId)) resolve(tev); - else if (isTransportError(tev)) - reject(errorFromJson(tev.error, tev.metadata, new ConnectError('Stream failed'))); - else reject(ConnectError.from(tev)); - }); - - if (method.kind === MethodKind.ServerStreaming) { - const iter = input[Symbol.asyncIterator](); - const [{ value } = { value: null }, { done }] = [await iter.next(), await iter.next()]; - if (done && typeof value === 'object' && value != null) { - const message = Any.pack(new method.I(value as object)).toJson(jsonOptions); - port.postMessage({ requestId, message, header } satisfies TransportMessage); - } else - throw new ConnectError( - 'MethodKind.ServerStreaming expects a single request message', - Code.OutOfRange, - ); - } else { - const stream: ReadableStream = ReadableStream.from(input).pipeThrough( - new TransformStream({ - transform: (chunk: PartialMessage, cont) => - cont.enqueue(Any.pack(new method.I(chunk)).toJson(jsonOptions)), - }), - ); - port.postMessage({ requestId, stream, header } satisfies TransportStream, [stream]); - } - - const success = await Promise.race([response, listenerError.promise]); - - return { - service, - method, - stream: true, - header: new Headers(success.header), - trailer: new Headers(success.trailer), - message: success.stream.pipeThrough( - new TransformStream({ - transform: (chunk, cont) => { - const o = new method.O(); - Any.fromJson(chunk, jsonOptions).unpackTo(o); - cont.enqueue(o); - }, - }), - ), - }; - }, - }; -}; diff --git a/packages/transport-dom/src/direct.ts b/packages/transport-dom/src/direct.ts deleted file mode 100644 index 4cad526a..00000000 --- a/packages/transport-dom/src/direct.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { - TransportEvent, - TransportMessage, - isTransportMessage, - isTransportStream, -} from './messages'; -import { ConnectError, createPromiseClient } from '@connectrpc/connect'; -import { errorToJson } from '@connectrpc/connect/protocol-connect'; -import { ChannelHandlerFn } from './adapter'; -import { JsonReadOptions, JsonWriteOptions, ServiceType } from '@bufbuild/protobuf'; -import { ChannelTransportOptions, createChannelTransport } from './create'; - -/** - * This creates a port for a channelTransport to enter a router, when provided - * the handler entry function. - * - * The returned function satisfies the `getPort` parameter required by - * `createChannelTransport`. - * - * @param entry router entry function - * @returns a getPort parameter for createChannelTransport - */ - -const directGetPort = - (entry: ChannelHandlerFn, jsonOptions?: Partial & Partial) => - (): Promise => { - const { port1: servicePort, port2: clientPort } = new MessageChannel(); - - // straight-pipe connection, no conditions or transformations - const directEntryHandler = async ({ requestId, message }: TransportMessage) => { - const transportResponse: TransportEvent = await entry(message).then( - response => - response instanceof ReadableStream - ? { requestId, stream: response } - : { requestId, message: response }, - error => ({ - requestId, - error: errorToJson(ConnectError.from(error), jsonOptions), - }), - ); - servicePort.postMessage( - transportResponse, - isTransportStream(transportResponse) ? [transportResponse.stream] : [], - ); - }; - - // TODO: this only supports unary requests - servicePort.addEventListener('message', (ev: MessageEvent) => { - if (isTransportMessage(ev.data)) void directEntryHandler(ev.data); - else console.error('Unknown message event', ev); - }); - - // open the port - servicePort.start(); - - // provide client port to the caller - return Promise.resolve(clientPort); - }; - -/** - * Creates a client for a router that you have the entry function for. This is - * only useful if you are hosting services and talking to those services in the - * same script. - */ -export const createDirectClient = ( - serviceType: S, - entry: ChannelHandlerFn, - transportOptions: Omit, -) => - createPromiseClient( - serviceType, - createChannelTransport({ - ...transportOptions, - getPort: directGetPort(entry, transportOptions.jsonOptions), - }), - ); diff --git a/packages/transport-dom/src/messages.ts b/packages/transport-dom/src/messages.ts deleted file mode 100644 index 1b200db6..00000000 --- a/packages/transport-dom/src/messages.ts +++ /dev/null @@ -1,51 +0,0 @@ -import type { JsonValue } from '@bufbuild/protobuf'; - -// transport meta - -export interface TransportError extends Partial { - error: JsonValue; - metadata?: HeadersInit; -} - -// transport content - -export type TransportData = TransportMessage | TransportStream; - -export interface TransportEvent { - requestId: I; - header?: HeadersInit; - trailer?: HeadersInit; - //contextValues?: object; -} - -export interface TransportMessage extends TransportEvent { - message: JsonValue; -} - -// in-channel stream -export interface TransportStream extends TransportEvent { - stream: ReadableStream; -} - -// guards - -const isObj = (o: unknown): o is object => typeof o === 'object' && o !== null; - -export const isTransportError = (e: unknown): e is TransportError => isObj(e) && 'error' in e; - -export const isTransportData = (t: unknown): t is TransportData => - isTransportMessage(t) || isTransportStream(t); - -export const isTransportEvent = (t: unknown, id?: I): t is TransportEvent => - isObj(t) && - 'requestId' in t && - typeof t.requestId === 'string' && - (id ? t.requestId === id : true); - -export const isTransportMessage = ( - m: unknown, - id?: I, -): m is TransportMessage => isTransportEvent(m, id) && 'message' in m; - -export const isTransportStream = (s: unknown, id?: I): s is TransportStream => - isTransportEvent(s, id) && 'stream' in s && s.stream instanceof ReadableStream; diff --git a/packages/transport-dom/src/proxy.ts b/packages/transport-dom/src/proxy.ts deleted file mode 100644 index 419d19d0..00000000 --- a/packages/transport-dom/src/proxy.ts +++ /dev/null @@ -1,81 +0,0 @@ -import type { ServiceType } from '@bufbuild/protobuf'; -import type { - CallOptions, - HandlerContext, - MethodImpl, - PromiseClient, - ServiceImpl, -} from '@connectrpc/connect'; -import { CreateAnyMethodImpl, makeAnyServiceImpl } from './any-impl'; - -export type ProxyContextHandler = (i: I, ctx: HandlerContext) => [I, CallOptions]; - -/** - * ConnectRPC expects hosts to use context values to convey non-request data and - * interfaces. Every implementation likely needs context if it's more complex - * than a simple pure function. - * - * If you're proxying a remote service, the context is all on the remote server, - * and handled there. If you're mutating the request or response, you may have - * your own implementation 'between' the client and the server, and that - * implementation may require context. - * - * This stub handler is used by default if no other is provided. It logs a - * warning to encourage the developer to be aware of the context feature, and - * provide a handler if necessary, or replace this one with a silent stub. - */ -export const defaultContextHandler: ProxyContextHandler = (i, ctx) => { - console.warn( - "You didn't provide a context handler. If you don't need to use context, you might want to use noContextHandler.", - ctx, - ); - return [i, {}]; -}; - -export const noContextHandler: ProxyContextHandler = i => [i, {}]; - -/** - * This simple context handler forwards basic context like abort controllers, - * headers, and timeout to the proxied client. This is not likely to be very - * useful but is a good starting point if you are going to implement your own. - */ -export const simpleContextHandler: ProxyContextHandler = (i, ctx) => { - const opt = { - contextValues: ctx.values, - signal: ctx.signal, - headers: ctx.requestHeader, - timeoutMs: ctx.timeoutMs(), - } as CallOptions; - return [i, opt]; -}; - -/** - * Creates a proxy implementation of a service, suitable for hosting in a - * ConnectRouter, from a given service type definition and a matching client to - * some other host of the service. - * - * To do this, it iterates over each method in the service type definition, - * creating a method on the proxy impl that calls the provided client. - * - * You can provide a contextHandler function to modify any request or the - * client-side contextValues of any request. - * - * The optional makePartialServiceImpl parameter can be provided to override the - * generated proxy methods with your own implementations. - */ -export const createProxyImpl = ( - service: S, - client: PromiseClient, - contextHandler = defaultContextHandler, - makePartialServiceImpl?: (c: PromiseClient) => Partial>, -) => { - const makeAnyProxyMethod: CreateAnyMethodImpl = (method, localName) => { - const clientMethod = client[localName] as (cI: unknown, cOpt: CallOptions) => unknown; - const impl = (hI: unknown, hCtx: HandlerContext) => clientMethod(...contextHandler(hI, hCtx)); - return impl as MethodImpl; - }; - return { - ...makeAnyServiceImpl(service, makeAnyProxyMethod), - ...makePartialServiceImpl?.(client), - }; -}; diff --git a/packages/transport-dom/src/stream.test.ts b/packages/transport-dom/src/stream.test.ts deleted file mode 100644 index d5fce034..00000000 --- a/packages/transport-dom/src/stream.test.ts +++ /dev/null @@ -1,174 +0,0 @@ -import { describe, expect, test } from 'vitest'; -import { JsonToMessage, MessageToJson } from './stream'; -import { createRegistry, Message, proto3 } from '@bufbuild/protobuf'; - -import ReadableStream from '@penumbra-zone/polyfills/ReadableStream.from'; - -import { ElizaService } from '@buf/connectrpc_eliza.connectrpc_es/connectrpc/eliza/v1/eliza_connect'; -import { SayRequest } from '@buf/connectrpc_eliza.bufbuild_es/connectrpc/eliza/v1/eliza_pb'; - -const typeRegistry = createRegistry(ElizaService); - -describe('Stream Transformers', () => { - describe('JsonToMessage', () => { - test('transforms JSON value to Appropriate Message', async () => { - const jsonOptions = { typeRegistry, ignoreUnknownFields: true }; - const jsonToMessage = new JsonToMessage(jsonOptions); - - const sayReqs = [ - new SayRequest({ sentence: "Let's see" }), - new SayRequest({ sentence: 'Well, nevertheless...' }), - new SayRequest({ sentence: 'Goodbye Cool World' }), - ]; - - const jsonReqs = [ - { '@type': 'connectrpc.eliza.v1.SayRequest', sentence: "Let's see" }, - { '@type': 'connectrpc.eliza.v1.SayRequest', sentence: 'Well, nevertheless...' }, - { '@type': 'connectrpc.eliza.v1.SayRequest', sentence: 'Goodbye Cool World' }, - ]; - - const sayStream = ReadableStream.from(jsonReqs).pipeThrough(jsonToMessage); - - const reader = sayStream.getReader(); - - expect(await reader.read()).toEqual({ value: sayReqs[0], done: false }); - expect(await reader.read()).toEqual({ value: sayReqs[1], done: false }); - expect(await reader.read()).toEqual({ value: sayReqs[2], done: false }); - expect(await reader.read()).toEqual({ value: undefined, done: true }); - }); - - test('throws on invalid message', async () => { - const jsonOptions = { typeRegistry, ignoreUnknownFields: true }; - const jsonToMessage = new JsonToMessage(jsonOptions); - - const invalidJson = { '@type': 'connectrpc.eliza.v1.SayRequest', sentence: 42 }; - - const invalidStream = ReadableStream.from([invalidJson]).pipeThrough(jsonToMessage); - - const reader = invalidStream.getReader(); - - await expect(reader.read()).rejects.toThrowError( - 'cannot decode field connectrpc.eliza.v1.SayRequest.sentence from JSON: 42', - ); - }); - - test('throws on unknown type', async () => { - const jsonOptions = { typeRegistry, ignoreUnknownFields: true }; - const jsonToMessage = new JsonToMessage(jsonOptions); - - const unknownJson = { '@type': 'connectrpc.eliza.v1.Unknown', sentence: 'Hello' }; - - const unknownStream = ReadableStream.from([unknownJson]).pipeThrough(jsonToMessage); - - const reader = unknownStream.getReader(); - - await expect(reader.read()).rejects.toThrowError( - 'cannot decode message google.protobuf.Any from JSON: connectrpc.eliza.v1.Unknown is not in the type registry', - ); - }); - - test('throws on unknown field', async () => { - const jsonOptions = { typeRegistry, ignoreUnknownFields: false }; - const jsonToMessage = new JsonToMessage(jsonOptions); - - const extraJson = { - '@type': 'connectrpc.eliza.v1.SayRequest', - sentence: 'Hello', - extra: 42, - }; - - const unknownStream = ReadableStream.from([extraJson]).pipeThrough(jsonToMessage); - - const reader = unknownStream.getReader(); - - await expect(reader.read()).rejects.toThrowError( - 'cannot decode message connectrpc.eliza.v1.SayRequest from JSON: key "extra" is unknown', - ); - }); - - test('ignores unknown field', async () => { - const jsonOptions = { typeRegistry, ignoreUnknownFields: true }; - const jsonToMessage = new JsonToMessage(jsonOptions); - - const extraJson = { - '@type': 'connectrpc.eliza.v1.SayRequest', - sentence: 'Hello', - extra: 42, - }; - - const unknownStream = ReadableStream.from([extraJson]).pipeThrough(jsonToMessage); - - const reader = unknownStream.getReader(); - - await expect(reader.read()).resolves.toEqual({ - value: new SayRequest({ sentence: 'Hello' }), - done: false, - }); - await expect(reader.read()).resolves.toEqual({ value: undefined, done: true }); - }); - }); - - describe('MessageToJson', () => { - test('transforms Message to JSON value', async () => { - const jsonOptions = { typeRegistry }; - const messageToJson = new MessageToJson(jsonOptions); - - const sayReqs = [ - new SayRequest({ sentence: "Let's see" }), - new SayRequest({ sentence: 'Well, nevertheless...' }), - new SayRequest({ sentence: 'Goodbye Cool World' }), - ]; - - const jsonReqs2 = [ - { '@type': 'type.googleapis.com/connectrpc.eliza.v1.SayRequest', sentence: "Let's see" }, - { - '@type': 'type.googleapis.com/connectrpc.eliza.v1.SayRequest', - sentence: 'Well, nevertheless...', - }, - { - '@type': 'type.googleapis.com/connectrpc.eliza.v1.SayRequest', - sentence: 'Goodbye Cool World', - }, - ]; - - const sayStream = ReadableStream.from(sayReqs).pipeThrough(messageToJson); - - const reader = sayStream.getReader(); - - expect(await reader.read()).toEqual({ value: jsonReqs2[0], done: false }); - expect(await reader.read()).toEqual({ value: jsonReqs2[1], done: false }); - expect(await reader.read()).toEqual({ value: jsonReqs2[2], done: false }); - expect(await reader.read()).toEqual({ value: undefined, done: true }); - }); - - test('throws on unknown type', async () => { - const jsonOptions = { typeRegistry }; - const messageToJson = new MessageToJson(jsonOptions); - - interface SomethingElse extends Message { - something: string; - } - const SomethingElse = proto3.makeMessageType( - 'connectrpc.eliza.v1.SomethingElse', - [ - { - no: 1, - name: 'something', - kind: 'scalar', - T: 9 /* ScalarType.STRING */, - }, - ], - ); - - const unknownReq = new SomethingElse({ something: 'else' }); - - const unknownStream = ReadableStream.from([unknownReq]).pipeThrough(messageToJson); - - const reader = unknownStream.getReader(); - - await expect(reader.read()).rejects.toThrowError( - 'cannot encode message google.protobuf.Any to JSON: "type.googleapis.com/connectrpc.eliza.v1.SomethingElse" is not in the type registry', - ); - }); - }); -}); diff --git a/packages/transport-dom/src/stream.ts b/packages/transport-dom/src/stream.ts deleted file mode 100644 index f4f31a9b..00000000 --- a/packages/transport-dom/src/stream.ts +++ /dev/null @@ -1,35 +0,0 @@ -/** - * @see https://developer.mozilla.org/en-US/docs/Web/API/Streams_API - */ - -import { Any, AnyMessage, JsonValue, JsonReadOptions, JsonWriteOptions } from '@bufbuild/protobuf'; - -/** - * Packs a stream of any registered message to json with "@type" annotation. - */ - -export class MessageToJson extends TransformStream { - constructor(jsonOptions: Partial) { - super({ - transform(chunk: AnyMessage, cont: TransformStreamDefaultController) { - const chunkJson = Any.pack(chunk).toJson(jsonOptions); - cont.enqueue(chunkJson); - }, - }); - } -} - -/** - * Unpacks a stream of json with "@type" annotation to any registered message. - */ - -export class JsonToMessage extends TransformStream { - constructor(jsonOptions: Required) { - super({ - transform(chunk: JsonValue, cont: TransformStreamDefaultController) { - const message = Any.fromJson(chunk, jsonOptions).unpack(jsonOptions.typeRegistry); - cont.enqueue(message); - }, - }); - } -} diff --git a/packages/transport-dom/tsconfig.json b/packages/transport-dom/tsconfig.json deleted file mode 100644 index 91f66ac4..00000000 --- a/packages/transport-dom/tsconfig.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": "tsconfig/base.json", - "exclude": ["node_modules", "dist"], - "compilerOptions": { - "outDir": "dist", - "noEmit": true - } -} diff --git a/packages/transport-dom/vite.config.ts b/packages/transport-dom/vite.config.ts deleted file mode 100644 index 191b5db1..00000000 --- a/packages/transport-dom/vite.config.ts +++ /dev/null @@ -1,32 +0,0 @@ -/// - -import { defineConfig } from 'vite'; -import dts from 'vite-plugin-dts'; -import { externalizeDeps } from 'vite-plugin-externalize-deps'; - -export default defineConfig({ - build: { - lib: { - entry: { - adapter: './src/adapter.ts', - impl: './src/any-impl.ts', - create: './src/create.ts', - direct: './src/direct.ts', - messages: './src/messages.ts', - proxy: './src/proxy.ts', - stream: './src/stream.ts', - }, - formats: ['es'], - }, - }, - plugins: [dts({ rollupTypes: true }), externalizeDeps({ except: ['@penumbra-zone/polyfills'] })], - test: { - include: ['**/*.test.ts'], - browser: { - name: 'chromium', - provider: 'playwright', - enabled: true, - headless: true, - }, - }, -}); diff --git a/packages/tsconfig/package.json b/packages/tsconfig/package.json index 01d8aa3f..6f3f3c04 100644 --- a/packages/tsconfig/package.json +++ b/packages/tsconfig/package.json @@ -1,5 +1,5 @@ { - "name": "tsconfig", + "name": "@repo/tsconfig", "version": "1.0.0", "private": true, "license": "(MIT OR Apache-2.0)" diff --git a/packages/types/CHANGELOG.md b/packages/types/CHANGELOG.md deleted file mode 100644 index 540ac8dd..00000000 --- a/packages/types/CHANGELOG.md +++ /dev/null @@ -1,144 +0,0 @@ -# @penumbra-zone/types - -## 7.1.0 - -### Minor Changes - -- ab9d743: decouple service/rpc init -- 282eabf: Click wallet for max amount - -### Patch Changes - -- c8e8d15: Bug fix in getFormattedAmtFromValueView: support known assets without metadata -- Updated dependencies [6b06e04] - - @penumbra-zone/getters@6.1.0 - -## 7.0.1 - -### Patch Changes - -- Updated dependencies [8fe4de6] - - @penumbra-zone/bech32m@5.0.0 - - @penumbra-zone/getters@6.0.0 - -## 7.0.0 - -### Major Changes - -- bb5f621: formatAmount() takes new args - -### Patch Changes - -- Updated dependencies [8b121ec] - - @penumbra-zone/bech32m@4.0.0 - - @penumbra-zone/getters@5.0.0 - -## 6.0.0 - -### Major Changes - -- 029eebb: use service definitions from protobuf collection package - -### Minor Changes - -- 3ea1e6c: update buf types dependencies - -### Patch Changes - -- Updated dependencies [120b654] -- Updated dependencies [3ea1e6c] - - @penumbra-zone/getters@4.1.0 - - @penumbra-zone/bech32m@3.2.0 - -## 5.0.0 - -### Major Changes - -- 8ccaf30: externalize dependencies - -### Patch Changes - -- 146b48d: Support GDAs -- e35c6f7: Deps bumped to latest -- Updated dependencies [146b48d] -- Updated dependencies [8ccaf30] -- Updated dependencies [8ccaf30] -- Updated dependencies [e35c6f7] -- Updated dependencies [cf63b30] -- Updated dependencies [8ccaf30] - - @penumbra-zone/getters@4.0.0 - - @penumbra-zone/bech32m@3.1.1 - -## 4.1.0 - -### Minor Changes - -- v8.0.0 versioning and manifest - -### Patch Changes - -- Updated dependencies - - @penumbra-zone/bech32m@3.1.0 - - @penumbra-zone/getters@3.0.2 - -## 4.0.1 - -### Patch Changes - -- Updated dependencies [8410d2f] - - @penumbra-zone/bech32m@3.0.1 - - @penumbra-zone/getters@3.0.1 - -## 4.0.0 - -### Major Changes - -- 6fb898a: initial release of `@penumbra-zone/protobuf` package containing `typeRegistry`. same removed from `@penumbra-zone/types` - -## 3.0.0 - -### Major Changes - -- 3148375: remove `/src/` path segment from exports - -### Patch Changes - -- Updated dependencies [3148375] -- Updated dependencies [fdd4303] - - @penumbra-zone/constants@4.0.0 - - @penumbra-zone/getters@3.0.0 - - @penumbra-zone/bech32m@3.0.0 - -## 2.0.1 - -### Patch Changes - -- Updated dependencies [862283c] - - @penumbra-zone/constants@3.0.0 - - @penumbra-zone/getters@2.0.1 - -## 2.0.0 - -### Major Changes - -- 929d278: barrel imports to facilitate better tree shaking - -### Patch Changes - -- Updated dependencies [8933117] -- Updated dependencies [929d278] - - @penumbra-zone/constants@2.0.0 - - @penumbra-zone/getters@2.0.0 - - @penumbra-zone/bech32@2.0.0 - -## 1.1.0 - -### Minor Changes - -- Initial changest. Git tag v5.0.0 updates. - -### Patch Changes - -- Updated dependencies - - @penumbra-zone/constants@1.1.0 - - @penumbra-zone/getters@1.1.0 diff --git a/packages/types/eslint.config.mjs b/packages/types/eslint.config.mjs deleted file mode 100644 index a53ed8e5..00000000 --- a/packages/types/eslint.config.mjs +++ /dev/null @@ -1,13 +0,0 @@ -import { penumbraEslintConfig } from '@penumbra-zone/eslint-config'; -import { config, parser } from 'typescript-eslint'; - -export default config({ - ...penumbraEslintConfig, - languageOptions: { - parser, - parserOptions: { - project: true, - tsconfigRootDir: import.meta.dirname, - }, - }, -}); diff --git a/packages/types/package.json b/packages/types/package.json deleted file mode 100644 index 4cf6deda..00000000 --- a/packages/types/package.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "name": "@penumbra-zone/types", - "version": "7.1.0", - "private": true, - "license": "(MIT OR Apache-2.0)", - "type": "module", - "scripts": { - "build": "tsc && vite build", - "clean": "rm -rfv dist", - "lint": "eslint src", - "test": "vitest run" - }, - "files": [ - "dist" - ], - "exports": { - "./*": "./src/*.ts", - "./internal-msg/*": "./src/internal-msg/*.ts" - }, - "publishConfig": { - "exports": { - "./*": "./dist/*.js", - "./internal-msg/*": "./dist/internal-msg/*.js" - } - }, - "dependencies": { - "@penumbra-zone/bech32m": "workspace:*", - "@penumbra-zone/getters": "workspace:*", - "bignumber.js": "^9.1.2", - "idb": "^8.0.0", - "zod": "^3.23.8" - }, - "devDependencies": { - "@buf/cosmos_ibc.bufbuild_es": "1.9.0-20240530142100-ad4444393387.1", - "@buf/penumbra-zone_penumbra.bufbuild_es": "1.9.0-20240528180215-8fe1c79485f8.1", - "@bufbuild/protobuf": "^1.10.0" - }, - "peerDependencies": { - "@buf/cosmos_ibc.bufbuild_es": "1.9.0-20240530142100-ad4444393387.1", - "@buf/penumbra-zone_penumbra.bufbuild_es": "1.9.0-20240528180215-8fe1c79485f8.1", - "@bufbuild/protobuf": "^1.10.0" - } -} diff --git a/packages/types/src/amount.test.ts b/packages/types/src/amount.test.ts deleted file mode 100644 index 19ba5ad2..00000000 --- a/packages/types/src/amount.test.ts +++ /dev/null @@ -1,299 +0,0 @@ -import { describe, expect, it } from 'vitest'; -import { - addAmounts, - divideAmounts, - formatNumber, - fromBaseUnitAmount, - fromString, - fromValueView, - isZero, - joinLoHiAmount, - multiplyAmountByNumber, - subtractAmounts, - toDecimalExchangeRate, -} from './amount'; -import { Amount } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/num/v1/num_pb'; -import { - Metadata, - ValueView, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; - -describe('lohi helpers', () => { - it('fromBaseUnitAmount works', () => { - const result = fromBaseUnitAmount(new Amount({ lo: 1000n, hi: 5n }), 6); - expect(result.toString()).toBe('92233720368547.75908'); - }); - - it('joinLoHiAmount works', () => { - const lo = 18446744073709551615n; - const hi = 18446744073709551615n; - expect(joinLoHiAmount(new Amount({ lo, hi }))).toBe(340282366920938463463374607431768211455n); - }); - - it('fromBaseUnitAmountAndMetadata works for knownAssetId', () => { - const penumbraMetadata = new Metadata({ - display: 'penumbra', - denomUnits: [ - { - denom: 'penumbra', - exponent: 6, - }, - { - denom: 'mpenumbra', - exponent: 3, - }, - { - denom: 'upenumbra', - exponent: 0, - }, - ], - }); - - const result = fromValueView( - new ValueView({ - valueView: { - case: 'knownAssetId', - value: { - amount: { lo: 123456789n, hi: 0n }, - metadata: penumbraMetadata, - }, - }, - }), - ); - - expect(result.toString()).toBe('123.456789'); - }); - - it('fromBaseUnitAmountAndMetadata works for unknownAssetId', () => { - const result = fromValueView( - new ValueView({ - valueView: { - case: 'unknownAssetId', - value: { - amount: { lo: 123456789n, hi: 0n }, - }, - }, - }), - ); - - expect(result.toString()).toBe('123456789'); - }); -}); - -describe('addAmounts', () => { - it('should return an Amount with lo and hi equal to 0 when both inputs are 0', () => { - const a = new Amount({ lo: 0n, hi: 0n }); - const b = new Amount({ lo: 0n, hi: 0n }); - - const result = addAmounts(a, b); - - expect(result.lo).toBe(0n); - expect(result.hi).toBe(0n); - }); - - it('should correctly add two Amounts where there is no carry from lo to hi', () => { - const a = new Amount({ lo: 1n, hi: 1n }); - const b = new Amount({ lo: 2n, hi: 2n }); - - const result = addAmounts(a, b); - - expect(result.lo).toBe(3n); - expect(result.hi).toBe(3n); - }); - - it('should correctly add two Amounts where there is carry from lo to hi', () => { - const a = new Amount({ lo: 18446744073709551615n, hi: 1n }); // max value for a 64-bit integer - const b = new Amount({ lo: 1n, hi: 2n }); - - const result = addAmounts(a, b); - - expect(result.lo).toBe(0n); - expect(result.hi).toBe(4n); - }); - - it('should correctly add two Amounts where hi is at the maximum value', () => { - const a = new Amount({ lo: 0n, hi: 18446744073709551615n }); // max value for a 64-bit integer - const b = new Amount({ lo: 0n, hi: 18446744073709551615n }); // max value for a 64-bit integer - - const result = addAmounts(a, b); - - expect(result.lo).toBe(0n); - expect(result.hi).toBe(36893488147419103230n); // 2*max value for a 64-bit integer - }); - - it('should return an Amount with maximum lo and hi when both inputs are at their maximum values', () => { - const a = new Amount({ - lo: 18446744073709551615n, - hi: 18446744073709551615n, - }); // max value for a 64-bit integer - const b = new Amount({ - lo: 18446744073709551615n, - hi: 18446744073709551615n, - }); // max value for a 64-bit integer - - const result = addAmounts(a, b); - - expect(result.lo).toBe(18446744073709551614n); // max value for a 64-bit integer - 1 - expect(result.hi).toBe(36893488147419103231n); // 2*max value for a 64-bit integer + 1 - }); -}); - -describe('subtractAmounts', () => { - it('should return an Amount with lo and hi equal to 0 when both inputs are 0', () => { - const a = new Amount({ lo: 0n, hi: 0n }); - const b = new Amount({ lo: 0n, hi: 0n }); - - const result = subtractAmounts(a, b); - - expect(result.lo).toBe(0n); - expect(result.hi).toBe(0n); - }); - - it('should correctly subtract two Amounts', () => { - const a = new Amount({ lo: 2n, hi: 2n }); - const b = new Amount({ lo: 1n, hi: 1n }); - - const result = subtractAmounts(a, b); - - expect(result.lo).toBe(1n); - expect(result.hi).toBe(1n); - }); - - it('should throw an error if minuend is less than subtrahend', () => { - const a = new Amount({ lo: 1n, hi: 1n }); - const b = new Amount({ lo: 2n, hi: 2n }); - - expect(() => subtractAmounts(a, b)).toThrow('Amount cannot be negative'); - }); -}); - -describe('divideAmounts', () => { - it('should throw an error when dividing by zero', () => { - const a = new Amount({ lo: 1n, hi: 1n }); - const b = new Amount({ lo: 0n, hi: 0n }); - - expect(() => divideAmounts(a, b)).toThrow('Division by zero'); - }); - - it('should return 0n if dividend is zero', () => { - const a = new Amount({ lo: 0n, hi: 0n }); - const b = new Amount({ lo: 18446744073709551615n, hi: 1n }); - const result = divideAmounts(a, b); - - expect(result.isZero()).toBeTruthy(); - }); - - it('should return a number without fractions when dividing without remainder', () => { - const a = new Amount({ lo: 6n, hi: 0n }); - const b = new Amount({ lo: 2n, hi: 0n }); - const result = divideAmounts(a, b); - - expect(result.toNumber()).toBe(3); - }); - - it('should return a number with specified precision', () => { - const a = new Amount({ lo: 10n, hi: 0n }); - const b = new Amount({ lo: 3n, hi: 0n }); - const result = divideAmounts(a, b); - - expect(result.toFixed(3)).toEqual('3.333'); - }); -}); - -describe('isZero', () => { - it('works with zero amount', () => { - const amount = new Amount({ lo: 0n, hi: 0n }); - expect(isZero(amount)).toBeTruthy(); - }); - - it('works with negatives', () => { - const amount = new Amount({ lo: -13n, hi: 1n }); - expect(isZero(amount)).toBeFalsy(); - }); - - it('detects hi number presence', () => { - const amount = new Amount({ lo: 0n, hi: 1n }); - expect(isZero(amount)).toBeFalsy(); - }); - - it('detects lo number presence', () => { - const amount = new Amount({ lo: 20n, hi: 0n }); - expect(isZero(amount)).toBeFalsy(); - }); -}); - -describe('toDecimalExchangeRate()', () => { - it('correctly expresses the exchange rate as a decimal', () => { - const amount = new Amount({ hi: 0n, lo: 325_000_000n }); - expect(toDecimalExchangeRate(amount)).toBe(3.25); - }); -}); - -describe('multiplyAmountByNumber()', () => { - it('correctly multiplies an amount by a number', () => { - const amount = new Amount({ hi: 0n, lo: 100n }); - - expect(multiplyAmountByNumber(amount, 1.5)).toEqual( - new Amount({ - hi: 0n, - lo: 150n, - }), - ); - }); - - it('rounds when needed, to avoid trying to convert a decimal to a BigInt', () => { - const amount = new Amount({ hi: 0n, lo: 100n }); - - expect(multiplyAmountByNumber(amount, 1.111111111)).toEqual( - new Amount({ - hi: 0n, - lo: 111n, - }), - ); - }); -}); - -describe('formatNumber', () => { - it('formats number with zero precision', () => { - expect(formatNumber(123.456, { precision: 0 })).toBe('123'); - }); - - it('formats number with non-zero precision', () => { - expect(formatNumber(123.456, { precision: 2 })).toBe('123.46'); - }); - - it('handles zero value with non-zero precision', () => { - expect(formatNumber(0, { precision: 2 })).toBe('0'); - }); - - it('removes unnecessary trailing zeros', () => { - expect(formatNumber(123.4, { precision: 3 })).toBe('123.4'); - }); - - it('formats negative number correctly', () => { - expect(formatNumber(-123.456, { precision: 2 })).toBe('-123.46'); - }); -}); - -describe('fromString', () => { - it('converts a string to an amount', () => { - const result = fromString('123456'); - const expected = new Amount({ hi: 0n, lo: 123456n }); - - expect(result.equals(expected)).toBe(true); - }); - - it('handles an exponent', () => { - const result = fromString('123.456', 3); - const expected = new Amount({ hi: 0n, lo: 123456n }); - - expect(result.equals(expected)).toBe(true); - }); - - it('rounds down when the user enters too many decimal places for the given exponent', () => { - const result = fromString('123.456789', 3); - const expected = new Amount({ hi: 0n, lo: 123456n }); - - expect(result.equals(expected)).toBe(true); - }); -}); diff --git a/packages/types/src/amount.ts b/packages/types/src/amount.ts deleted file mode 100644 index ce03c1f6..00000000 --- a/packages/types/src/amount.ts +++ /dev/null @@ -1,130 +0,0 @@ -import { Amount } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/num/v1/num_pb'; -import { fromBaseUnit, joinLoHi, splitLoHi, toBaseUnit } from './lo-hi'; -import { BigNumber } from 'bignumber.js'; -import { ValueView } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; -import { getAmount, getDisplayDenomExponentFromValueView } from '@penumbra-zone/getters/value-view'; - -export const joinLoHiAmount = (amount: Amount): bigint => { - return joinLoHi(amount.lo, amount.hi); -}; - -export const fromBaseUnitAmount = (amount: Amount, exponent = 0): BigNumber => { - return fromBaseUnit(amount.lo, amount.hi, exponent); -}; - -export const isZero = (amount: Amount): boolean => { - return joinLoHiAmount(amount) === 0n; -}; - -export const fromValueView = (valueView: ValueView): BigNumber => { - return fromBaseUnitAmount( - getAmount(valueView), - valueView.valueView.case === 'knownAssetId' - ? getDisplayDenomExponentFromValueView(valueView) - : 0, - ); -}; - -export const fromString = (amount: string, exponent = 0): Amount => - new Amount( - toBaseUnit(BigNumber(amount).decimalPlaces(exponent, BigNumber.ROUND_FLOOR), exponent), - ); - -export const addAmounts = (a: Amount, b: Amount): Amount => { - const joined = joinLoHiAmount(a) + joinLoHiAmount(b); - const { lo, hi } = splitLoHi(joined); - return new Amount({ lo, hi }); -}; - -export const subtractAmounts = (minuend: Amount, subtrahend: Amount): Amount => { - const joinedMinuend = joinLoHiAmount(minuend); - const joinedSubtrahend = joinLoHiAmount(subtrahend); - - if (joinedSubtrahend > joinedMinuend) throw new Error('Amount cannot be negative'); - - const joined = joinedMinuend - joinedSubtrahend; - const { lo, hi } = splitLoHi(joined); - return new Amount({ lo, hi }); -}; - -export const multiplyAmountByNumber = (amount: Amount, multiplier: number): Amount => { - const amountAsBigNumber = new BigNumber(joinLoHiAmount(amount).toString()); - const result = amountAsBigNumber.multipliedBy(multiplier).decimalPlaces(0).toString(10); - const loHi = splitLoHi(BigInt(result)); - - return new Amount(loHi); -}; - -export const divideAmounts = (dividend: Amount, divisor: Amount): BigNumber => { - if (isZero(divisor)) throw new Error('Division by zero'); - - const joinedDividend = new BigNumber(joinLoHiAmount(dividend).toString()); - const joinedDivisor = new BigNumber(joinLoHiAmount(divisor).toString()); - - return joinedDividend.dividedBy(joinedDivisor); -}; - -interface FormatOptions { - precision: number; -} - -export const formatNumber = (number: number, options: FormatOptions): string => { - const { precision } = options; - - // Use toFixed to set the precision and then remove unnecessary trailing zeros - return precision === 0 - ? number.toFixed(precision) - : parseFloat(number.toFixed(precision)).toString(); -}; - -export const removeTrailingZeros = (strNum: string): string => { - return strNum.replace(/(\.\d*?[1-9])0+$|\.0*$/, '$1'); -}; - -export const formatAmount = ({ - amount, - exponent = 0, - commas = false, - decimalPlaces = 6, -}: { - amount: Amount; - exponent?: number; - commas?: boolean; - decimalPlaces?: number; -}) => { - const result = fromBaseUnitAmount(amount, exponent).toFormat(decimalPlaces, { - decimalSeparator: '.', - groupSeparator: commas ? ',' : '', - groupSize: 3, - }); - return removeTrailingZeros(result); -}; - -/** - * Exchange rates in core are expressed as whole numbers on the order of 10 to - * the power of 8, so they need to be divided by 10e8 to turn into a decimal. - * - * @see https://github.com/penumbra-zone/penumbra/blob/839f978/crates/bin/pcli/src/command/view/staked.rs#L90-L93 - */ -const EXCHANGE_RATE_DENOMINATOR = 1e8; - -/** - * Given an amount expressing an exchange rate, returns a decimal representation of - * that exchange rate. This makes it easy to multiply by exchange rates. - * - * For example, an exchange rate of 150_000_000 is 1.5. Thus, - * `toBasisPointsAsDecimal(amount)`, where `amount` is an `Amount` totaling - * `150_000_000n`, will return `1.5`. - */ -export const toDecimalExchangeRate = ( - /** - * An amount expressing basis points -- i.e., one hundredth of one percent. - * - * @see https://en.wikipedia.org/wiki/Basis_point - */ - amount: Amount, -) => { - const joinedDividend = new BigNumber(joinLoHiAmount(amount).toString()); - - return joinedDividend.dividedBy(EXCHANGE_RATE_DENOMINATOR).toNumber(); -}; diff --git a/packages/types/src/assets.test.ts b/packages/types/src/assets.test.ts deleted file mode 100644 index 063cbfcb..00000000 --- a/packages/types/src/assets.test.ts +++ /dev/null @@ -1,177 +0,0 @@ -import { describe, expect, it } from 'vitest'; -import { assetPatterns, getUnbondingStartHeight, RegexMatcher } from './assets'; -import { Metadata } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; - -describe('assetPatterns', () => { - describe('auctionNft', () => { - it('matches when a string is a valid auction NFT', () => { - expect(assetPatterns.auctionNft.matches('auctionnft_0_pauctid1abc123')).toBe(true); - }); - - it('does not match when a string contains, but does not begin with, a valid auction NFT', () => { - expect( - assetPatterns.auctionNft.matches('ibc-transfer/channel-1234/auctionnft_0_pauctid1abc123'), - ).toBe(false); - }); - - it('captures the capture groups correctly', () => { - const result = assetPatterns.auctionNft.capture('auctionnft_0_pauctid1abc123'); - expect(result).toEqual({ auctionId: 'pauctid1abc123', seqNum: '0' }); - }); - }); - - describe('lpNft', () => { - it('matches when a string begins with `lpnft_`', () => { - expect(assetPatterns.lpNft.matches('lpnft_abc123')).toBe(true); - }); - - it('does not match when a string contains, but does not begin with, `lpnft_`', () => { - expect(assetPatterns.lpNft.matches('ibc-transfer/channel-1234/lpnft_abc123')).toBe(false); - }); - }); - - describe('delegationToken', () => { - it('matches when a string is a valid delegation token name', () => { - expect(assetPatterns.delegationToken.matches('delegation_penumbravalid1abc123')).toBe(true); - }); - - it('does not match when a string contains, but does not begin with, a valid delegation token name', () => { - expect( - assetPatterns.delegationToken.matches( - 'ibc-transfer/channel-1234/delegation_penumbravalid1abc123', - ), - ).toBe(false); - }); - }); - - describe('proposalNft', () => { - it('matches when a string begins with `proposal_`', () => { - expect(assetPatterns.proposalNft.matches('proposal_abc123')).toBe(true); - }); - - it('does not match when a string contains, but does not begin with, `proposal_`', () => { - expect(assetPatterns.proposalNft.matches('ibc-transfer/channel-1234/proposal_abc123')).toBe( - false, - ); - }); - }); - - describe('unbondingToken', () => { - it('matches when a string is a valid unbonding token name', () => { - expect( - assetPatterns.unbondingToken.matches('unbonding_start_at_1_penumbravalid1abc123'), - ).toBe(true); - }); - - it('captures the unbonding start height', () => { - const match = assetPatterns.unbondingToken.capture( - 'unbonding_start_at_1_penumbravalid1abc123', - ); - expect(match?.startAt).toBe('1'); - }); - - it('does not match when a string contains, but does not begin with, a valid unbonding token name', () => { - expect( - assetPatterns.unbondingToken.matches( - 'ibc-transfer/channel-1234/unbonding_start_at_1_penumbravalid1abc123', - ), - ).toBe(false); - }); - }); - - describe('votingReceipt', () => { - it('matches when a string begins with `voted_on_`', () => { - expect(assetPatterns.votingReceipt.matches('voted_on_abc123')).toBe(true); - }); - - it('does not match when a string contains, but does not begin with, `voted_on_`', () => { - expect(assetPatterns.votingReceipt.matches('ibc-transfer/channel-1234/voted_on_abc123')).toBe( - false, - ); - }); - }); - - describe('ibc', () => { - it('matches when a string follows the pattern transfer//', () => { - expect(assetPatterns.ibc.matches('transfer/channel-141/uosmo')).toBeTruthy(); - expect(assetPatterns.ibc.matches('transfer/channel-0/upenumbra')).toBeTruthy(); - expect(assetPatterns.ibc.matches('transfer/channel-0/upenumbra/moo/test')).toBeTruthy(); - expect(assetPatterns.ibc.matches('x/channel-0/upenumbra')).toBeFalsy(); - }); - - it('captures channel and denom correctly', () => { - const match = assetPatterns.ibc.capture('transfer/channel-141/uosmo'); - expect(match?.channel).toBe('channel-141'); - expect(match?.denom).toBe('uosmo'); - }); - - it('captures multi-hops', () => { - const match = assetPatterns.ibc.capture('transfer/channel-141/transfer/channel-42/uosmo'); - expect(match?.channel).toBe('channel-141'); - expect(match?.denom).toBe('transfer/channel-42/uosmo'); - }); - }); -}); - -describe('RegexMatcher', () => { - describe('RegexMatcher.matches', () => { - it('should return true when the string matches the regex', () => { - const regex = /^[a-z]+$/; - const matcher = new RegexMatcher(regex); - expect(matcher.matches('abc')).toBe(true); - }); - - it('should return false when the string does not match the regex', () => { - const regex = /^[a-z]+$/; - const matcher = new RegexMatcher(regex); - expect(matcher.matches('123')).toBe(false); - }); - }); - - it('should return undefined if no groups are present', () => { - const regex = /hello/; - const matcher = new RegexMatcher(regex); - // eslint-disable-next-line @typescript-eslint/no-confusing-void-expression - expect(matcher.capture('hello')).toBeUndefined(); - }); - - it('should return undefined if the string does not match', () => { - const regex = /hello/; - const matcher = new RegexMatcher(regex); - // eslint-disable-next-line @typescript-eslint/no-confusing-void-expression - expect(matcher.capture('world')).toBeUndefined(); - }); - - it('should return typed capture groups object if present', () => { - interface GreetingSubjectGroups { - greeting: string; - subject: string; - } - - const regex = /(?hello) (?world)/; - const matcher = new RegexMatcher(regex); - const expected: GreetingSubjectGroups = { - greeting: 'hello', - subject: 'world', - }; - expect(matcher.capture('hello world')).toEqual(expected); - }); -}); - -describe('getUnbondingStartHeight()', () => { - it("gets the unbonding start height, coerced to a `BigInt`, from an unbonding token's asset ID", () => { - const metadata = new Metadata({ display: 'unbonding_start_at_123_penumbravalid1abc123' }); - - expect(getUnbondingStartHeight(metadata)).toBe(123n); - }); - - it("returns `undefined` for a non-unbonding token's metadata", () => { - const metadata = new Metadata({ display: 'penumbra' }); - - expect(getUnbondingStartHeight(metadata)).toBeUndefined(); - }); - - it('returns `undefined` for undefined metadata', () => { - expect(getUnbondingStartHeight(undefined)).toBeUndefined(); - }); -}); diff --git a/packages/types/src/assets.ts b/packages/types/src/assets.ts deleted file mode 100644 index 90da3753..00000000 --- a/packages/types/src/assets.ts +++ /dev/null @@ -1,105 +0,0 @@ -import { Metadata } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; - -// PRICE_RELEVANCE_THRESHOLDS defines how long prices for different asset types remain relevant (in blocks) -// 1 block = 5 seconds, 200 blocks approximately equals 17 minutes -export const PRICE_RELEVANCE_THRESHOLDS = { - delegationToken: 719, - default: 200, -}; - -export interface AuctionNftCaptureGroups { - seqNum: string; - auctionId: string; -} - -export interface IbcCaptureGroups { - channel: string; - denom: string; -} - -export interface DelegationCaptureGroups { - id: string; - idKey: string; -} - -export interface UnbondingCaptureGroups { - startAt: string; - id: string; - idKey: string; -} - -export interface AssetPatterns { - auctionNft: RegexMatcher; - lpNft: RegexMatcher; - delegationToken: RegexMatcher; - proposalNft: RegexMatcher; - unbondingToken: RegexMatcher; - votingReceipt: RegexMatcher; - ibc: RegexMatcher; -} - -export class RegexMatcher { - constructor(private readonly regex: RegExp) {} - - matches(str: string): boolean { - return this.regex.exec(str) !== null; - } - - capture(str: string): T | undefined { - const match = this.regex.exec(str); - if (!match) return undefined; - return match.groups as unknown as T; - } -} - -/** - * Call `.matches()` on these RegExp patterns to test whether a token is of a given type. - * Call `.capture()` to grab the content by its capture groups (if present) - * - * NOTE - SECURITY IMPLICATIONS: These RegExps each assert that the given prefix - * is at the _beginning_ of the string. This ensures that they are - * differentiated from IBC deposits with the same asset name. Penumbra prefixes - * IBC deposit assets with the provenance of the token, so that if someone - * creates a token called, e.g., `delegation_whatever` and sends it to a - * Penumbra user via IBC, it will show up in Penumbra as - * `transfer/channel-1234/delegation_whatever`. Thus, asserting that the - * `delegation_` prefix occurs at the _beginning_ of the string, as we're doing - * below, ensures that it's actually the type we expect it to be. - * - * Source of truth for regex patterns: - * https://github.com/penumbra-zone/penumbra/blob/main/crates/core/asset/src/asset/registry.rs - */ -export const assetPatterns: AssetPatterns = { - auctionNft: new RegexMatcher( - /^auctionnft_(?[0-9]+)_(?pauctid1[a-zA-HJ-NP-Z0-9]+)$/, - ), - lpNft: new RegexMatcher(/^lpnft_/), - delegationToken: new RegexMatcher( - /^delegation_(?penumbravalid1(?[a-zA-HJ-NP-Z0-9]+))$/, - ), - proposalNft: new RegexMatcher(/^proposal_/), - unbondingToken: new RegexMatcher( - /^unbonding_start_at_(?[0-9]+)_(?penumbravalid1(?[a-zA-HJ-NP-Z0-9]+))$/, - ), - votingReceipt: new RegexMatcher(/^voted_on_/), - ibc: new RegexMatcher(/^transfer\/(?channel-\d+)\/(?.*)/), -}; - -/** - * Get the unbonding start height index from the metadata of an unbonding token - * -- that is, the block height at which unbonding started. - * - * For metadata of a non-unbonding token, will return `undefined`. - */ -export const getUnbondingStartHeight = (metadata?: Metadata) => { - if (!metadata) return undefined; - - const unbondingMatch = assetPatterns.unbondingToken.capture(metadata.display); - - if (unbondingMatch) { - const { startAt } = unbondingMatch; - return BigInt(startAt); - } - - return undefined; -}; diff --git a/packages/types/src/base64.test.ts b/packages/types/src/base64.test.ts deleted file mode 100644 index 938840a7..00000000 --- a/packages/types/src/base64.test.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { describe, expect, it } from 'vitest'; - -import { - Base64StringSchema, - base64ToUint8Array, - InnerBase64Schema, - uint8ArrayToBase64, -} from './base64'; -import type { SafeParseError } from 'zod'; - -describe('Base64StringSchema', () => { - it('validates base64 strings', () => { - const validBase64 = 'SGVsbG8gd29ybGQ='; // 'Hello world' in base64 - const result = Base64StringSchema.safeParse(validBase64); - expect(result.success).toBe(true); - }); - - it('rejects non-base64 strings', () => { - const invalidBase64 = 'not a base64 string'; - const result = Base64StringSchema.safeParse(invalidBase64) as SafeParseError; - expect(result.success).toBe(false); - expect(result.error.message.includes('Invalid base64 string')).toBeTruthy(); - }); -}); - -describe('InnerBase64Schema', () => { - it('validates objects with base64 strings', () => { - const validInput = { inner: 'SGVsbG8gd29ybGQ=' }; // 'Hello world' in base64 - const result = InnerBase64Schema.safeParse(validInput); - expect(result.success).toBe(true); - }); - - it('rejects objects without base64 strings', () => { - const invalidInput = { inner: 'not a base64 string' }; - const result = InnerBase64Schema.safeParse(invalidInput) as SafeParseError; - expect(result.success).toBe(false); - expect(result.error.message.includes('Invalid base64 string')).toBeTruthy(); - }); - - it('rejects non-object inputs', () => { - const nonObjectInput = 'not an object'; - const result = InnerBase64Schema.safeParse(nonObjectInput); - expect(result.success).toBe(false); - }); -}); - -describe('base64ToUint8Array', () => { - it('should correctly convert a Base64 string to Uint8Array', () => { - const base64String = 'SGVsbG8gd29ybGQ='; // 'Hello world' in Base64 - const expectedUint8Array = new Uint8Array([ - 72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, - ]); // 'Hello world' in ASCII values - expect(base64ToUint8Array(base64String)).toEqual(expectedUint8Array); - }); - - it('should return an empty Uint8Array for an empty Base64 string', () => { - const base64String = ''; - const expectedUint8Array = new Uint8Array([]); - expect(base64ToUint8Array(base64String)).toEqual(expectedUint8Array); - }); - - it('should handle non-Base64 strings', () => { - const nonBase64String = 'This is not a Base64 string'; - expect(() => base64ToUint8Array(nonBase64String)).toThrow(); - }); -}); - -describe('uint8ArrayToBase64', () => { - it('converts an empty Uint8Array to an empty string', () => { - const byteArray = new Uint8Array(); - const result = uint8ArrayToBase64(byteArray); - expect(result).toBe(''); - }); - - it('correctly converts a Uint8Array to a base64 string', () => { - const byteArray = new Uint8Array([104, 101, 108, 108, 111]); // ASCII for "hello" - const result = uint8ArrayToBase64(byteArray); - expect(result).toBe('aGVsbG8='); // base64 for "hello" - }); - - it('correctly converts a large Uint8Array to a base64 string', () => { - const largeArray = new Uint8Array(1024).fill(97); // 1024 bytes all set to ASCII for "a" - const result = uint8ArrayToBase64(largeArray); - expect(result).toBe(Buffer.from(largeArray).toString('base64')); // compare with Node's built-in conversion - }); -}); diff --git a/packages/types/src/base64.ts b/packages/types/src/base64.ts deleted file mode 100644 index 3c03a60c..00000000 --- a/packages/types/src/base64.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { validateSchema } from './validation'; -import { z } from 'zod'; - -export const Base64StringSchema = z.string().refine( - str => { - // Regular expression that matches base64 strings - const base64Regex = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/; - return base64Regex.test(str); - }, - { - message: 'Invalid base64 string', - }, -); - -export type Base64Str = z.infer; - -export const InnerBase64Schema = z.object({ inner: Base64StringSchema }); - -export const base64ToUint8Array = (base64: string): Uint8Array => { - const validated = validateSchema(Base64StringSchema, base64); - const binString = atob(validated); - return Uint8Array.from(binString, byte => byte.codePointAt(0)!); -}; - -export const uint8ArrayToBase64 = (byteArray: Uint8Array): string => { - const binString = String.fromCodePoint(...byteArray); - return btoa(binString); -}; diff --git a/packages/types/src/block-processor.ts b/packages/types/src/block-processor.ts deleted file mode 100644 index 8288a9fa..00000000 --- a/packages/types/src/block-processor.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { AssetId } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; - -export interface BlockProcessorInterface { - sync(): Promise; - stop(r?: string): void; - setNumeraires(numeraires: AssetId[]): void; -} diff --git a/packages/types/src/box.ts b/packages/types/src/box.ts deleted file mode 100644 index 16eebbb1..00000000 --- a/packages/types/src/box.ts +++ /dev/null @@ -1,26 +0,0 @@ -// Public, stored representation of Box -import { Base64Str, base64ToUint8Array, uint8ArrayToBase64 } from './base64'; - -export interface BoxJson { - nonce: Base64Str; - cipherText: Base64Str; -} - -// Represents the encrypted data -export class Box { - constructor( - readonly nonce: Uint8Array, - readonly cipherText: Uint8Array, - ) {} - - static fromJson(json: BoxJson): Box { - return new Box(base64ToUint8Array(json.nonce), base64ToUint8Array(json.cipherText)); - } - - toJson(): BoxJson { - return { - nonce: uint8ArrayToBase64(this.nonce), - cipherText: uint8ArrayToBase64(this.cipherText), - }; - } -} diff --git a/packages/types/src/environment.ts b/packages/types/src/environment.ts deleted file mode 100644 index a8b8b80b..00000000 --- a/packages/types/src/environment.ts +++ /dev/null @@ -1,55 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unnecessary-condition */ -// Rule disabled so Typescript doesn't complain about unnecessary env checks - -enum Environment { - NODE_DEV, - NODE_PROD, - CHROME_EXT_DEV, - CHROME_EXT_PROD, - BROWSER, - UNKNOWN, -} - -declare global { - interface Window { - // This file has many environments running it. Makes it hard to please every runtime. - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - chrome?: { - runtime?: { - id?: string; - getManifest: () => { update_url?: string }; - }; - }; - } -} - -export const isDevEnv = (): boolean => { - const env = getEnv(); - return env === Environment.CHROME_EXT_DEV || env === Environment.NODE_DEV; -}; - -// Should consider moving this to a package if other consumers need this -const getEnv = (): Environment => { - // Check for Node.js environment - if (globalThis.process?.versions?.node !== null) { - return process.env['NODE_ENV'] === 'production' ? Environment.NODE_PROD : Environment.NODE_DEV; - } - - // Check for Chrome extension environment - else if (globalThis?.window?.chrome?.runtime?.id) { - return !('update_url' in globalThis.window.chrome.runtime.getManifest()) // Unpacked extensions do not have "update_url" field - ? Environment.CHROME_EXT_DEV - : Environment.CHROME_EXT_PROD; - } - - // Check for browser environment - else if (globalThis?.window) { - return Environment.BROWSER; - } - - // If neither node.js, chrome extension, nor browser - else { - return Environment.UNKNOWN; - } -}; diff --git a/packages/types/src/hex.test.ts b/packages/types/src/hex.test.ts deleted file mode 100644 index 03c8164a..00000000 --- a/packages/types/src/hex.test.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { describe, expect, it } from 'vitest'; -import { base64ToHex, hexToBase64, hexToUint8Array, uint8ArrayToHex } from './hex'; - -describe('base64ToHex', () => { - it('should convert base64 string to hexadecimal', () => { - const base64 = 'SGVsbG8gd29ybGQ='; - const expectedHex = '48656c6c6f20776f726c64'; - expect(base64ToHex(base64)).toBe(expectedHex); - }); - - it('should handle empty string', () => { - const base64 = ''; - const expectedHex = ''; - expect(base64ToHex(base64)).toBe(expectedHex); - }); - - it('should throw an error for invalid base64 string', () => { - const base64 = 'not a valid base64 string'; - expect(() => base64ToHex(base64)).toThrow(); - }); -}); - -describe('hexToBase64', () => { - it('should convert hexadecimal string to base64', () => { - const hex = '48656c6c6f20776f726c64'; - const expectedBase64 = 'SGVsbG8gd29ybGQ='; - expect(hexToBase64(hex)).toBe(expectedBase64); - }); - - it('should handle empty string', () => { - const hex = ''; - const expectedBase64 = ''; - expect(hexToBase64(hex)).toBe(expectedBase64); - }); - - it('should throw when passed an invalid hex input', () => { - // Hex input must be in pairs of characters, so a single character is - // invalid. - const hex = 'a'; - expect(() => hexToBase64(hex)).toThrow('Invalid hexadecimal input'); - }); -}); - -describe('uint8ArrayToHex()', () => { - it('Converts Uint8Array to Hex string', () => { - const uint8Array = new Uint8Array([0x00, 0x01, 0x02, 0xfd, 0xfe, 0xff]); - const expectedOutput = '000102fdfeff'; - expect(uint8ArrayToHex(uint8Array)).toEqual(expectedOutput); - }); - - it('Converts empty Uint8Array to an empty string', () => { - const uint8Array = new Uint8Array([]); - const expectedOutput = ''; - expect(uint8ArrayToHex(uint8Array)).toEqual(expectedOutput); - }); - - it('Handles single element Uint8Array', () => { - const uint8Array = new Uint8Array([0xab]); - const expectedOutput = 'ab'; - expect(uint8ArrayToHex(uint8Array)).toEqual(expectedOutput); - }); - - it('Converts Uint8Array with single digit hex numbers correctly', () => { - const uint8Array = new Uint8Array([0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9]); - const expectedOutput = '00010203040506070809'; - expect(uint8ArrayToHex(uint8Array)).toEqual(expectedOutput); - }); -}); - -describe('hexToUint8Array', () => { - it('should convert a hexadecimal string to a Uint8Array', () => { - const hexString = '48656c6c6f20576f726c64'; // Hexadecimal representation of "Hello World" - const expected = new Uint8Array(Buffer.from('Hello World')); - const result = hexToUint8Array(hexString); - expect(result).toEqual(expected); - }); - - it('should handle an empty string', () => { - const hexString = ''; - const expected = new Uint8Array(); - const result = hexToUint8Array(hexString); - expect(result).toEqual(expected); - }); - - it('should throw an error for a non-hexadecimal string', () => { - const nonHexString = 'GHIJK'; - expect(() => hexToUint8Array(nonHexString)).toThrow(); - }); -}); diff --git a/packages/types/src/hex.ts b/packages/types/src/hex.ts deleted file mode 100644 index a47e267d..00000000 --- a/packages/types/src/hex.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { Base64StringSchema } from './base64'; -import { validateSchema } from './validation'; - -/** - * @see https://stackoverflow.com/a/39460727/974981 - */ -export const base64ToHex = (base64: string): string => { - const validated = validateSchema(Base64StringSchema, base64); - const bytes = atob(validated); - - let result = ''; - for (let i = 0; i < bytes.length; i++) { - const hex = bytes.charCodeAt(i).toString(16); - result += hex.length === 2 ? hex : '0' + hex; - } - - return result; -}; - -/** - * @see https://stackoverflow.com/a/41797377/974981 - */ -export const hexToBase64 = (hex: string): string => { - if (!hex) return ''; - - const hexPairs = hex.match(/[0-9A-Fa-f]{2}/g); - if (!hexPairs) throw new Error('Invalid hexadecimal input'); - - const binaryString = hexPairs.map(a => String.fromCharCode(parseInt(a, 16))).join(''); - - return btoa(binaryString); -}; - -/** - * @see https://stackoverflow.com/a/65851423/974981 - */ -export const uint8ArrayToHex = (uint8Array: Uint8Array): string => { - return Array.from(uint8Array, i => i.toString(16).padStart(2, '0')).join(''); -}; - -/** - * @see https://stackoverflow.com/a/65851423/974981 - */ -export const hexToUint8Array = (hexString: string): Uint8Array => { - // Check if the input string is a valid hexadecimal string - if (!/^([0-9A-Fa-f]{2})*$/.test(hexString)) { - throw new Error(`Invalid hexadecimal string: ${hexString}`); - } - - if (!hexString) return new Uint8Array(); - - // Split the string into pairs of characters - const hexPairs = hexString.match(/.{1,2}/g)!; - - // Map each hexadecimal pair to the corresponding integer and create a Uint8Array from it - return new Uint8Array(hexPairs.map(byte => parseInt(byte, 16))); -}; diff --git a/packages/types/src/indexed-db.ts b/packages/types/src/indexed-db.ts deleted file mode 100644 index e4bef3bb..00000000 --- a/packages/types/src/indexed-db.ts +++ /dev/null @@ -1,311 +0,0 @@ -import { DBSchema, StoreKey, StoreNames, StoreValue } from 'idb'; - -import { - ScanBlockResult, - StateCommitmentTree, - StoreCommitment, - StoredPosition, - StoreHash, -} from './state-commitment-tree'; - -import { AppParameters } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/app/v1/app_pb'; -import { - AssetId, - EstimatedPrice, - Metadata, - Value, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; -import { - Position, - PositionId, - PositionState, - TradingPair, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/dex/v1/dex_pb'; -import { GasPrices } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/fee/v1/fee_pb'; -import { - Epoch, - Nullifier, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/sct/v1/sct_pb'; -import { - FmdParameters, - Note, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/shielded_pool/v1/shielded_pool_pb'; -import { ValidatorInfo } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/stake/v1/stake_pb'; -import { - AddressIndex, - IdentityKey, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb'; -import { Transaction } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/transaction/v1/transaction_pb'; -import { TransactionId } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/txhash/v1/txhash_pb'; -import { StateCommitment } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/crypto/tct/v1/tct_pb'; -import { - NotesForVotingResponse, - SpendableNoteRecord, - SwapRecord, - TransactionInfo, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; -import type { Jsonified } from './jsonified'; -import { - AuctionId, - DutchAuctionDescription, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/auction/v1/auction_pb'; -import { PartialMessage } from '@bufbuild/protobuf'; - -export interface IdbUpdate> { - table: StoreName; - value: StoreValue; - key?: StoreKey | IDBKeyRange; -} - -export interface IndexedDbInterface { - subscribe>( - table: StoreName, - ): AsyncGenerator, void>; - constants(): IdbConstants; - clear(): Promise; - getFullSyncHeight(): Promise; - getSpendableNoteByNullifier(nullifier: Nullifier): Promise; - getSpendableNoteByCommitment( - commitment: StateCommitment, - ): Promise; - saveSpendableNote(note: SpendableNoteRecord): Promise; - iterateSpendableNotes(): AsyncGenerator; - saveTransaction(id: TransactionId, height: bigint, tx: Transaction): Promise; - getTransaction(txId: TransactionId): Promise; - iterateTransactions(): AsyncGenerator; - getAssetsMetadata(assetId: AssetId): Promise; - saveAssetsMetadata(metadata: Metadata): Promise; - iterateAssetsMetadata(): AsyncGenerator; - getStateCommitmentTree(): Promise; - saveScanResult(updates: ScanBlockResult): Promise; - getFmdParams(): Promise; - saveFmdParams(params: FmdParameters): Promise; - getAppParams(): Promise; - saveAppParams(params: AppParameters): Promise; - iterateSwaps(): AsyncGenerator; - getSwapByNullifier(nullifier: Nullifier): Promise; - saveSwap(note: SwapRecord): Promise; - getSwapByCommitment(commitment: StateCommitment): Promise; - getGasPrices(): Promise; - saveGasPrices(value: PartialMessage): Promise; - getNotesForVoting( - addressIndex: AddressIndex | undefined, - votableAtHeight: bigint, - ): Promise; - getOwnedPositionIds( - positionState: PositionState | undefined, - tradingPair: TradingPair | undefined, - ): AsyncGenerator; - addPosition(positionId: PositionId, position: Position): Promise; - updatePosition(positionId: PositionId, newState: PositionState): Promise; - addEpoch(startHeight: bigint): Promise; - getEpochByHeight(height: bigint): Promise; - upsertValidatorInfo(validatorInfo: ValidatorInfo): Promise; - iterateValidatorInfos(): AsyncGenerator; - getValidatorInfo(identityKey: IdentityKey): Promise; - updatePrice( - pricedAsset: AssetId, - numeraire: AssetId, - numerairePerUnit: number, - height: bigint, - ): Promise; - getPricesForAsset(assetMetadata: Metadata, latestBlockHeight: bigint): Promise; - clearSwapBasedPrices(): Promise; - - // Add more auction union types as they are created - upsertAuction( - auctionId: AuctionId, - value: { - auction?: T; - noteCommitment?: StateCommitment; - seqNum?: bigint; - }, - ): Promise; - - getAuction(auctionId: AuctionId): Promise<{ - // Add more auction union types as they are created - auction?: DutchAuctionDescription; - noteCommitment?: StateCommitment; - seqNum?: bigint; - }>; - - addAuctionOutstandingReserves( - auctionId: AuctionId, - value: { - input: Value; - output: Value; - }, - ): Promise; - - deleteAuctionOutstandingReserves(auctionId: AuctionId): Promise; - - getAuctionOutstandingReserves( - auctionId: AuctionId, - ): Promise<{ input: Value; output: Value } | undefined>; -} - -export interface PenumbraDb extends DBSchema { - FULL_SYNC_HEIGHT: { - key: 'height'; - value: bigint; - }; - TREE_LAST_POSITION: { - key: 'last_position'; - value: StoredPosition; - }; - TREE_LAST_FORGOTTEN: { - key: 'last_forgotten'; - value: bigint; - }; - TREE_HASHES: { - key: number; // autoincrement - value: StoreHash; - }; - TREE_COMMITMENTS: { - key: StoreCommitment['commitment']['inner']; // base64 - value: StoreCommitment; - }; - APP_PARAMETERS: { - key: 'params'; - value: Jsonified; - }; - FMD_PARAMETERS: { - key: 'params'; - value: Jsonified; - }; - TRANSACTIONS: { - key: string; // base64 TransactionInfo['id']['inner']; - value: Jsonified; // TransactionInfo with undefined view and perspective - }; - REGISTRY_VERSION: { - key: 'commit'; - value: string; - }; - // ======= Json serialized values ======= - // Allows wasm crate to directly deserialize - ASSETS: { - key: Jsonified['penumbraAssetId']['inner']>; // base64 - value: Jsonified; - }; - SPENDABLE_NOTES: { - key: Jsonified['noteCommitment']['inner']>; // base64 - value: Jsonified; - indexes: { - nullifier: Jsonified['nullifier']['inner']>; // base64 - }; - }; - - /** - * Store for advice for future spendable notes - * Used in wasm crate to process swap and swap claim - * - * This emphasizes the difference between Rust view service data storage and extension view service data storage. - * In the relational model (Rust view service), each 'SPENDABLE_NOTES' must have a corresponding record - * in the 'NOTES' table ('note_commitment' is used as a foreign key). - * Therefore, in Rust view service, the 'NOTES' table stores both notes that do not yet have an associated - * record in the 'SPENDABLE_NOTES' table (we call them advices) - * and notes that already have an associated record in 'SPENDABLE_NOTES'. - * - * In indexed-db (extension view service), we store advices separately in the 'ADVICE_NOTES' table, - * and store spendable notes along with nested notes in the 'SPENDABLE_NOTES' table. - * - * This table is never written or queried by TypeScript. - */ - ADVICE_NOTES: { - // key is not part of the stored object - key: Jsonified; // base64 - value: Jsonified; - }; - SWAPS: { - key: Jsonified['swapCommitment']['inner']>; // base64 - value: Jsonified; - indexes: { - nullifier: Jsonified['nullifier']['inner']>; // base64 - }; - }; - GAS_PRICES: { - key: 'gas_prices'; - value: Jsonified; - }; - POSITIONS: { - key: string; // base64 PositionRecord['id']['inner']; - value: PositionRecord; - }; - EPOCHS: { - key: number; // auto-increment - value: Jsonified; - }; - VALIDATOR_INFOS: { - key: string; // bech32-encoded validator identity key - value: Jsonified; - }; - PRICES: { - key: [ - Jsonified['pricedAsset']['inner']>, - Jsonified['numeraire']['inner']>, - ]; // composite key - value: Jsonified; - indexes: { - pricedAsset: Jsonified['pricedAsset']['inner']>; - }; - }; - AUCTIONS: { - key: string; // base64 AuctionId - value: { - noteCommitment?: Jsonified; - // Add more types to `auction` as more auction types are created - auction?: Jsonified; - /** - * For Dutch auctions: - * `0n`: auction is active - * `1n`: auction has ended - * `2n`+: the user has withdrawn funds from the auction - */ - seqNum?: bigint; - }; - }; - /** - * Only populated when BOTH a) the user has ended an auction, and b) the - * user has not yet withdrawn funds from it. - */ - AUCTION_OUTSTANDING_RESERVES: { - key: string; // base64 AuctionId - value: { - input: Jsonified; - output: Jsonified; - }; - }; -} - -// need to store PositionId and Position in the same table -export interface PositionRecord { - id: Jsonified; // PositionId (must be JsonValue because ['id']['inner'] is a key ) - position: Jsonified; // Position -} - -export type Tables = Record>; -export type PenumbraStoreNames = StoreNames; - -// Must be kept in sync with: https://github.com/penumbra-zone/penumbra/blob/02462635d6c825019822cbeeb44d422cf900f25d/crates/wasm/src/storage.rs#L15C1-L30 -export interface IdbConstants { - name: string; - version: number; - tables: Tables; -} - -export const IDB_TABLES: Tables = { - assets: 'ASSETS', - auctions: 'AUCTIONS', - auction_outstanding_reserves: 'AUCTION_OUTSTANDING_RESERVES', - advice_notes: 'ADVICE_NOTES', - spendable_notes: 'SPENDABLE_NOTES', - swaps: 'SWAPS', - fmd_parameters: 'FMD_PARAMETERS', - app_parameters: 'APP_PARAMETERS', - gas_prices: 'GAS_PRICES', - epochs: 'EPOCHS', - prices: 'PRICES', - validator_infos: 'VALIDATOR_INFOS', - transactions: 'TRANSACTIONS', - full_sync_height: 'FULL_SYNC_HEIGHT', -}; diff --git a/packages/types/src/internal-msg/chrome-error.ts b/packages/types/src/internal-msg/chrome-error.ts deleted file mode 100644 index f1bd268e..00000000 --- a/packages/types/src/internal-msg/chrome-error.ts +++ /dev/null @@ -1,7 +0,0 @@ -type ChromeResponderDroppedError = Error & { - message: 'A listener indicated an asynchronous response by returning true, but the message channel closed before a response was received'; -}; -export const isChromeResponderDroppedError = (e: unknown): e is ChromeResponderDroppedError => - e instanceof Error && - e.message === - 'A listener indicated an asynchronous response by returning true, but the message channel closed before a response was received'; diff --git a/packages/types/src/internal-msg/offscreen.ts b/packages/types/src/internal-msg/offscreen.ts deleted file mode 100644 index a74438e1..00000000 --- a/packages/types/src/internal-msg/offscreen.ts +++ /dev/null @@ -1,49 +0,0 @@ -import type { - Action, - TransactionPlan, - WitnessData, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/transaction/v1/transaction_pb'; -import type { Jsonified } from '../jsonified'; -import type { InternalMessage, InternalRequest, InternalResponse } from './shared'; -import { FullViewingKey } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb'; - -export type ActionBuildMessage = InternalMessage< - 'BUILD_ACTION', - ActionBuildRequest, - ActionBuildResponse ->; - -export type OffscreenMessage = ActionBuildMessage; -export type OffscreenRequest = InternalRequest; -export type OffscreenResponse = InternalResponse; - -export interface ActionBuildRequest { - transactionPlan: Jsonified; - witness: Jsonified; - fullViewingKey: Jsonified; - actionPlanIndex: number; -} -export type ActionBuildResponse = Jsonified; - -export const isActionBuildRequest = (req: unknown): req is ActionBuildRequest => - req != null && - typeof req === 'object' && - 'transactionPlan' in req && - req.transactionPlan != null && - typeof req.transactionPlan === 'object' && - 'actions' in req.transactionPlan && - Array.isArray(req.transactionPlan.actions) && - 'witness' in req && - req.witness != null && - typeof req.witness === 'object' && - 'fullViewingKey' in req && - typeof req.fullViewingKey === 'object' && - 'actionPlanIndex' in req && - typeof req.actionPlanIndex === 'number'; - -export const isOffscreenRequest = (req: unknown): req is OffscreenRequest => - req != null && - typeof req === 'object' && - 'type' in req && - typeof req.type === 'string' && - req.type === 'BUILD_ACTION'; diff --git a/packages/types/src/internal-msg/shared.ts b/packages/types/src/internal-msg/shared.ts deleted file mode 100644 index 31d5e8b4..00000000 --- a/packages/types/src/internal-msg/shared.ts +++ /dev/null @@ -1,22 +0,0 @@ -import type { JsonValue } from '@bufbuild/protobuf'; - -export interface InternalMessage { - type: Type; - request: Req; - response: Res; -} - -export interface InternalRequest> { - type: M['type']; - request: M['request']; -} - -export type InternalResponse> = - | { - type: M['type']; - data: M['response']; - } - | { - type: M['type']; - error: JsonValue; - }; diff --git a/packages/types/src/jsonified.ts b/packages/types/src/jsonified.ts deleted file mode 100644 index dbeb3231..00000000 --- a/packages/types/src/jsonified.ts +++ /dev/null @@ -1,60 +0,0 @@ -import type { JsonValue, JsonObject, AnyMessage } from '@bufbuild/protobuf'; - -export const isJsonObject = (res: unknown): res is JsonObject => - res != null && - typeof res === 'object' && - !Array.isArray(res) && - Object.keys(res).every(k => typeof k === 'string') && - Object.values(res).every(isJsonValue); - -export const isJsonArray = (res: unknown): res is JsonValue[] => - res != null && Array.isArray(res) && res.every(isJsonValue); - -export const isJsonValue = (res: unknown): res is JsonValue => - res === null || - typeof res === 'string' || - typeof res === 'number' || - typeof res === 'boolean' || - isJsonObject(res) || - isJsonArray(res); - -/** - * This is used to suggest the purpose of a string to a human. It provides no - * actual type assistance. - */ -export type Stringified = Jsonified extends JsonValue ? string : never; - -/** - * This is used to approximate a json-compatible version of a type. Mostly, it - * is for *suggesting* what a parameter or return *should* represent, *to a - * human*. It performs no actual data conversion, and makes assumptions about - * how some json-incompatible types will be converted. - * - * Our idb schema uses it for identifying key/index types generated from stored - * object fields. - * - * It's based on PlainMessage from `@bufbuild/protobuf`, but notably we treat - * any `Message` as a black-box `JsonObject`, to avoid the complex and - * configurable details of protojson. - * - * - members of `JsonValue` are directly equivalent - * - `Date`, `Uint8Array`, and `bigint` are assumed to stringify - * - Arrays are recursively Jsonified. - * - `AnyMessage` becomes generic `JsonObject` - * - other objects maintain structure, and filter out functions - */ -// prettier-ignore -export type Jsonified = T extends JsonValue ? T // JsonValue members equivalent - : T extends (Date | Uint8Array | bigint) ? string // these types stringify - : T extends (infer U)[] ? Jsonified[] // recurse into array members - : T extends AnyMessage ? JsonObject // AnyMessage is a black box - : T extends object ? { // any object... - [P in keyof T as // ...index into... - // eslint-disable-next-line @typescript-eslint/ban-types - T[P] extends (Function) ? never // ...strip function members - : P extends string ? P // ...keep string keys - : P extends number ? `${P}` // ...stringify number keys - : never // ...strip symbol keys - ]: Jsonified; // ...recurse object members - } - : T extends undefined ? never : T; // undefined not allowed diff --git a/packages/types/src/lo-hi.test.ts b/packages/types/src/lo-hi.test.ts deleted file mode 100644 index 473aecc1..00000000 --- a/packages/types/src/lo-hi.test.ts +++ /dev/null @@ -1,207 +0,0 @@ -import { describe, expect, it } from 'vitest'; -import { addLoHi, fromBaseUnit, joinLoHi, splitLoHi, toBaseUnit } from './lo-hi'; -import { BigNumber } from 'bignumber.js'; - -describe('lo-hi', () => { - describe('splitLoHi', () => { - it('should correctly split a 128-bit number into two 64-bit numbers', () => { - const value = 18446744073709551615n + (18446744073709551615n << 64n); - const result = splitLoHi(value); - - expect(result.lo).toBe(18446744073709551615n); - expect(result.hi).toBe(18446744073709551615n); - }); - - it('should correctly handle zero', () => { - const result = splitLoHi(0n); - - expect(result.lo).toBe(0n); - expect(result.hi).toBe(0n); - }); - - it('should correctly handle a number less than 2^64', () => { - const result = splitLoHi(1234567890n); - - expect(result.lo).toBe(1234567890n); - expect(result.hi).toBe(0n); - }); - - it('should correctly handle a number with non-zero high and zero low', () => { - const result = splitLoHi(1234567890n << 64n); - - expect(result.hi).toBe(1234567890n); - expect(result.lo).toBe(0n); - }); - - it('should correctly split the low bits when no splitting is required', () => { - const value = 0xfedcba9876543210n; - const { lo } = splitLoHi(value); - - expect(lo).toBe(value); - }); - }); - - describe('joinLoHi', () => { - it('should correctly join two 64-bit numbers into a 128-bit number', () => { - const lo = 18446744073709551615n; - const hi = 18446744073709551615n; - const result = joinLoHi(lo, hi); - - expect(result).toBe((hi << 64n) + lo); - expect(result).toBe(340282366920938463463374607431768211455n); - }); - - it('should correctly handle zero', () => { - const result = joinLoHi(0n, 0n); - expect(result).toBe(0n); - - const passingNone = joinLoHi(); - expect(passingNone).toBe(0n); - }); - - it('should correctly handle a number less than 2^64', () => { - const result = joinLoHi(1234567890n, 0n); - expect(result).toBe(1234567890n); - }); - - it('should correctly join a lo value with no hi value', () => { - const lo = 123456789n; - expect(joinLoHi(lo)).toEqual(lo); - }); - }); - - describe('splitLoHi and joinLoHi', () => { - it('should be able to recover the original number after splitting and joining', () => { - const original = (18446744073709551615n + 18446744073709551615n) << 64n; - const split = splitLoHi(original); - const recovered = joinLoHi(split.lo, split.hi); - - expect(recovered).toBe(original); - }); - - it('should be able to recover random 128-bit numbers after splitting and joining', () => { - for (let i = 0; i < 1000; i++) { - const original = - BigInt(Math.floor(Math.random() * Number.MAX_SAFE_INTEGER)) + - (BigInt(Math.floor(Math.random() * Number.MAX_SAFE_INTEGER)) << 64n); - const split = splitLoHi(original); - const recovered = joinLoHi(split.lo, split.hi); - - expect(recovered).toBe(original); - } - }); - }); - - describe('addLoHi', () => { - it('adds zero amounts', () => { - const a = { lo: 0n, hi: 0n }; - const b = { lo: 0n, hi: 0n }; - - expect(addLoHi(a, b)).toEqual({ lo: 0n, hi: 0n }); - }); - - it('adds with no carry', () => { - const a = { lo: 123456789n, hi: 987654321n }; - const b = { lo: 9876543210n, hi: 1234567890n }; - - expect(addLoHi(a, b)).toEqual({ lo: 9999999999n, hi: 2222222211n }); - }); - - it('add results in a carry from the lo to the hi', () => { - const a = { lo: 0xffffffffffffffffn, hi: 0n }; - const b = { lo: 1n, hi: 0n }; - - expect(addLoHi(a, b)).toEqual({ lo: 0n, hi: 1n }); - }); - - it('should handle large hi values', () => { - const a = { lo: 0n, hi: 0xffffffffffffffffn }; - const b = { lo: 0n, hi: 1n }; - - expect(addLoHi(a, b)).toEqual({ lo: 0n, hi: 0x10000000000000000n }); - }); - - it('should handle large lo and hi values', () => { - const a = { lo: 0xffffffffffffffffn, hi: 0xffffffffffffffffn }; - const b = { lo: 1n, hi: 1n }; - - expect(addLoHi(a, b)).toEqual({ lo: 0n, hi: 0x10000000000000001n }); - }); - }); - - describe('fromBaseUnit', () => { - it('applies positive exponent', () => { - const result = fromBaseUnit(1000n, 0n, 3); - expect(result.toString()).toBe('1'); - }); - - it('handles high and low bits', () => { - const result = fromBaseUnit(1000n, 5n, 6); - expect(result.toString()).toBe('92233720368547.75908'); - }); - - it('handles exponent of 0', () => { - const result = fromBaseUnit(1000n, 0n, 0); - expect(result.toString()).toBe('1000'); - }); - - it('handles big numbers', () => { - const result = fromBaseUnit(123456789012345n, 987654321098765n, 30); - expect(result.toString()).toBe('18219.00649460227383107831'); - }); - - it('should return less than 1', () => { - const result = fromBaseUnit(7n, 0n, 12); - expect(result.toString()).toBe('0.000000000007'); - }); - - it('uses exponential notation if big/small enough', () => { - const result = fromBaseUnit(7n, 0n, 20); - expect(result.toString()).toBe('7e-20'); - }); - }); - - describe('toBaseUnit', () => { - it('returns correct LoHi for integer value and exponent 0', () => { - const result = toBaseUnit(BigNumber(12345), 0); - expect(result.lo).toBe(12345n); - expect(result.hi).toBe(0n); - }); - - it('should correctly convert to base unit', () => { - const result = toBaseUnit(BigNumber(123.456), 3); - expect(result.lo).toBe(123456n); - expect(result.hi).toBe(0n); - }); - - it('returns correct LoHi for integer value and positive exponent', () => { - const result = toBaseUnit(BigNumber(12345), 2); - expect(result.lo).toBe(1234500n); - expect(result.hi).toBe(0n); - }); - - it('returns correct LoHi for large value and positive exponent', () => { - const result = toBaseUnit(BigNumber(1234567.13314), 9); - expect(joinLoHi(result.lo, result.hi)).toBe(1234567133140000n); - }); - - it('handles max safe integer', () => { - const max = Number.MAX_SAFE_INTEGER; - const result = toBaseUnit(BigNumber(max), 0); - expect(result.lo).toEqual(BigInt(max)); - expect(result.hi).toBe(0n); - }); - - it('returns correct LoHi for large value and zero exponent', () => { - const result = toBaseUnit(BigNumber(1234567891234567), 0); - const expectedValue = BigInt(1234567891234567); - expect(joinLoHi(result.lo, result.hi)).toEqual(expectedValue); - }); - - it('returns correct LoHi for large value and 18 exponent', () => { - const result = toBaseUnit(BigNumber(1234567891234567), 18); - const expectedValue = BigInt('1234567891234567000000000000000000'); - expect(joinLoHi(result.lo, result.hi)).toEqual(expectedValue); - }); - }); -}); diff --git a/packages/types/src/lo-hi.ts b/packages/types/src/lo-hi.ts deleted file mode 100644 index 6a6c09dd..00000000 --- a/packages/types/src/lo-hi.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { BigNumber } from 'bignumber.js'; - -BigNumber.config({ - EXPONENTIAL_AT: [-20, 20], - FORMAT: { - decimalSeparator: '.', - groupSeparator: '', - }, -}); - -/** - * In protobufs, it's common to split a single u128 into two u64's. - * - * hi: u64 lo: u64 - * ┌───┬───┬───┬───┬───┬───┬───┬───┐ ┌───┬───┬───┬───┬───┬───┬───┬───┐ - * │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ - * └───┴───┴───┴───┴───┴───┴───┴───┘ └───┴───┴───┴───┴───┴───┴───┴───┘ - * 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 - */ -export interface LoHi { - lo: bigint; - hi?: bigint; -} - -/** - * @param {bigint} value - The 128-bit number represented as a bigint. - * @returns {LoHi} An object with properties `lo` and `hi`, representing the low and high 64 bits of `value`. - */ -export const splitLoHi = (value: bigint): Required => { - const hi = value >> 64n; - const lo = value & ((1n << 64n) - 1n); - return { lo, hi }; -}; - -/** - * Joins a high order and a low order bigint into a single bigint. - * - * The `hi` and `lo` values are expected to represent the high and - * low 64 bits of a 128-bit number, respectively. The function - * returns a bigint that combines these two parts. - * To achieve this, we shift `hi` 8 bytes to the left. - * - * @param {bigint} lo - The low order 64 bits of the number. - * @param {bigint} hi - The high order 64 bits of the number. - * @returns {bigint} The combined 128-bit number represented as a single bigint. - */ -export const joinLoHi = (lo = 0n, hi = 0n): bigint => { - return (hi << 64n) + lo; -}; - -/** - * Adds two LoHi numbers together - */ -export const addLoHi = (a: LoHi, b: LoHi): Required => { - const aBigInt = joinLoHi(a.lo, a.hi); - const bBigInt = joinLoHi(b.lo, b.hi); - return splitLoHi(aBigInt + bBigInt); -}; - -/** - * Denoms have `DenomUnit[]` which provide variations of the denom display name with different exponents: - * - penumbra, exponent 6 - * - mpenumbra, exponent 3 - * - upenumbra, exponent 0 - * This function allows you to calculate a single BigInt with the exponent applied - * Note: Often passing exponent 0 is the default given protobuf serialization. - * This is treated as 1 instead. - * - * @returns BigNumber as javascript's `number` does not have the necessary precision - */ -export const fromBaseUnit = (lo = 0n, hi = 0n, exponent: number): BigNumber => { - const bigNum = new BigNumber(joinLoHi(lo, hi).toString()); - return bigNum.dividedBy(exponent ? BigNumber(10).pow(exponent) : 1); -}; - -/** - * Inverse of fromBaseUnit. - * Multiplies the given number by 10 to the power of the exponent, - * and then splits the result into separate lo and hi values. - * - * @param {BigNumber} value - The value to be multiplied. - * @param {number} exponent - The exponent to be applied. - * @returns {LoHi} An object with properties `lo` and `hi`, representing the low and high 64 bits of the multiplied value. - */ -export const toBaseUnit = (value: BigNumber, exponent = 0): LoHi => { - const multipliedValue = value.multipliedBy(new BigNumber(10).pow(exponent)); - const bigInt = BigInt(multipliedValue.toFixed()); - - return splitLoHi(bigInt); -}; diff --git a/packages/types/src/protobuf.test.ts b/packages/types/src/protobuf.test.ts deleted file mode 100644 index afee0bc4..00000000 --- a/packages/types/src/protobuf.test.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { describe, expect, it } from 'vitest'; -import { typeUrlMatchesTypeName } from './protobuf'; - -describe('typeUrlMatchesTypeName()', () => { - it('returns `true` if the type URL is equal to the type name with a leading slash', () => { - expect(typeUrlMatchesTypeName('/foo', 'foo')).toBe(true); - }); - - it('returns `false` if the type URL is not equal to the type name with a leading slash', () => { - expect(typeUrlMatchesTypeName('/foo', 'bar')).toBe(false); - }); - - it('returns `false` if the type URL is undefined', () => { - expect(typeUrlMatchesTypeName(undefined, 'foo')).toBe(false); - }); - - it('returns `false` if the type name is undefined', () => { - expect(typeUrlMatchesTypeName('/foo', undefined)).toBe(false); - }); -}); diff --git a/packages/types/src/protobuf.ts b/packages/types/src/protobuf.ts deleted file mode 100644 index 8b842319..00000000 --- a/packages/types/src/protobuf.ts +++ /dev/null @@ -1,10 +0,0 @@ -/** - * When converting a type name to a type URL, you simply add a leading slash. - * This little helper allows you to pass the type URL of a Protobuf object, and - * the typename of a Protobuf class, to compare them. Useful when working with - * `Any`s. - * - * @see https://github.com/tokio-rs/prost/blob/215ae16/prost/src/name.rs#L27-L33 - */ -export const typeUrlMatchesTypeName = (typeUrl?: string, typeName?: string): typeUrl is string => - typeUrl !== undefined && typeName !== undefined && typeUrl === `/${typeName}`; diff --git a/packages/types/src/querier.ts b/packages/types/src/querier.ts deleted file mode 100644 index 98ad2d05..00000000 --- a/packages/types/src/querier.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { AppParameters } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/app/v1/app_pb'; -import { CompactBlock } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/compact_block/v1/compact_block_pb'; -import { - AssetId, - Metadata, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; -import { - QueryClientStatesRequest, - QueryClientStatesResponse, -} from '@buf/cosmos_ibc.bufbuild_es/ibc/core/client/v1/query_pb'; -import { TransactionId } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/txhash/v1/txhash_pb'; -import { Transaction } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/transaction/v1/transaction_pb'; -import { - ValidatorInfoRequest, - ValidatorInfoResponse, - ValidatorPenaltyRequest, - ValidatorPenaltyResponse, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/stake/v1/stake_pb'; -import { MerkleRoot } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/crypto/tct/v1/tct_pb'; -import { - AuctionId, - DutchAuction, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/auction/v1/auction_pb'; - -export interface RootQuerierInterface { - app: AppQuerierInterface; - compactBlock: CompactBlockQuerierInterface; - tendermint: TendermintQuerierInterface; - shieldedPool: ShieldedPoolQuerierInterface; - ibcClient: IbcClientQuerierInterface; - stake: StakeQuerierInterface; - cnidarium: CnidariumQuerierInterface; - auction: AuctionQuerierInterface; -} - -export interface AppQuerierInterface { - appParams(): Promise; - txsByHeight(blockHeight: bigint): Promise; -} - -export interface CompactBlockRangeParams { - startHeight: bigint; - keepAlive: boolean; // Will continuously receive blocks as long as service worker is running - abortSignal: AbortSignal; -} - -export interface CompactBlockQuerierInterface { - compactBlockRange(params: CompactBlockRangeParams): AsyncIterable; -} - -export interface TendermintQuerierInterface { - latestBlockHeight(): Promise; - broadcastTx(tx: Transaction): Promise; - getTransaction(txId: TransactionId): Promise<{ height: bigint; transaction: Transaction }>; -} - -export interface ShieldedPoolQuerierInterface { - assetMetadataById(assetId: AssetId): Promise; -} - -export interface IbcClientQuerierInterface { - ibcClientStates(req: QueryClientStatesRequest): Promise; -} - -export interface StakeQuerierInterface { - allValidatorInfos(req: ValidatorInfoRequest): AsyncIterable; - validatorPenalty(req: ValidatorPenaltyRequest): Promise; -} - -export interface CnidariumQuerierInterface { - fetchRemoteRoot(blockHeight: bigint): Promise; -} - -export interface AuctionQuerierInterface { - auctionStateById(id: AuctionId): Promise; -} diff --git a/packages/types/src/servers.ts b/packages/types/src/servers.ts deleted file mode 100644 index 29751049..00000000 --- a/packages/types/src/servers.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { ScanBlockResult } from './state-commitment-tree'; -import { CompactBlock } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/compact_block/v1/compact_block_pb'; -import { MerkleRoot } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/crypto/tct/v1/tct_pb'; - -export interface ViewServerInterface { - scanBlock(compactBlock: CompactBlock): Promise; - flushUpdates(): ScanBlockResult; - resetTreeToStored(): Promise; - getSctRoot(): MerkleRoot; -} diff --git a/packages/types/src/services.ts b/packages/types/src/services.ts deleted file mode 100644 index d4ca9634..00000000 --- a/packages/types/src/services.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { IndexedDbInterface } from './indexed-db'; -import { ViewServerInterface } from './servers'; -import { BlockProcessorInterface } from './block-processor'; -import { RootQuerierInterface } from './querier'; - -export interface WalletServices { - viewServer: ViewServerInterface; - blockProcessor: BlockProcessorInterface; - indexedDb: IndexedDbInterface; - querier: RootQuerierInterface; -} - -export interface ServicesInterface { - getWalletServices(): Promise; -} diff --git a/packages/types/src/staking.test.ts b/packages/types/src/staking.test.ts deleted file mode 100644 index a67a5dc4..00000000 --- a/packages/types/src/staking.test.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { describe, expect, it } from 'vitest'; -import { calculateCommissionAsPercentage, getVotingPowerByValidatorInfo } from './staking'; -import { ValidatorInfo } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/stake/v1/stake_pb'; -import { bech32mIdentityKey } from '@penumbra-zone/bech32m/penumbravalid'; -import { getIdentityKeyFromValidatorInfo } from '@penumbra-zone/getters/validator-info'; - -describe('calculateCommission()', () => { - const validatorInfo = new ValidatorInfo({ - validator: { - fundingStreams: [ - { - recipient: { - case: 'toAddress', - value: { - rateBps: 100, - }, - }, - }, - { - recipient: { - case: 'toCommunityPool', - value: { - rateBps: 200, - }, - }, - }, - { - recipient: { - case: 'toAddress', - value: { - rateBps: 300, - }, - }, - }, - ], - }, - }); - - it("returns the sum of all of a validator's funding streams' rates", () => { - expect(calculateCommissionAsPercentage(validatorInfo)).toBe(6); - }); -}); - -describe('getVotingPowerByValidatorInfo()', () => { - const validatorInfo1 = new ValidatorInfo({ - status: { - votingPower: { hi: 0n, lo: 2n }, - }, - validator: { - name: 'Validator 1', - identityKey: { ik: Uint8Array.from({ length: 32 }, () => Math.floor(Math.random() * 256)) }, - }, - }); - - const validatorInfo2 = new ValidatorInfo({ - status: { - votingPower: { hi: 0n, lo: 2n }, - }, - validator: { - name: 'Validator 2', - identityKey: { ik: Uint8Array.from({ length: 32 }, () => Math.floor(Math.random() * 256)) }, - }, - }); - - const validatorInfo3 = new ValidatorInfo({ - status: { - votingPower: { hi: 0n, lo: 1n }, - }, - validator: { - name: 'Validator 3', - identityKey: { ik: Uint8Array.from({ length: 32 }, () => Math.floor(Math.random() * 256)) }, - }, - }); - - const validator1Bech32IdentityKey = bech32mIdentityKey( - getIdentityKeyFromValidatorInfo(validatorInfo1), - ); - - const validator2Bech32IdentityKey = bech32mIdentityKey( - getIdentityKeyFromValidatorInfo(validatorInfo2), - ); - - const validator3Bech32IdentityKey = bech32mIdentityKey( - getIdentityKeyFromValidatorInfo(validatorInfo3), - ); - - it('accurately calculates voting power for each validator', () => { - const result = getVotingPowerByValidatorInfo([validatorInfo1, validatorInfo2, validatorInfo3]); - - expect(result[validator1Bech32IdentityKey]).toBe(40); - expect(result[validator2Bech32IdentityKey]).toBe(40); - expect(result[validator3Bech32IdentityKey]).toBe(20); - }); -}); diff --git a/packages/types/src/staking.ts b/packages/types/src/staking.ts deleted file mode 100644 index 1d3a6c97..00000000 --- a/packages/types/src/staking.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { - BondingState_BondingStateEnum, - ValidatorInfo, - ValidatorState_ValidatorStateEnum, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/stake/v1/stake_pb'; -import { - getBondingStateEnumFromValidatorInfo, - getFundingStreamsFromValidatorInfo, - getIdentityKeyFromValidatorInfo, - getStateEnumFromValidatorInfo, - getVotingPowerFromValidatorInfo, -} from '@penumbra-zone/getters/validator-info'; -import { getRateBpsFromFundingStream } from '@penumbra-zone/getters/funding-stream'; -import { joinLoHiAmount } from './amount'; -import { bech32mIdentityKey } from '@penumbra-zone/bech32m/penumbravalid'; -import { ValueView } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; -import { getDisplayDenomFromView } from '@penumbra-zone/getters/value-view'; -import { assetPatterns } from './assets'; - -export const getStateLabel = (validatorInfo: ValidatorInfo): string => - ValidatorState_ValidatorStateEnum[getStateEnumFromValidatorInfo(validatorInfo)]; - -export const getBondingStateLabel = (validatorInfo: ValidatorInfo): string => - BondingState_BondingStateEnum[getBondingStateEnumFromValidatorInfo(validatorInfo)]; - -const toSum = (prev: number, curr: number) => prev + curr; - -/** - * Given A) a `ValueView` with a delegation token, and B) a `ValidatorInfo`, - * returns a boolean indicating whether the delegation token is for the given - * validator. Useful for using with `Array.prototype.find`/`.filter` to identify - * a value of delegation tokens for a given validator - */ -export const isDelegationTokenForValidator = ( - delegation: ValueView, - validatorInfo: ValidatorInfo, -): boolean => { - const delegationMatch = assetPatterns.delegationToken.capture( - getDisplayDenomFromView(delegation), - ); - if (!delegationMatch) return false; - - return ( - delegationMatch.idKey === bech32mIdentityKey(getIdentityKeyFromValidatorInfo(validatorInfo)) - ); -}; - -/** - * Given a `ValidatorInfo`, returns the sum of all commission rates as a - * percentage. - * - * To do this, we convert the rate from [basis - * points](https://en.wikipedia.org/wiki/Basis_point) (which are one hundredth - * of one percent). - */ -export const calculateCommissionAsPercentage = (validatorInfo: ValidatorInfo): number => { - const fundingStreams = getFundingStreamsFromValidatorInfo(validatorInfo); - const totalBps = fundingStreams.map(getRateBpsFromFundingStream).reduce(toSum); - - return totalBps / 100; -}; - -const toTotalVotingPower = (prev: number, curr: ValidatorInfo) => - prev + Number(joinLoHiAmount(getVotingPowerFromValidatorInfo(curr))); - -const getFormattedVotingPower = (validatorInfo: ValidatorInfo, totalVotingPower: number) => - Math.round( - (Number(joinLoHiAmount(getVotingPowerFromValidatorInfo(validatorInfo))) / totalVotingPower) * - 100, - ); - -/** - * Just a `number`, but used to indicate what information this number - * represents. - */ -export type VotingPowerAsIntegerPercentage = number; - -/** - * Returns an object mapping validator infos (by bech32 identity key) to their - * voting power, expressed as a percentage of total voting power. - */ -export const getVotingPowerByValidatorInfo = ( - validatorInfos: ValidatorInfo[], -): Record => { - const totalVotingPower = validatorInfos.reduce(toTotalVotingPower, 0); - - return validatorInfos.reduce>((prev, curr) => { - prev[bech32mIdentityKey(getIdentityKeyFromValidatorInfo(curr))] = getFormattedVotingPower( - curr, - totalVotingPower, - ); - return prev; - }, {}); -}; diff --git a/packages/types/src/state-commitment-tree.ts b/packages/types/src/state-commitment-tree.ts deleted file mode 100644 index 7ba04240..00000000 --- a/packages/types/src/state-commitment-tree.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { z } from 'zod'; -import { InnerBase64Schema } from './base64'; -import { - SpendableNoteRecord, - SwapRecord, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; - -export const Position = z.object({ - epoch: z.number(), - block: z.number(), - commitment: z.number(), -}); - -export const StoredPositionSchema = z.union([ - z.object({ - Position: Position, - }), - z.literal('Full'), -]); - -export type StoredPosition = z.infer; - -export const StoreHashSchema = z.object({ - position: Position, - height: z.number(), - hash: z.instanceof(Uint8Array), - essential: z.boolean(), -}); - -export type StoreHash = z.infer; - -export const StoreCommitmentSchema = z.object({ - position: Position, - commitment: InnerBase64Schema, -}); - -export type StoreCommitment = z.infer; - -export const DeleteRange = z.object({ - below_height: z.number(), // exclusive - positions: z.object({ - start: Position, // inclusive - end: Position, // exclusive - }), -}); - -export const SctUpdatesSchema = z.object({ - set_position: StoredPositionSchema.optional(), - set_forgotten: z.bigint().optional(), - store_commitments: z.array(StoreCommitmentSchema), - store_hashes: z.array(StoreHashSchema), - delete_ranges: z.array(DeleteRange), -}); - -export type SctUpdates = z.infer; - -export interface ScanBlockResult { - height: bigint; - sctUpdates: SctUpdates; - newNotes: SpendableNoteRecord[]; - newSwaps: SwapRecord[]; -} - -export const StateCommitmentTreeSchema = z.object({ - last_position: StoredPositionSchema, - last_forgotten: z.bigint(), - hashes: z.array(StoreHashSchema), - commitments: z.array(StoreCommitmentSchema), -}); - -export type StateCommitmentTree = z.infer; diff --git a/packages/types/src/string.test.ts b/packages/types/src/string.test.ts deleted file mode 100644 index eb5f950c..00000000 --- a/packages/types/src/string.test.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { describe, expect, it } from 'vitest'; -import { shorten, stringToUint8Array, uint8ArrayToString } from './string'; - -describe('stringToUint8Array', () => { - it('should return correct Uint8Array for ASCII strings', () => { - const str = 'Hello, world!'; - const expected = new Uint8Array([72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100, 33]); // UTF-8 codes for 'Hello, world!' - const result = stringToUint8Array(str); - expect(result).toEqual(expected); - }); - - it('should return correct Uint8Array for non-ASCII strings', () => { - const str = 'こんにちは世界'; // "Hello, world!" in Japanese - const expected = new Uint8Array([ - 227, 129, 147, 227, 130, 147, 227, 129, 171, 227, 129, 161, 227, 129, 175, 228, 184, 150, 231, - 149, 140, - ]); // UTF-8 codes for 'こんにちは世界' - const result = stringToUint8Array(str); - expect(result).toEqual(expected); - }); - - it('should return an empty Uint8Array for an empty string', () => { - const str = ''; - const expected = new Uint8Array([]); - const result = stringToUint8Array(str); - expect(result).toEqual(expected); - }); -}); - -describe('Uint8Array to String conversion', () => { - it('should convert Uint8Array to String correctly', () => { - const originalString = 'Hello, world!'; - const uint8Array = stringToUint8Array(originalString); - const convertedString = uint8ArrayToString(uint8Array); - - expect(convertedString).toEqual(originalString); - }); - - it('should handle empty string', () => { - const originalString = ''; - const uint8Array = stringToUint8Array(originalString); - const convertedString = uint8ArrayToString(uint8Array); - - expect(convertedString).toEqual(originalString); - }); - - it('should handle non-English characters', () => { - const originalString = 'こんにちは、world!'; - const uint8Array = stringToUint8Array(originalString); - const convertedString = uint8ArrayToString(uint8Array); - - expect(convertedString).toEqual(originalString); - }); -}); - -describe('shorten()', () => { - it('returns the original string when string length is less than or equal to 6', () => { - const input = 'abcdef'; - const output = shorten(input); - expect(output).toBe('abcdef'); - }); - - it('returns a shortened string when string length is more than 6', () => { - const input = 'abcdefgh'; - const output = shorten(input); - expect(output).toBe('abcdefgh'); - }); - - it('returns a shortened string when string length is exactly 7', () => { - const input = 'abcdefgh'; - const output = shorten(input, 4); - expect(output).toBe('abcdefgh'); - }); - - it('returns empty string when input is empty string', () => { - const input = ''; - const output = shorten(input); - expect(output).toBe(''); - }); - - it('works with custom ends length', () => { - const input = 'abcdefghijklmnop'; - const outputA = shorten(input, 6); - expect(outputA).toBe('abcdef…klmnop'); - const outputB = shorten(input, 1); - expect(outputB).toBe('a…p'); - }); -}); diff --git a/packages/types/src/string.ts b/packages/types/src/string.ts deleted file mode 100644 index e288becd..00000000 --- a/packages/types/src/string.ts +++ /dev/null @@ -1,17 +0,0 @@ -const encoder = new TextEncoder(); -export const stringToUint8Array = (str: string): Uint8Array => { - return encoder.encode(str); -}; - -const decoder = new TextDecoder(); -export const uint8ArrayToString = (array: Uint8Array): string => { - return decoder.decode(array); -}; - -export const shorten = (str: string, endsLength = 4) => { - if (str.length <= endsLength + 4) { - return str; - } else { - return str.slice(0, endsLength) + '…' + str.slice(endsLength * -1); - } -}; diff --git a/packages/types/src/swap.test.ts b/packages/types/src/swap.test.ts deleted file mode 100644 index 7c6420dd..00000000 --- a/packages/types/src/swap.test.ts +++ /dev/null @@ -1,327 +0,0 @@ -import { describe, expect, it } from 'vitest'; -import { getOneWaySwapValues, isOneWaySwap } from './swap'; -import { SwapView } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/dex/v1/dex_pb'; -import { - Metadata, - ValueView, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; -import { NoteView } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/shielded_pool/v1/shielded_pool_pb'; - -const asset1Metadata = new Metadata({ - symbol: 'ASSET1', -}); - -const asset2Metadata = new Metadata({ - symbol: 'ASSET2', -}); - -describe('isOneWaySwap()', () => { - it('returns true when only delta 1 is zero', () => { - const swapView = new SwapView({ - swapView: { - case: 'visible', - value: { - swapPlaintext: { - delta1I: { hi: 0n, lo: 0n }, - delta2I: { hi: 0n, lo: 2n }, - }, - }, - }, - }); - - expect(isOneWaySwap(swapView)).toBe(true); - }); - - it('returns true when only delta 2 is zero', () => { - const swapView = new SwapView({ - swapView: { - case: 'visible', - value: { - swapPlaintext: { - delta1I: { hi: 0n, lo: 2n }, - delta2I: { hi: 0n, lo: 0n }, - }, - }, - }, - }); - - expect(isOneWaySwap(swapView)).toBe(true); - }); - - it('returns true when both deltas are zero', () => { - const swapView = new SwapView({ - swapView: { - case: 'visible', - value: { - swapPlaintext: { - delta1I: { hi: 0n, lo: 0n }, - delta2I: { hi: 0n, lo: 0n }, - }, - }, - }, - }); - - expect(isOneWaySwap(swapView)).toBe(true); - }); - - it('returns false when both deltas are nonzero', () => { - const swapView = new SwapView({ - swapView: { - case: 'visible', - value: { - swapPlaintext: { - delta1I: { hi: 0n, lo: 1n }, - delta2I: { hi: 0n, lo: 2n }, - }, - }, - }, - }); - - expect(isOneWaySwap(swapView)).toBe(false); - }); -}); - -describe('getOneWaySwapValues()', () => { - describe('when passed a `SwapView` with no nonzero deltas', () => { - const swapViewWithNoNonzeroInputs = new SwapView({ - swapView: { - case: 'visible', - value: { - swapPlaintext: { - delta1I: { hi: 0n, lo: 1n }, - delta2I: { hi: 0n, lo: 2n }, - }, - }, - }, - }); - - it('throws', () => { - expect(() => getOneWaySwapValues(swapViewWithNoNonzeroInputs)).toThrow( - 'Attempted to get one-way swap values from a two-way swap.', - ); - }); - }); - - describe('when passed a `SwapView` with exactly one nonzero delta', () => { - describe('asset1 -> asset2 swap', () => { - const output1 = new NoteView({ - value: { - valueView: { - case: 'knownAssetId', - value: { - amount: { hi: 0n, lo: 0n }, - }, - }, - }, - }); - - const output2 = new NoteView({ - value: { - valueView: { - case: 'knownAssetId', - value: { - amount: { hi: 0n, lo: 5n }, - }, - }, - }, - }); - - const swapViewWithOneNonzeroInput = new SwapView({ - swapView: { - case: 'visible', - value: { - swapPlaintext: { - delta1I: { hi: 0n, lo: 1n }, - delta2I: { hi: 0n, lo: 0n }, - }, - asset1Metadata, - asset2Metadata, - output1, - output2, - }, - }, - }); - - it('returns the values in the correct fields', () => { - expect(getOneWaySwapValues(swapViewWithOneNonzeroInput)).toEqual({ - input: new ValueView({ - valueView: { - case: 'knownAssetId', - value: { - amount: { hi: 0n, lo: 1n }, - metadata: asset1Metadata, - }, - }, - }), - output: output2.value, - }); - }); - }); - - describe('asset2 -> asset1 swap', () => { - const output1 = new NoteView({ - value: { - valueView: { - case: 'knownAssetId', - value: { - amount: { hi: 0n, lo: 5n }, - }, - }, - }, - }); - - const output2 = new NoteView({ - value: { - valueView: { - case: 'knownAssetId', - value: { - amount: { hi: 0n, lo: 0n }, - }, - }, - }, - }); - - const swapViewWithOneNonzeroInput = new SwapView({ - swapView: { - case: 'visible', - value: { - swapPlaintext: { - delta1I: { hi: 0n, lo: 0n }, - delta2I: { hi: 0n, lo: 1n }, - }, - asset1Metadata, - asset2Metadata, - output1, - output2, - }, - }, - }); - - it('returns the values in the correct fields', () => { - expect(getOneWaySwapValues(swapViewWithOneNonzeroInput)).toEqual({ - input: new ValueView({ - valueView: { - case: 'knownAssetId', - value: { - amount: { hi: 0n, lo: 1n }, - metadata: asset2Metadata, - }, - }, - }), - output: output1.value, - }); - }); - }); - - describe('when both outputs are nonzero', () => { - const output1 = new NoteView({ - value: { - valueView: { - case: 'knownAssetId', - value: { - amount: { hi: 0n, lo: 2n }, - }, - }, - }, - }); - - const output2 = new NoteView({ - value: { - valueView: { - case: 'knownAssetId', - value: { - amount: { hi: 0n, lo: 5n }, - }, - }, - }, - }); - - const swapViewWithTwoNonzeroOutputs = new SwapView({ - swapView: { - case: 'visible', - value: { - swapPlaintext: { - delta1I: { hi: 0n, lo: 10n }, - delta2I: { hi: 0n, lo: 0n }, - }, - asset1Metadata, - asset2Metadata, - output1, - output2, - }, - }, - }); - - it('returns an unfilled amount', () => { - expect(getOneWaySwapValues(swapViewWithTwoNonzeroOutputs)).toEqual({ - input: new ValueView({ - valueView: { - case: 'knownAssetId', - value: { - amount: { hi: 0n, lo: 10n }, - metadata: asset1Metadata, - }, - }, - }), - output: output2.value, - unfilled: output1.value, - }); - }); - }); - }); - - describe('when passed a `SwapView` with two zero-amount deltas', () => { - const output1 = new NoteView({ - value: { - valueView: { - case: 'knownAssetId', - value: { - amount: { hi: 0n, lo: 0n }, - }, - }, - }, - }); - - const output2 = new NoteView({ - value: { - valueView: { - case: 'knownAssetId', - value: { - amount: { hi: 0n, lo: 0n }, - }, - }, - }, - }); - - const swapViewWithOneNonzeroInput = new SwapView({ - swapView: { - case: 'visible', - value: { - swapPlaintext: { - delta1I: { hi: 0n, lo: 0n }, - delta2I: { hi: 0n, lo: 0n }, - }, - asset1Metadata, - asset2Metadata, - output1, - output2, - }, - }, - }); - - it('returns the values in the order asset1 -> asset2', () => { - expect(getOneWaySwapValues(swapViewWithOneNonzeroInput)).toEqual({ - input: new ValueView({ - valueView: { - case: 'knownAssetId', - value: { - amount: { hi: 0n, lo: 0n }, - metadata: asset1Metadata, - }, - }, - }), - output: output2.value, - }); - }); - }); -}); diff --git a/packages/types/src/swap.ts b/packages/types/src/swap.ts deleted file mode 100644 index 5f1eef78..00000000 --- a/packages/types/src/swap.ts +++ /dev/null @@ -1,106 +0,0 @@ -import { - getAsset1Metadata, - getAsset2Metadata, - getDelta1IFromSwapView, - getDelta2IFromSwapView, - getOutput1Value, - getOutput2Value, -} from '@penumbra-zone/getters/swap-view'; -import { ValueView } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; -import { SwapView } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/dex/v1/dex_pb'; -import { isZero } from './amount'; -import { getAmount } from '@penumbra-zone/getters/value-view'; - -/** - * Swaps can go in either direction in Penumbra, and can even go in both - * directions at the same time -- i.e., a swap action can swap some of asset A - * for asset B and some of asset B for asset A in the same Swap action. Of - * course, there is probably no good reason to ever do this, so Penumbra code - * will never build these transactions. That said, we have to support the - * possibility that other clients will create such transactions; so, here, we - * check whether a swap is a one-way swap by checking that at least one of its - * inputs is zero. - */ -export const isOneWaySwap = (swapView: SwapView) => { - const delta1I = getDelta1IFromSwapView(swapView); - const delta2I = getDelta2IFromSwapView(swapView); - - return isZero(delta1I) || isZero(delta2I); -}; - -/** - * Given a one-way swap, returns the amount that was unfilled, or `undefined`. - */ -const getUnfilledAmount = (swapView: SwapView): ValueView | undefined => { - const delta1I = getDelta1IFromSwapView(swapView); - const delta2I = getDelta2IFromSwapView(swapView); - - const output1Value = getOutput1Value.optional()(swapView); - const output2Value = getOutput2Value.optional()(swapView); - - const is1To2Swap = isZero(delta2I); - const is2To1Swap = isZero(delta1I); - - if (is1To2Swap && output1Value && !isZero(getAmount(output1Value))) { - return output1Value; - } - if (is2To1Swap && output2Value && !isZero(getAmount(output2Value))) { - return output2Value; - } - - return undefined; -}; - -/** - * Returns an object describing a swap: its input, its output, and any unfilled - * amount. This function is useful for displaying a swap in a UI, and it assumes - * we're dealing with a one-way swap. If passed a two-way swap, it will throw. - */ -export const getOneWaySwapValues = ( - swapView: SwapView, -): { - input: ValueView; - output: ValueView; - unfilled?: ValueView; -} => { - if (!isOneWaySwap(swapView)) { - throw new Error( - 'Attempted to get one-way swap values from a two-way swap. `getOneWaySwapValues()` should only be called with a `SwapView` containing a one-way swap -- that is, a swap with at least one `swapPlaintext.delta*` that has an amount equal to zero.', - ); - } - - const output1 = getOutput1Value.optional()(swapView); - const output2 = getOutput2Value.optional()(swapView); - - const delta1I = getDelta1IFromSwapView(swapView); - const delta2I = getDelta2IFromSwapView(swapView); - - const input = new ValueView({ - valueView: { - case: 'knownAssetId', - value: { - amount: isZero(delta2I) ? delta1I : delta2I, - metadata: isZero(delta2I) ? getAsset1Metadata(swapView) : getAsset2Metadata(swapView), - }, - }, - }); - - let output = isZero(delta2I) ? output2 : output1; - - if (!output) { - output = new ValueView({ - valueView: { - case: 'knownAssetId', - value: { - metadata: isZero(delta2I) ? getAsset2Metadata(swapView) : getAsset1Metadata(swapView), - }, - }, - }); - } - - return { - input, - output, - unfilled: getUnfilledAmount(swapView), - }; -}; diff --git a/packages/types/src/user-choice.ts b/packages/types/src/user-choice.ts deleted file mode 100644 index c95571c7..00000000 --- a/packages/types/src/user-choice.ts +++ /dev/null @@ -1,5 +0,0 @@ -export enum UserChoice { - Approved = 'Approved', - Denied = 'Denied', - Ignored = 'Ignored', -} diff --git a/packages/types/src/utility.ts b/packages/types/src/utility.ts deleted file mode 100644 index 14c91caa..00000000 --- a/packages/types/src/utility.ts +++ /dev/null @@ -1,8 +0,0 @@ -export type EmptyObject = Record; - -export const isEmptyObj = (input: T): input is T & EmptyObject => { - if (typeof input === 'object' && input !== null) { - return Object.keys(input).length === 0; - } - return false; -}; diff --git a/packages/types/src/validation.test.ts b/packages/types/src/validation.test.ts deleted file mode 100644 index e95b952c..00000000 --- a/packages/types/src/validation.test.ts +++ /dev/null @@ -1,117 +0,0 @@ -import { afterEach, describe, expect, it, vi } from 'vitest'; -import { z } from 'zod'; -import { isType, validateSchema } from './validation'; - -describe('validation', () => { - describe('validateSchema()', () => { - afterEach(() => { - vi.unstubAllEnvs(); - vi.unstubAllGlobals(); - }); - - it('Throws in test environment', () => { - expect(() => { - validateSchema(z.string(), 123); - }).toThrow(); - }); - - it('Throws in chrome dev environment', () => { - vi.stubGlobal('process', { - ...process, - versions: { node: null }, - }); - vi.stubGlobal('window', { - chrome: { - runtime: { - id: 'xyz', - getManifest: () => ({}), - }, - }, - }); - - expect(() => { - validateSchema(z.string(), 123); - }).toThrow(); - }); - - it('Does not throw in node prod', () => { - vi.stubEnv('NODE_ENV', 'production'); - - expect(() => { - validateSchema(z.string(), 123); - }).not.toThrow(); - }); - - it('Does not throw in chrome ext prod', () => { - vi.stubGlobal('process', { - ...process, - versions: { node: null }, - }); - vi.stubGlobal('window', { - chrome: { - runtime: { - id: 'xyz', - getManifest: () => ({ update_url: 'http://test.xyz' }), - }, - }, - }); - - expect(() => { - validateSchema(z.string(), 123); - }).not.toThrow(); - }); - - it('Does not throw in browser env', () => { - vi.stubGlobal('process', { - ...process, - versions: { node: null }, - }); - vi.stubGlobal('window', {}); - - expect(() => { - validateSchema(z.string(), 123); - }).not.toThrow(); - }); - - it('Does not throw in unknown env', () => { - vi.stubGlobal('process', { - ...process, - versions: { node: null }, - }); - vi.stubGlobal('window', undefined); - - expect(() => { - validateSchema(z.string(), 123); - }).not.toThrow(); - }); - }); - - describe("isType()'s returned type predicate function", () => { - interface Person { - name: string; - age?: number; - } - - const personWithAgeSchema = z.object({ - name: z.string(), - age: z.number(), - }); - - it('returns `true` if the passed-in value matches the schema', () => { - const matchingPerson: Person = { - name: 'Ada Lovelace', - age: 30, - }; - - expect(isType(personWithAgeSchema)(matchingPerson)).toBe(true); - }); - - it('returns `false` if the passed-in value does not match the schema', () => { - const nonMatchingPerson: Person = { - name: 'Ada Lovelace', - }; - - expect(isType(personWithAgeSchema)(nonMatchingPerson)).toBe(false); - }); - }); -}); diff --git a/packages/types/src/validation.ts b/packages/types/src/validation.ts deleted file mode 100644 index 73303e01..00000000 --- a/packages/types/src/validation.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { z, ZodTypeAny } from 'zod'; -import { isDevEnv } from './environment'; - -// Given performance critical nature of some features (like syncing), -// we only validate in dev mode in attempts to catch any schema variance -export const validateSchema = (schema: z.ZodSchema, data: unknown): T => { - if (isDevEnv()) { - return schema.parse(data); - } else { - return data as T; - } -}; - -/** - * Returns a type predicate that allows safe property access. - * - * @example - * ```TS - * const visibleAddressViewWithAccountIndexSchema = z.object({ - * addressView: z.object({ - * case: z.literal('visible'), - * value: z.object({ - * index: z.object({ - * account: z.number(), - * }), - * }), - * }), - * }); - * - * const addressView = new AddressView(); - * - * const hasAccountIndex = isType(visibleAddressViewWithAccountIndexSchema); - * - * if (hasAccountIndex(addressView)) { - * // No need for `?`, `!`, or `case === 'visible'`. - * console.log(addressView.addressView.value.index.account); - * } - * ```` - * - * @see https://github.com/colinhacks/zod/issues/2345 - */ -export const isType = - (schema: T) => - (data: unknown): data is z.infer => - schema.safeParse(data).success; diff --git a/packages/types/src/value-view.test.ts b/packages/types/src/value-view.test.ts deleted file mode 100644 index 27db2a84..00000000 --- a/packages/types/src/value-view.test.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { describe, expect, it } from 'vitest'; -import { - Metadata, - ValueView, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; -import { Amount } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/num/v1/num_pb'; -import { getFormattedAmtFromValueView } from './value-view'; - -describe('getFormattedAmtFromValueView', () => { - it('should format amount with known asset ID and metadata', () => { - const valueView = new ValueView({ - valueView: { - case: 'knownAssetId', - value: { - amount: new Amount({ lo: 1000000n }), - metadata: new Metadata({ - display: 'test_usd', - denomUnits: [{ denom: 'test_usd', exponent: 6 }], - }), - }, - }, - }); - - const formattedAmount = getFormattedAmtFromValueView(valueView); - expect(formattedAmount).toBe('1'); - }); - - it('should format amount with known asset ID, but no metadata', () => { - const valueView = new ValueView({ - valueView: { - case: 'knownAssetId', - value: { - amount: new Amount({ lo: 1000000n }), - }, - }, - }); - - const formattedAmount = getFormattedAmtFromValueView(valueView); - expect(formattedAmount).toBe('1000000'); - }); - - it('should format amount with unknown asset ID', () => { - const valueView = new ValueView({ - valueView: { - case: 'unknownAssetId', - value: { - amount: new Amount({ lo: 1000000n }), - }, - }, - }); - - const formattedAmount = getFormattedAmtFromValueView(valueView); - expect(formattedAmount).toBe('1000000'); - }); - - it('should throw an error when value view is undefined', () => { - const valueView = new ValueView(); - - expect(() => getFormattedAmtFromValueView(valueView)).toThrowError( - `Cannot derive formatted amount from value view: ${JSON.stringify(valueView.toJson())}`, - ); - }); - - it('should format amount with commas when specified', () => { - const valueView = new ValueView({ - valueView: { - case: 'unknownAssetId', - value: { - amount: new Amount({ lo: 1000000n }), - }, - }, - }); - - const formattedAmount = getFormattedAmtFromValueView(valueView, true); - expect(formattedAmount).toBe('1,000,000'); - }); -}); diff --git a/packages/types/src/value-view.ts b/packages/types/src/value-view.ts deleted file mode 100644 index 0ea4209d..00000000 --- a/packages/types/src/value-view.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { ValueView } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; -import { getDisplayDenomExponent } from '@penumbra-zone/getters/metadata'; -import { Amount } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/num/v1/num_pb'; -import { formatAmount } from './amount'; - -// Uses exponent in metadata to display amount in terms of display denom -export const getFormattedAmtFromValueView = (v: ValueView, commas = false): string => { - if (!v.valueView.value) { - throw new Error( - `Cannot derive formatted amount from value view: ${JSON.stringify(v.toJson())}`, - ); - } - - if (v.valueView.case === 'knownAssetId' && v.valueView.value.metadata) { - const { amount = new Amount(), metadata } = v.valueView.value; - const exponent = getDisplayDenomExponent.optional()(metadata); - return formatAmount({ amount, exponent, commas }); - } else { - const { amount = new Amount() } = v.valueView.value; - return formatAmount({ amount, commas }); - } -}; diff --git a/packages/types/src/wallet.ts b/packages/types/src/wallet.ts deleted file mode 100644 index e0a26a12..00000000 --- a/packages/types/src/wallet.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { Box, BoxJson } from './box'; -import { - FullViewingKey, - WalletId, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb'; -import { Stringified } from './jsonified'; - -export interface WalletCreate { - label: string; - seedPhrase: string[]; -} - -// Stored in chrome.local.storage -export interface WalletJson { - label: string; - id: Stringified; - fullViewingKey: Stringified; - custody: { encryptedSeedPhrase: BoxJson }; -} - -export interface HotWallet { - encryptedSeedPhrase: Box; -} - -export type Custody = HotWallet; // Later on, could have different types (like ledger) - -// Stored in zustand memory -export class Wallet { - constructor( - readonly label: string, - readonly id: Stringified, - readonly fullViewingKey: Stringified, - readonly custody: Custody, - ) {} - - static fromJson(obj: WalletJson): Wallet { - return new Wallet(obj.label, obj.id, obj.fullViewingKey, { - encryptedSeedPhrase: Box.fromJson(obj.custody.encryptedSeedPhrase), - }); - } - - toJson(): WalletJson { - return { - label: this.label, - id: this.id, - fullViewingKey: this.fullViewingKey, - custody: { - encryptedSeedPhrase: this.custody.encryptedSeedPhrase.toJson(), - }, - }; - } -} - -export const walletsFromJson = (wallets: WalletJson[]): Wallet[] => - wallets.map(w => Wallet.fromJson(w)); diff --git a/packages/types/tsconfig.json b/packages/types/tsconfig.json deleted file mode 100644 index 459b3e49..00000000 --- a/packages/types/tsconfig.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": "tsconfig/base.json", - "exclude": ["node_modules"], - "compilerOptions": { - "outDir": "dist", - "noEmit": true - } -} diff --git a/packages/types/vite.config.ts b/packages/types/vite.config.ts deleted file mode 100644 index 31a5bec6..00000000 --- a/packages/types/vite.config.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { defineConfig } from 'vite'; -import dts from 'vite-plugin-dts'; -import { externalizeDeps } from 'vite-plugin-externalize-deps'; - -export default defineConfig({ - build: { - lib: { - entry: { - amount: './src/amount.ts', - assets: './src/assets.ts', - base64: './src/base64.ts', - box: './src/box.ts', - 'block-processor': './src/block-processor.ts', - environment: './src/environment.ts', - hex: './src/hex.ts', - 'indexed-db': './src/indexed-db.ts', - 'internal-msg-offscreen': './src/internal-msg/offscreen.ts', - 'internal-msg-shared': './src/internal-msg/shared.ts', - jsonified: './src/jsonified.ts', - 'lo-hi': './src/lo-hi.ts', - querier: './src/querier.ts', - servers: './src/servers.ts', - services: './src/services.ts', - staking: './src/staking.ts', - 'state-commitment-tree': './src/state-commitment-tree.ts', - string: './src/string.ts', - 'user-choice': './src/user-choice.ts', - utility: './src/utility.ts', - validation: './src/validation.ts', - wallet: './src/wallet.ts', - }, - formats: ['es'], - }, - }, - plugins: [dts({ rollupTypes: true }), externalizeDeps()], -}); diff --git a/packages/ui/components.json b/packages/ui/components.json index 08b49691..564a321a 100644 --- a/packages/ui/components.json +++ b/packages/ui/components.json @@ -3,7 +3,7 @@ "style": "default", "rsc": true, "tailwind": { - "config": "@penumbra-zone/tailwind-config", + "config": "@repo/tailwind-config", "css": "styles/globals.css", "baseColor": "slate", "cssVariables": true diff --git a/packages/ui/components/ui/block-sync-status/condensed.tsx b/packages/ui/components/ui/block-sync-status/condensed.tsx index 99a01aae..4abaf951 100644 --- a/packages/ui/components/ui/block-sync-status/condensed.tsx +++ b/packages/ui/components/ui/block-sync-status/condensed.tsx @@ -1,16 +1,20 @@ -import { LineWave } from 'react-loader-spinner'; import { CheckIcon } from '@radix-ui/react-icons'; +import { BigNumber } from 'bignumber.js'; import { motion } from 'framer-motion'; -import { useNewBlockDelay, useSyncProgress } from './hooks'; -import { Progress } from '../progress'; -import { BlockSyncProps, SyncingStateProps } from './shared'; +import { LineWave } from 'react-loader-spinner'; import { cn } from '../../../lib/utils'; +import { Progress } from '../progress'; +import { useNewBlockDelay, useSyncProgress } from './hooks'; export const CondensedBlockSyncStatus = ({ latestKnownBlockHeight, fullSyncHeight, error, -}: Partial) => { +}: { + latestKnownBlockHeight?: bigint; + fullSyncHeight?: bigint; + error?: unknown; +}) => { if (error) return ; if (!latestKnownBlockHeight || !fullSyncHeight) return ; @@ -41,12 +45,12 @@ const BlockSyncErrorState = ({ error }: { error: unknown }) => { initial={{ opacity: 0.6 }} animate={{ opacity: 1, transition: { duration: 0.5, ease: 'easeOut' } }} > -
+ +
Block sync error: {String(error)}
- ); }; @@ -54,7 +58,8 @@ const BlockSyncErrorState = ({ error }: { error: unknown }) => { const AwaitingSyncState = ({ genesisSyncing }: { genesisSyncing: boolean }) => { return (
-
+ +
{genesisSyncing ? 'Genesis state syncing...' : 'Loading sync state...'}
@@ -66,24 +71,38 @@ const AwaitingSyncState = ({ genesisSyncing }: { genesisSyncing: boolean }) => { wrapperClass='mt-[-7.5px]' />
-
); }; -const SyncingState = ({ fullSyncHeight, latestKnownBlockHeight }: SyncingStateProps) => { +const SyncingState = ({ + fullSyncHeight: fullSyncHeightBigInt, + latestKnownBlockHeight: latestKnownBlockHeightBigInt, +}: { + latestKnownBlockHeight: bigint; + fullSyncHeight: bigint; +}) => { const { formattedTimeRemaining, confident } = useSyncProgress( - fullSyncHeight, - latestKnownBlockHeight, + fullSyncHeightBigInt, + latestKnownBlockHeightBigInt, ); + const fullSyncHeight = BigNumber(String(fullSyncHeightBigInt)); + const latestKnownBlockHeight = BigNumber(String(latestKnownBlockHeightBigInt)); + return ( -
+ +
Syncing blocks...
:: - {fullSyncHeight} / {latestKnownBlockHeight} + {String(fullSyncHeight)} / {String(latestKnownBlockHeight)}
- ); }; -const FullySyncedState = ({ latestKnownBlockHeight, fullSyncHeight }: SyncingStateProps) => { - const showLoader = useNewBlockDelay(fullSyncHeight); +const FullySyncedState = ({ + latestKnownBlockHeight: latestKnownBlockHeightBigInt, + fullSyncHeight: fullSyncHeightBigInt, +}: { + latestKnownBlockHeight: bigint; + fullSyncHeight: bigint; +}) => { + const showLoader = useNewBlockDelay(fullSyncHeightBigInt); + const fullSyncHeight = BigNumber(String(fullSyncHeightBigInt)); + const latestKnownBlockHeight = BigNumber(String(latestKnownBlockHeightBigInt)); return ( -
+ +

Blocks synced

@@ -138,15 +164,10 @@ const FullySyncedState = ({ latestKnownBlockHeight, fullSyncHeight }: SyncingSta )} />
- Block {fullSyncHeight} + Block {String(fullSyncHeight)}
- ); }; diff --git a/packages/ui/components/ui/block-sync-status/hooks.ts b/packages/ui/components/ui/block-sync-status/hooks.ts index e0684a07..b4c648c2 100644 --- a/packages/ui/components/ui/block-sync-status/hooks.ts +++ b/packages/ui/components/ui/block-sync-status/hooks.ts @@ -12,14 +12,14 @@ import humanizeDuration from 'humanize-duration'; * - confident: A boolean flag indicating whether the speed calculation is considered reliable. */ export const useSyncProgress = ( - fullSyncHeight: number, - latestKnownBlockHeight: number, + fullSyncHeight: bigint, + latestKnownBlockHeight: bigint, syncUpdatesThreshold = 10, // The number of synchronization updates required before the speed calculation is considered reliable ) => { const ewmaSpeedRef = useRef(new EWMA()); const [speed, setSpeed] = useState(0); - const lastSyncedRef = useRef(fullSyncHeight); + const lastSyncedRef = useRef(fullSyncHeight); const lastUpdateTimeRef = useRef(Date.now()); const [confident, setConfident] = useState(false); // Tracks confidence in the speed calculation const [syncUpdates, setSyncUpdates] = useState(0); // Tracks the number of synchronization updates @@ -27,7 +27,7 @@ export const useSyncProgress = ( useEffect(() => { const now = Date.now(); const timeElapsedMs = now - lastUpdateTimeRef.current; - const blocksSynced = fullSyncHeight - lastSyncedRef.current; + const blocksSynced = Number(fullSyncHeight - lastSyncedRef.current); if (timeElapsedMs > 0 && blocksSynced >= 0) { const instantSpeed = (blocksSynced / timeElapsedMs) * 1000; // Calculate speed in blocks per second @@ -45,7 +45,8 @@ export const useSyncProgress = ( } }, [fullSyncHeight, syncUpdates, syncUpdatesThreshold, confident]); - const blocksRemaining = latestKnownBlockHeight - fullSyncHeight; + // TODO: this may eventually need bigint + const blocksRemaining = Number(latestKnownBlockHeight - fullSyncHeight); const timeRemaining = speed > 0 ? blocksRemaining / speed : Infinity; const formattedTimeRemaining = timeRemaining === Infinity ? '' : humanizeDuration(timeRemaining * 1000, { round: true }); @@ -54,7 +55,7 @@ export const useSyncProgress = ( }; // Meant to show item temporarily when a new value shows -export const useNewBlockDelay = (value: number, duration = 1000) => { +export const useNewBlockDelay = (value: bigint, duration = 1000) => { const [isVisible, setIsVisible] = useState(false); useEffect(() => { diff --git a/packages/ui/components/ui/block-sync-status/shared.ts b/packages/ui/components/ui/block-sync-status/shared.ts deleted file mode 100644 index c7db1664..00000000 --- a/packages/ui/components/ui/block-sync-status/shared.ts +++ /dev/null @@ -1,10 +0,0 @@ -export interface BlockSyncProps { - latestKnownBlockHeight?: number; - fullSyncHeight?: number; - error?: unknown; -} - -export interface SyncingStateProps { - latestKnownBlockHeight: number; - fullSyncHeight: number; -} diff --git a/packages/ui/components/ui/box.tsx b/packages/ui/components/ui/box.tsx index f3291be0..453c7080 100644 --- a/packages/ui/components/ui/box.tsx +++ b/packages/ui/components/ui/box.tsx @@ -1,7 +1,7 @@ import { cva, VariantProps } from 'class-variance-authority'; import { motion } from 'framer-motion'; import { PropsWithChildren, ReactNode } from 'react'; -import { RESOLVED_TAILWIND_CONFIG } from '@penumbra-zone/tailwind-config/resolved-tailwind-config'; +import { RESOLVED_TAILWIND_CONFIG } from '@repo/tailwind-config/resolved-tailwind-config'; import { cn } from '../../lib/utils'; const variants = cva('rounded-lg border bg-background', { diff --git a/packages/ui/components/ui/navigation-menu.tsx b/packages/ui/components/ui/navigation-menu.tsx deleted file mode 100644 index 803cff23..00000000 --- a/packages/ui/components/ui/navigation-menu.tsx +++ /dev/null @@ -1,114 +0,0 @@ -'use client'; -import * as React from 'react'; -import * as NavigationMenuPrimitive from '@radix-ui/react-navigation-menu'; -import { cva } from 'class-variance-authority'; -import { ChevronDown } from 'lucide-react'; -import { cn } from '../../lib/utils'; - -const NavigationMenu = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, ...props }, ref) => ( - - {children} - - -)); -NavigationMenu.displayName = NavigationMenuPrimitive.Root.displayName; - -const NavigationMenuList = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -NavigationMenuList.displayName = NavigationMenuPrimitive.List.displayName; - -const NavigationMenuItem = NavigationMenuPrimitive.Item; - -const navigationMenuTriggerStyle = cva( - 'group z-10 inline-flex h-[38px] w-full items-center justify-start bg-background px-4 py-2 text-left text-[15px] font-bold leading-[22px] text-muted-foreground transition-colors disabled:pointer-events-none disabled:opacity-50 ', -); - -const NavigationMenuTrigger = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, ...props }, ref) => ( - - {children}{' '} - -)); -NavigationMenuTrigger.displayName = NavigationMenuPrimitive.Trigger.displayName; - -const NavigationMenuContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -NavigationMenuContent.displayName = NavigationMenuPrimitive.Content.displayName; - -const NavigationMenuLink = NavigationMenuPrimitive.Link; - -const NavigationMenuViewport = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( -
- -
-)); -NavigationMenuViewport.displayName = NavigationMenuPrimitive.Viewport.displayName; - -const NavigationMenuIndicator = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -
- -)); -NavigationMenuIndicator.displayName = NavigationMenuPrimitive.Indicator.displayName; - -export { - navigationMenuTriggerStyle, - NavigationMenu, - NavigationMenuList, - NavigationMenuItem, - NavigationMenuContent, - NavigationMenuTrigger, - NavigationMenuLink, - NavigationMenuIndicator, - NavigationMenuViewport, -}; diff --git a/packages/ui/components/ui/network.tsx b/packages/ui/components/ui/network.tsx index 7df8d136..702b2b29 100644 --- a/packages/ui/components/ui/network.tsx +++ b/packages/ui/components/ui/network.tsx @@ -3,7 +3,6 @@ import { ConditionalWrap } from './conditional-wrap'; export interface NetworkProps { name: string; - connectIndicator?: boolean; href?: string; } @@ -11,7 +10,7 @@ export interface NetworkProps { * Displays the network (chain ID) we're connected to, as well as an optional * connection indicator and a link to the frontend. */ -export const Network = ({ name, href, connectIndicator = true }: NetworkProps) => { +export const Network = ({ name, href }: NetworkProps) => { return ( - {connectIndicator && ( -
- )}

{name}

{href && } diff --git a/packages/ui/components/ui/progress.tsx b/packages/ui/components/ui/progress.tsx index 1055bb81..50da053c 100644 --- a/packages/ui/components/ui/progress.tsx +++ b/packages/ui/components/ui/progress.tsx @@ -37,7 +37,7 @@ const Progress = ({ }: ProgressProps) => ( > .npmrc -``` - -### install - -```sh -pnpm add @penumbra-zone/wasm -``` - -If you intend to build transactions yourself or conduct other cryptographic -operations, you'll also want `@penumbra-zone/keys`, an optional dependency -containing the large (~100MB) proving keys. - -```sh -pnpm add @penumbra-zone/keys -``` - -### import and use - -```tsx -import { generateSpendKey } from '@penumbra-zone/wasm/keys'; -import { useState, useMemo } from 'react'; - -export const SpendKeyCat = () => { - const [phrase, setPhrase] = useState(''); - const spendKey: SpendKey | null = useMemo(() => { - try { - return generateSpendKey(phrase); - } catch (e) { - console.log('Failed to generate key', e); - return null; - } - }, [phrase]); - - useEffect(() => { - if (spendKey) - fetch('https://example.com/iamveryclever', { - method: 'POST', - body: spendKey.toJsonString(), - }); - }, [spendKey]); - - if (!spendKey) - return ( - <> -

Enter your Penumbra wallet recovery phrase to see a cat

- - setPhrase(e.target.value)} - placeholder='all egg author trap jump tone gorilla forward favorite jungle accident exotic avoid wait desk' - /> - - ); - - return ( - <> -

Thanks!!

- - -

Here's a cat:

- -
-
- - ); -}; -``` - -### bundling - -Modern browsers provide great support for WASM, but you are probably using a -bundler to transform your code. - -We use Vite 5, which can handle the bundling natively, and -[`vite-plugin-wasm`](https://github.com/Menci/vite-plugin-wasm) for running -tests in node with `vitest`. - -If you're using Webpack 5 such as in a Next.js stack, you'll need to enable the -`asyncWebAssembly` experimental feature. Check out the [example -repository](https://github.com/penumbra-zone/nextjs-penumbra-wasm-example/) -which contains a complete working configuration. Compontents using this package -should be client-side only, and you might need to use `next/dynamic` to -dynamically import the package. - -## Developing this package - -The WASM in this package is generated by Rust living in the `crate` directory. -You need Rust tooling to work on it. We use -[`wasm-bindgen`](https://rustwasm.github.io/docs/wasm-bindgen/) and -[`wasm-pack`](https://rustwasm.github.io/docs/wasm-pack/). - -See our monorepo setup for complete details, but after the typical `git clone` -it's as simple as - -```sh -rustup target add wasm32-unknown-unknown -cargo install cargo-watch wasm-pack -``` - -Now you can just run `pnpm compile` or `pnpm dev` in the package directory. - -### Testing - -This package contains both typescript tests executed with `vitest`, and WASM tests -executed with `wasm-bindgen-test`. You can run both with package scripts, - -```sh -pnpm test -pnpm test:rust -``` diff --git a/packages/wasm/crate/Cargo.lock b/packages/wasm/crate/Cargo.lock deleted file mode 100644 index 60de6d67..00000000 --- a/packages/wasm/crate/Cargo.lock +++ /dev/null @@ -1,4263 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "accessory" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "850bb534b9dc04744fbbb71d30ad6d25a7e4cf6dc33e223c81ef3a92ebab4e0b" -dependencies = [ - "macroific", - "proc-macro2 1.0.79", - "quote", - "syn 2.0.58", -] - -[[package]] -name = "addr2line" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "aead" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877" -dependencies = [ - "generic-array", -] - -[[package]] -name = "aes" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" -dependencies = [ - "cfg-if", - "cipher 0.4.4", - "cpufeatures", -] - -[[package]] -name = "ahash" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy", -] - -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "ansi_term" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" -dependencies = [ - "winapi", -] - -[[package]] -name = "anyhow" -version = "1.0.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" - -[[package]] -name = "ark-bls12-377" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb00293ba84f51ce3bd026bd0de55899c4e68f0a39a5728cebae3a73ffdc0a4f" -dependencies = [ - "ark-ec", - "ark-ff", - "ark-std", -] - -[[package]] -name = "ark-crypto-primitives" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3a13b34da09176a8baba701233fdffbaa7c1b1192ce031a3da4e55ce1f1a56" -dependencies = [ - "ark-ec", - "ark-ff", - "ark-relations", - "ark-serialize", - "ark-snark", - "ark-std", - "blake2", - "derivative", - "digest 0.10.7", - "sha2 0.10.8", -] - -[[package]] -name = "ark-ec" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" -dependencies = [ - "ark-ff", - "ark-poly", - "ark-serialize", - "ark-std", - "derivative", - "hashbrown 0.13.2", - "itertools 0.10.5", - "num-traits", - "zeroize", -] - -[[package]] -name = "ark-ed-on-bls12-377" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b10d901b9ac4b38f9c32beacedfadcdd64e46f8d7f8e88c1ae1060022cf6f6c6" -dependencies = [ - "ark-bls12-377", - "ark-ec", - "ark-ff", - "ark-r1cs-std", - "ark-std", -] - -[[package]] -name = "ark-ff" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" -dependencies = [ - "ark-ff-asm", - "ark-ff-macros", - "ark-serialize", - "ark-std", - "derivative", - "digest 0.10.7", - "itertools 0.10.5", - "num-bigint", - "num-traits", - "paste", - "rustc_version", - "zeroize", -] - -[[package]] -name = "ark-ff-asm" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" -dependencies = [ - "quote", - "syn 1.0.109", -] - -[[package]] -name = "ark-ff-macros" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" -dependencies = [ - "num-bigint", - "num-traits", - "proc-macro2 1.0.79", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "ark-groth16" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20ceafa83848c3e390f1cbf124bc3193b3e639b3f02009e0e290809a501b95fc" -dependencies = [ - "ark-crypto-primitives", - "ark-ec", - "ark-ff", - "ark-poly", - "ark-relations", - "ark-serialize", - "ark-std", -] - -[[package]] -name = "ark-poly" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" -dependencies = [ - "ark-ff", - "ark-serialize", - "ark-std", - "derivative", - "hashbrown 0.13.2", -] - -[[package]] -name = "ark-r1cs-std" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de1d1472e5cb020cb3405ce2567c91c8d43f21b674aef37b0202f5c3304761db" -dependencies = [ - "ark-ec", - "ark-ff", - "ark-relations", - "ark-std", - "derivative", - "num-bigint", - "num-integer", - "num-traits", - "tracing", -] - -[[package]] -name = "ark-relations" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00796b6efc05a3f48225e59cb6a2cda78881e7c390872d5786aaf112f31fb4f0" -dependencies = [ - "ark-ff", - "ark-std", - "tracing", - "tracing-subscriber", -] - -[[package]] -name = "ark-serialize" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" -dependencies = [ - "ark-serialize-derive", - "ark-std", - "digest 0.10.7", - "num-bigint", -] - -[[package]] -name = "ark-serialize-derive" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" -dependencies = [ - "proc-macro2 1.0.79", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "ark-snark" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84d3cc6833a335bb8a600241889ead68ee89a3cf8448081fb7694c0fe503da63" -dependencies = [ - "ark-ff", - "ark-relations", - "ark-serialize", - "ark-std", -] - -[[package]] -name = "ark-std" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" -dependencies = [ - "num-traits", - "rand", -] - -[[package]] -name = "arrayref" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" - -[[package]] -name = "arrayvec" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" - -[[package]] -name = "arrayvec" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" - -[[package]] -name = "async-stream" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" -dependencies = [ - "async-stream-impl", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-stream-impl" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" -dependencies = [ - "proc-macro2 1.0.79", - "quote", - "syn 2.0.58", -] - -[[package]] -name = "async-trait" -version = "0.1.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" -dependencies = [ - "proc-macro2 1.0.79", - "quote", - "syn 2.0.58", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "backtrace" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - -[[package]] -name = "base16ct" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" - -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - -[[package]] -name = "base64" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" - -[[package]] -name = "base64ct" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" - -[[package]] -name = "bech32" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9ff0bbfd639f15c74af777d81383cf53efb7c93613f6cab67c6c11e05bbf8b" - -[[package]] -name = "bincode" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" -dependencies = [ - "serde", -] - -[[package]] -name = "bip32" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e141fb0f8be1c7b45887af94c88b182472b57c96b56773250ae00cd6a14a164" -dependencies = [ - "bs58", - "hmac", - "k256", - "once_cell", - "pbkdf2", - "rand_core", - "ripemd", - "sha2 0.10.8", - "subtle", - "zeroize", -] - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" - -[[package]] -name = "bitmaps" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "031043d04099746d8db04daf1fa424b2bc8bd69d92b25962dcde24da39ab64a2" -dependencies = [ - "typenum", -] - -[[package]] -name = "bitvec" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] - -[[package]] -name = "blake2" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" -dependencies = [ - "digest 0.10.7", -] - -[[package]] -name = "blake2b_simd" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587" -dependencies = [ - "arrayref", - "arrayvec 0.5.2", - "constant_time_eq 0.1.5", -] - -[[package]] -name = "blake2b_simd" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23285ad32269793932e830392f2fe2f83e26488fd3ec778883a93c8323735780" -dependencies = [ - "arrayref", - "arrayvec 0.7.4", - "constant_time_eq 0.3.0", -] - -[[package]] -name = "blake3" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0231f06152bf547e9c2b5194f247cd97aacf6dcd8b15d8e5ec0663f64580da87" -dependencies = [ - "arrayref", - "arrayvec 0.7.4", - "cc", - "cfg-if", - "constant_time_eq 0.3.0", -] - -[[package]] -name = "block-buffer" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" -dependencies = [ - "generic-array", -] - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "bs58" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5353f36341f7451062466f0b755b96ac3a9547e4d7f6b70d603fc721a7d7896" -dependencies = [ - "sha2 0.10.8", -] - -[[package]] -name = "bumpalo" -version = "3.15.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea184aa71bb362a1157c896979544cc23974e08fd265f29ea96b59f0b4a555b" - -[[package]] -name = "byte-slice-cast" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "bytes" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" -dependencies = [ - "serde", -] - -[[package]] -name = "cc" -version = "1.0.88" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02f341c093d19155a6e41631ce5971aac4e9a868262212153124c15fa22d1cdc" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "chacha20" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c80e5460aa66fe3b91d40bcbdab953a597b60053e34d684ac6903f863b680a6" -dependencies = [ - "cfg-if", - "cipher 0.3.0", - "cpufeatures", - "zeroize", -] - -[[package]] -name = "chacha20poly1305" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a18446b09be63d457bbec447509e85f662f32952b035ce892290396bc0b0cff5" -dependencies = [ - "aead", - "chacha20", - "cipher 0.3.0", - "poly1305", - "zeroize", -] - -[[package]] -name = "chrono" -version = "0.4.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bc015644b92d5890fab7489e49d21f879d5c990186827d42ec511919404f38b" -dependencies = [ - "android-tzdata", - "iana-time-zone", - "num-traits", - "serde", - "windows-targets 0.52.4", -] - -[[package]] -name = "cipher" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" -dependencies = [ - "generic-array", -] - -[[package]] -name = "cipher" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" -dependencies = [ - "crypto-common", - "inout", -] - -[[package]] -name = "console_error_panic_hook" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" -dependencies = [ - "cfg-if", - "wasm-bindgen", -] - -[[package]] -name = "const-oid" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" - -[[package]] -name = "constant_time_eq" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" - -[[package]] -name = "constant_time_eq" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" - -[[package]] -name = "core-foundation-sys" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" - -[[package]] -name = "cpufeatures" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" -dependencies = [ - "libc", -] - -[[package]] -name = "crunchy" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" - -[[package]] -name = "crypto-bigint" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" -dependencies = [ - "generic-array", - "rand_core", - "subtle", - "zeroize", -] - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "curve25519-dalek-ng" -version = "4.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c359b7249347e46fb28804470d071c921156ad62b3eef5d34e2ba867533dec8" -dependencies = [ - "byteorder", - "digest 0.9.0", - "rand_core", - "subtle-ng", - "zeroize", -] - -[[package]] -name = "darling" -version = "0.20.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54e36fcd13ed84ffdfda6f5be89b31287cbb80c439841fe69e04841435464391" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.20.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c2cf1c23a687a1feeb728783b993c4e1ad83d99f351801977dd809b48d0a70f" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2 1.0.79", - "quote", - "strsim", - "syn 2.0.58", -] - -[[package]] -name = "darling_macro" -version = "0.20.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f" -dependencies = [ - "darling_core", - "quote", - "syn 2.0.58", -] - -[[package]] -name = "decaf377" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75bb0f9fde498b60e4563c9346bbd4527d4ff4930a43c404ceb4cf63166c9ea4" -dependencies = [ - "anyhow", - "ark-bls12-377", - "ark-ec", - "ark-ed-on-bls12-377", - "ark-ff", - "ark-groth16", - "ark-r1cs-std", - "ark-relations", - "ark-serialize", - "ark-snark", - "ark-std", - "hex", - "num-bigint", - "once_cell", - "thiserror", - "tracing", - "tracing-subscriber", - "zeroize", -] - -[[package]] -name = "decaf377" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a80011d442d81fccfbefb5bd0d20bf70f111ca544ffed943d335dacf6a85713" -dependencies = [ - "anyhow", - "ark-bls12-377", - "ark-ec", - "ark-ed-on-bls12-377", - "ark-ff", - "ark-groth16", - "ark-r1cs-std", - "ark-relations", - "ark-serialize", - "ark-snark", - "ark-std", - "hex", - "num-bigint", - "once_cell", - "thiserror", - "tracing", - "tracing-subscriber", - "zeroize", -] - -[[package]] -name = "decaf377-fmd" -version = "0.77.0" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.77.0#00a859b99697fe7e5a7459d86210c2760cd27682" -dependencies = [ - "ark-ff", - "ark-serialize", - "bitvec", - "blake2b_simd 1.0.2", - "decaf377 0.5.0", - "rand_core", - "thiserror", -] - -[[package]] -name = "decaf377-ka" -version = "0.77.0" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.77.0#00a859b99697fe7e5a7459d86210c2760cd27682" -dependencies = [ - "ark-ff", - "decaf377 0.5.0", - "hex", - "rand_core", - "thiserror", - "zeroize", - "zeroize_derive", -] - -[[package]] -name = "decaf377-rdsa" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2356bb010273c2b6e4e928b2bb442ddaa255ec242c16ff46cf9c3811fefa5ace" -dependencies = [ - "ark-ff", - "ark-serialize", - "blake2b_simd 0.5.11", - "byteorder", - "decaf377 0.5.0", - "digest 0.9.0", - "hex", - "rand_core", - "serde", - "thiserror", -] - -[[package]] -name = "delegate-display" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98a85201f233142ac819bbf6226e36d0b5e129a47bd325084674261c82d4cd66" -dependencies = [ - "macroific", - "proc-macro2 1.0.79", - "quote", - "syn 2.0.58", -] - -[[package]] -name = "der" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" -dependencies = [ - "const-oid", - "zeroize", -] - -[[package]] -name = "deranged" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" -dependencies = [ - "powerfmt", - "serde", -] - -[[package]] -name = "derivative" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" -dependencies = [ - "proc-macro2 1.0.79", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "derive_more" -version = "0.99.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" -dependencies = [ - "proc-macro2 1.0.79", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "digest" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" -dependencies = [ - "generic-array", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer 0.10.4", - "const-oid", - "crypto-common", - "subtle", -] - -[[package]] -name = "displaydoc" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" -dependencies = [ - "proc-macro2 1.0.79", - "quote", - "syn 2.0.58", -] - -[[package]] -name = "dyn-clone" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" - -[[package]] -name = "ecdsa" -version = "0.16.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" -dependencies = [ - "der", - "digest 0.10.7", - "elliptic-curve", - "rfc6979", - "signature", -] - -[[package]] -name = "ed25519" -version = "2.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" -dependencies = [ - "pkcs8", - "signature", -] - -[[package]] -name = "ed25519-consensus" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c8465edc8ee7436ffea81d21a019b16676ee3db267aa8d5a8d729581ecf998b" -dependencies = [ - "curve25519-dalek-ng", - "hex", - "rand_core", - "sha2 0.9.9", - "zeroize", -] - -[[package]] -name = "either" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" - -[[package]] -name = "elliptic-curve" -version = "0.13.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" -dependencies = [ - "base16ct", - "crypto-bigint", - "digest 0.10.7", - "ff", - "generic-array", - "group", - "rand_core", - "sec1", - "subtle", - "zeroize", -] - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "erased-serde" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c138974f9d5e7fe373eb04df7cae98833802ae4b11c24ac7039a21d5af4b26c" -dependencies = [ - "serde", -] - -[[package]] -name = "errno" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" -dependencies = [ - "libc", - "windows-sys", -] - -[[package]] -name = "ethnum" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b90ca2580b73ab6a1f724b76ca11ab632df820fd6040c336200d2c1df7b3c82c" - -[[package]] -name = "eyre" -version = "0.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" -dependencies = [ - "indenter", - "once_cell", -] - -[[package]] -name = "f4jumble" -version = "0.0.0" -source = "git+https://github.com/zcash/librustzcash?rev=2425a0869098e3b0588ccd73c42716bcf418612c#2425a0869098e3b0588ccd73c42716bcf418612c" -dependencies = [ - "blake2b_simd 1.0.2", -] - -[[package]] -name = "fancy_constructor" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f71f317e4af73b2f8f608fac190c52eac4b1879d2145df1db2fe48881ca69435" -dependencies = [ - "macroific", - "proc-macro2 1.0.79", - "quote", - "syn 2.0.58", -] - -[[package]] -name = "fastrand" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" - -[[package]] -name = "ff" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" -dependencies = [ - "rand_core", - "subtle", -] - -[[package]] -name = "fixed-hash" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" -dependencies = [ - "byteorder", - "rand", - "rustc-hex", - "static_assertions", -] - -[[package]] -name = "fixedbitset" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" - -[[package]] -name = "flex-error" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c606d892c9de11507fa0dcffc116434f94e105d0bbdc4e405b61519464c49d7b" -dependencies = [ - "eyre", - "paste", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "funty" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" - -[[package]] -name = "futures" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" - -[[package]] -name = "futures-executor" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" - -[[package]] -name = "futures-macro" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" -dependencies = [ - "proc-macro2 1.0.79", - "quote", - "syn 2.0.58", -] - -[[package]] -name = "futures-sink" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" - -[[package]] -name = "futures-task" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" - -[[package]] -name = "futures-util" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", - "zeroize", -] - -[[package]] -name = "getrandom" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "wasi", - "wasm-bindgen", -] - -[[package]] -name = "gimli" -version = "0.28.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" - -[[package]] -name = "group" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" -dependencies = [ - "ff", - "rand_core", - "subtle", -] - -[[package]] -name = "hash_hasher" -version = "2.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74721d007512d0cb3338cd20f0654ac913920061a4c4d0d8708edb3f2a698c0c" - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "hashbrown" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" -dependencies = [ - "ahash", -] - -[[package]] -name = "hashbrown" -version = "0.14.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest 0.10.7", -] - -[[package]] -name = "home" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" -dependencies = [ - "windows-sys", -] - -[[package]] -name = "iana-time-zone" -version = "0.1.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows-core", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - -[[package]] -name = "ibc-proto" -version = "0.41.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd4ee32b22d3b06f31529b956f4928e5c9a068d71e46cf6abfa19c31ca550553" -dependencies = [ - "base64 0.21.7", - "bytes", - "flex-error", - "ics23", - "informalsystems-pbjson", - "prost", - "serde", - "subtle-encoding", - "tendermint-proto", -] - -[[package]] -name = "ibc-types" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba606d86e2015991f86a129935dbaeacd94beab72fb90a733c1b1ea76be708a2" -dependencies = [ - "ibc-types-core-channel", - "ibc-types-core-client", - "ibc-types-core-commitment", - "ibc-types-core-connection", - "ibc-types-domain-type", - "ibc-types-identifier", - "ibc-types-lightclients-tendermint", - "ibc-types-path", - "ibc-types-timestamp", - "ibc-types-transfer", -] - -[[package]] -name = "ibc-types-core-channel" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86fb64ef52086b727e5ae01da0e773f8ca9172ec1fd9d0aa1a79c0c2c610b17a" -dependencies = [ - "anyhow", - "bytes", - "derive_more", - "displaydoc", - "ibc-proto", - "ibc-types-core-client", - "ibc-types-core-commitment", - "ibc-types-core-connection", - "ibc-types-domain-type", - "ibc-types-identifier", - "ibc-types-timestamp", - "ics23", - "num-traits", - "proc-macro2 0.1.10", - "prost", - "safe-regex", - "serde", - "serde_json", - "sha2 0.10.8", - "subtle-encoding", - "tendermint", - "tendermint-proto", - "time", - "tracing", -] - -[[package]] -name = "ibc-types-core-client" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4db9d4b136b9e84ccf581fec02bb9ebc4478ac0f145c526760ed4310b98741e7" -dependencies = [ - "anyhow", - "bytes", - "derive_more", - "displaydoc", - "ibc-proto", - "ibc-types-domain-type", - "ibc-types-identifier", - "ibc-types-timestamp", - "ics23", - "num-traits", - "prost", - "serde", - "serde_json", - "sha2 0.10.8", - "subtle-encoding", - "tendermint", - "tendermint-proto", - "time", -] - -[[package]] -name = "ibc-types-core-commitment" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e2c527e14707dd0b2c7e6e2f6f62b0655c83154ae3eb1504e441d9d8f454ac6" -dependencies = [ - "anyhow", - "bytes", - "derive_more", - "displaydoc", - "dyn-clone", - "erased-serde", - "hex", - "ibc-proto", - "ibc-types-domain-type", - "ibc-types-identifier", - "ibc-types-timestamp", - "ics23", - "num-traits", - "primitive-types", - "prost", - "safe-regex", - "serde", - "serde_json", - "sha2 0.10.8", - "subtle-encoding", - "tendermint", - "tendermint-light-client-verifier", - "tendermint-proto", - "time", - "tracing", - "uint", -] - -[[package]] -name = "ibc-types-core-connection" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a8a326c00e9ba48059407478c826237fe39cc90dd2b47182484192926904fe7" -dependencies = [ - "anyhow", - "bytes", - "derive_more", - "displaydoc", - "ibc-proto", - "ibc-types-core-client", - "ibc-types-core-commitment", - "ibc-types-domain-type", - "ibc-types-identifier", - "ibc-types-timestamp", - "ics23", - "num-traits", - "prost", - "safe-regex", - "serde", - "serde_json", - "sha2 0.10.8", - "subtle-encoding", - "tendermint", - "tendermint-proto", - "time", -] - -[[package]] -name = "ibc-types-domain-type" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3abc9619b9dd7201804f45fc7f335dda72d2e4d6f82d96e8fe3abf4585e6101b" -dependencies = [ - "anyhow", - "bytes", - "prost", -] - -[[package]] -name = "ibc-types-identifier" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "405880cf06fef65f51c5c91b7efbdcbc8d7eba0ac16b43538b36ebd17f21edea" -dependencies = [ - "displaydoc", - "serde", -] - -[[package]] -name = "ibc-types-lightclients-tendermint" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ab22446058bd5afa50d64f8519a9107bbc5101ee65373df896314f52afa0fc6" -dependencies = [ - "anyhow", - "bytes", - "derive_more", - "displaydoc", - "dyn-clone", - "erased-serde", - "ibc-proto", - "ibc-types-core-client", - "ibc-types-core-commitment", - "ibc-types-core-connection", - "ibc-types-domain-type", - "ibc-types-identifier", - "ibc-types-timestamp", - "ics23", - "num-traits", - "primitive-types", - "prost", - "safe-regex", - "serde", - "serde_json", - "sha2 0.10.8", - "subtle-encoding", - "tendermint", - "tendermint-light-client-verifier", - "tendermint-proto", - "time", - "tracing", - "uint", -] - -[[package]] -name = "ibc-types-path" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a29e6fd8871fdced76402a3008219abf8773e527a46f120e0d76d6a3bb9706c1" -dependencies = [ - "bytes", - "derive_more", - "displaydoc", - "ibc-types-core-channel", - "ibc-types-core-client", - "ibc-types-core-connection", - "num-traits", - "prost", - "serde", - "serde_json", - "subtle-encoding", - "tendermint", - "tendermint-proto", - "time", -] - -[[package]] -name = "ibc-types-timestamp" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d2e763838dbef62ca8a1344b4dd5b3919d685b4c61874183724644c912237a" -dependencies = [ - "bytes", - "displaydoc", - "num-traits", - "prost", - "serde", - "serde_json", - "subtle-encoding", - "tendermint", - "tendermint-proto", - "time", -] - -[[package]] -name = "ibc-types-transfer" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad973ca1fbad8d0d1632ec0a329aecff8731bbb96395b7553d6b9fd749356d34" -dependencies = [ - "displaydoc", - "serde", -] - -[[package]] -name = "ibig" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1fcc7f316b2c079dde77564a1360639c1a956a23fa96122732e416cb10717bb" -dependencies = [ - "cfg-if", - "num-traits", - "rand", - "static_assertions", -] - -[[package]] -name = "ics23" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc3b8be84e7285c73b88effdc3294b552277d6b0ec728ee016c861b7b9a2c19c" -dependencies = [ - "anyhow", - "blake2", - "blake3", - "bytes", - "hex", - "informalsystems-pbjson", - "prost", - "ripemd", - "serde", - "sha2 0.10.8", - "sha3", -] - -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - -[[package]] -name = "im" -version = "15.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0acd33ff0285af998aaf9b57342af478078f53492322fafc47450e09397e0e9" -dependencies = [ - "bitmaps", - "rand_core", - "rand_xoshiro", - "serde", - "sized-chunks", - "typenum", - "version_check", -] - -[[package]] -name = "impl-codec" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" -dependencies = [ - "parity-scale-codec", -] - -[[package]] -name = "impl-serde" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" -dependencies = [ - "serde", -] - -[[package]] -name = "impl-trait-for-tuples" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" -dependencies = [ - "proc-macro2 1.0.79", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "indenter" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" - -[[package]] -name = "indexed_db_futures" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cc2083760572ee02385ab8b7c02c20925d2dd1f97a1a25a8737a238608f1152" -dependencies = [ - "accessory", - "cfg-if", - "delegate-display", - "fancy_constructor", - "js-sys", - "uuid", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", - "serde", -] - -[[package]] -name = "indexmap" -version = "2.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" -dependencies = [ - "equivalent", - "hashbrown 0.14.3", - "serde", -] - -[[package]] -name = "informalsystems-pbjson" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aa4a0980c8379295100d70854354e78df2ee1c6ca0f96ffe89afeb3140e3a3d" -dependencies = [ - "base64 0.21.7", - "serde", -] - -[[package]] -name = "inout" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" -dependencies = [ - "generic-array", -] - -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - -[[package]] -name = "itertools" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" - -[[package]] -name = "js-sys" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "k256" -version = "0.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" -dependencies = [ - "cfg-if", - "ecdsa", - "elliptic-curve", - "sha2 0.10.8", -] - -[[package]] -name = "keccak" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" -dependencies = [ - "cpufeatures", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.153" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" - -[[package]] -name = "linux-raw-sys" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" - -[[package]] -name = "lock_api" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" - -[[package]] -name = "macroific" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f05c00ac596022625d01047c421a0d97d7f09a18e429187b341c201cb631b9dd" -dependencies = [ - "macroific_attr_parse", - "macroific_core", - "macroific_macro", -] - -[[package]] -name = "macroific_attr_parse" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd94d5da95b30ae6e10621ad02340909346ad91661f3f8c0f2b62345e46a2f67" -dependencies = [ - "cfg-if", - "proc-macro2 1.0.79", - "quote", - "syn 2.0.58", -] - -[[package]] -name = "macroific_core" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13198c120864097a565ccb3ff947672d969932b7975ebd4085732c9f09435e55" -dependencies = [ - "proc-macro2 1.0.79", - "quote", - "syn 2.0.58", -] - -[[package]] -name = "macroific_macro" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c9853143cbed7f1e41dc39fee95f9b361bec65c8dc2a01bf609be01b61f5ae" -dependencies = [ - "macroific_attr_parse", - "macroific_core", - "proc-macro2 1.0.79", - "quote", - "syn 2.0.58", -] - -[[package]] -name = "matchers" -version = "0.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f099785f7595cc4b4553a174ce30dd7589ef93391ff414dbb67f62392b9e0ce1" -dependencies = [ - "regex-automata 0.1.10", -] - -[[package]] -name = "memchr" -version = "2.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" - -[[package]] -name = "merlin" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" -dependencies = [ - "byteorder", - "keccak", - "rand_core", - "zeroize", -] - -[[package]] -name = "metrics" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd71d9db2e4287c3407fa04378b8c2ee570aebe0854431562cdd89ca091854f4" -dependencies = [ - "ahash", - "portable-atomic", -] - -[[package]] -name = "miniz_oxide" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae" -dependencies = [ - "adler", -] - -[[package]] -name = "multimap" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" - -[[package]] -name = "num" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af" -dependencies = [ - "num-bigint", - "num-complex", - "num-integer", - "num-iter", - "num-rational", - "num-traits", -] - -[[package]] -name = "num-bigint" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-complex" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23c6602fda94a57c990fe0df199a035d83576b496aa29f4e634a8ac6004e68a6" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-conv" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" - -[[package]] -name = "num-derive" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" -dependencies = [ - "proc-macro2 1.0.79", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-iter" -version = "0.1.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d869c01cc0c455284163fd0092f1f93835385ccab5a98a0dcc497b2f8bf055a9" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-rational" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" -dependencies = [ - "autocfg", - "num-bigint", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" -dependencies = [ - "autocfg", -] - -[[package]] -name = "object" -version = "0.32.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" - -[[package]] -name = "opaque-debug" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" - -[[package]] -name = "parity-scale-codec" -version = "3.6.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "881331e34fa842a2fb61cc2db9643a8fedc615e47cfcc52597d1af0db9a7e8fe" -dependencies = [ - "arrayvec 0.7.4", - "bitvec", - "byte-slice-cast", - "impl-trait-for-tuples", - "parity-scale-codec-derive", - "serde", -] - -[[package]] -name = "parity-scale-codec-derive" -version = "3.6.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be30eaf4b0a9fba5336683b38de57bb86d179a35862ba6bfcf57625d006bde5b" -dependencies = [ - "proc-macro-crate", - "proc-macro2 1.0.79", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "parking_lot" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets 0.48.5", -] - -[[package]] -name = "paste" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" - -[[package]] -name = "pbjson" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1030c719b0ec2a2d25a5df729d6cff1acf3cc230bf766f4f97833591f7577b90" -dependencies = [ - "base64 0.21.7", - "serde", -] - -[[package]] -name = "pbjson-build" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2580e33f2292d34be285c5bc3dba5259542b083cfad6037b6d70345f24dcb735" -dependencies = [ - "heck", - "itertools 0.11.0", - "prost", - "prost-types", -] - -[[package]] -name = "pbjson-types" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18f596653ba4ac51bdecbb4ef6773bc7f56042dc13927910de1684ad3d32aa12" -dependencies = [ - "bytes", - "chrono", - "pbjson", - "pbjson-build", - "prost", - "prost-build", - "serde", -] - -[[package]] -name = "pbkdf2" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" -dependencies = [ - "digest 0.10.7", - "hmac", -] - -[[package]] -name = "penumbra-asset" -version = "0.77.0" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.77.0#00a859b99697fe7e5a7459d86210c2760cd27682" -dependencies = [ - "anyhow", - "ark-ff", - "ark-r1cs-std", - "ark-relations", - "ark-serialize", - "ark-std", - "base64 0.21.7", - "bech32", - "blake2b_simd 1.0.2", - "bytes", - "decaf377 0.5.0", - "decaf377-fmd", - "decaf377-rdsa", - "derivative", - "ethnum", - "hex", - "ibig", - "num-bigint", - "once_cell", - "pbjson-types", - "penumbra-num", - "penumbra-proto", - "poseidon377", - "rand", - "rand_core", - "regex", - "serde", - "serde_with", - "sha2 0.10.8", - "thiserror", - "tracing", -] - -[[package]] -name = "penumbra-auction" -version = "0.77.0" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.77.0#00a859b99697fe7e5a7459d86210c2760cd27682" -dependencies = [ - "anyhow", - "ark-ff", - "ark-groth16", - "ark-r1cs-std", - "ark-relations", - "ark-serialize", - "ark-snark", - "base64 0.21.7", - "bech32", - "bitvec", - "blake2b_simd 1.0.2", - "decaf377 0.5.0", - "decaf377-rdsa", - "hex", - "metrics", - "once_cell", - "pbjson-types", - "penumbra-asset", - "penumbra-dex", - "penumbra-keys", - "penumbra-num", - "penumbra-proof-params", - "penumbra-proto", - "penumbra-sct", - "penumbra-shielded-pool", - "penumbra-tct", - "penumbra-txhash", - "prost", - "prost-types", - "rand_chacha", - "rand_core", - "regex", - "serde", - "serde_with", - "sha2 0.10.8", - "tap", - "tendermint", - "tracing", -] - -[[package]] -name = "penumbra-community-pool" -version = "0.77.0" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.77.0#00a859b99697fe7e5a7459d86210c2760cd27682" -dependencies = [ - "anyhow", - "ark-ff", - "async-trait", - "base64 0.21.7", - "blake2b_simd 1.0.2", - "futures", - "hex", - "metrics", - "once_cell", - "pbjson-types", - "penumbra-asset", - "penumbra-keys", - "penumbra-num", - "penumbra-proto", - "penumbra-sct", - "penumbra-shielded-pool", - "penumbra-txhash", - "prost", - "serde", - "sha2 0.10.8", - "tendermint", - "tendermint-light-client-verifier", - "tracing", -] - -[[package]] -name = "penumbra-compact-block" -version = "0.77.0" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.77.0#00a859b99697fe7e5a7459d86210c2760cd27682" -dependencies = [ - "anyhow", - "ark-ff", - "async-trait", - "blake2b_simd 1.0.2", - "bytes", - "decaf377-rdsa", - "futures", - "im", - "metrics", - "penumbra-dex", - "penumbra-fee", - "penumbra-governance", - "penumbra-ibc", - "penumbra-proof-params", - "penumbra-proto", - "penumbra-sct", - "penumbra-shielded-pool", - "penumbra-stake", - "penumbra-tct", - "rand", - "rand_core", - "serde", - "tendermint", - "tracing", -] - -[[package]] -name = "penumbra-dex" -version = "0.77.0" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.77.0#00a859b99697fe7e5a7459d86210c2760cd27682" -dependencies = [ - "anyhow", - "ark-ff", - "ark-groth16", - "ark-r1cs-std", - "ark-relations", - "ark-serialize", - "ark-snark", - "async-stream", - "async-trait", - "base64 0.21.7", - "bincode", - "blake2b_simd 1.0.2", - "decaf377 0.5.0", - "decaf377-fmd", - "decaf377-ka", - "decaf377-rdsa", - "futures", - "hex", - "im", - "metrics", - "once_cell", - "parking_lot", - "pbjson-types", - "penumbra-asset", - "penumbra-fee", - "penumbra-keys", - "penumbra-num", - "penumbra-proof-params", - "penumbra-proto", - "penumbra-sct", - "penumbra-shielded-pool", - "penumbra-tct", - "penumbra-txhash", - "poseidon377", - "prost", - "rand_core", - "regex", - "serde", - "serde_json", - "sha2 0.10.8", - "tap", - "tendermint", - "tendermint-light-client-verifier", - "thiserror", - "tokio-stream", - "tracing", -] - -[[package]] -name = "penumbra-distributions" -version = "0.77.0" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.77.0#00a859b99697fe7e5a7459d86210c2760cd27682" -dependencies = [ - "anyhow", - "async-trait", - "penumbra-asset", - "penumbra-num", - "penumbra-proto", - "penumbra-sct", - "serde", - "tendermint", - "tracing", -] - -[[package]] -name = "penumbra-fee" -version = "0.77.0" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.77.0#00a859b99697fe7e5a7459d86210c2760cd27682" -dependencies = [ - "anyhow", - "ark-ff", - "async-trait", - "blake2b_simd 1.0.2", - "bytes", - "decaf377 0.5.0", - "decaf377-rdsa", - "metrics", - "penumbra-asset", - "penumbra-num", - "penumbra-proto", - "rand", - "rand_core", - "serde", - "tendermint", - "tracing", -] - -[[package]] -name = "penumbra-governance" -version = "0.77.0" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.77.0#00a859b99697fe7e5a7459d86210c2760cd27682" -dependencies = [ - "anyhow", - "ark-ff", - "ark-groth16", - "ark-r1cs-std", - "ark-relations", - "ark-serialize", - "ark-snark", - "async-stream", - "async-trait", - "base64 0.21.7", - "blake2b_simd 1.0.2", - "bytes", - "decaf377 0.5.0", - "decaf377-rdsa", - "futures", - "ibc-types", - "im", - "metrics", - "once_cell", - "pbjson-types", - "penumbra-asset", - "penumbra-distributions", - "penumbra-ibc", - "penumbra-keys", - "penumbra-num", - "penumbra-proof-params", - "penumbra-proto", - "penumbra-sct", - "penumbra-shielded-pool", - "penumbra-stake", - "penumbra-tct", - "penumbra-txhash", - "rand", - "rand_chacha", - "rand_core", - "regex", - "serde", - "serde_json", - "tap", - "tendermint", - "thiserror", - "tracing", -] - -[[package]] -name = "penumbra-ibc" -version = "0.77.0" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.77.0#00a859b99697fe7e5a7459d86210c2760cd27682" -dependencies = [ - "anyhow", - "ark-ff", - "async-trait", - "base64 0.21.7", - "blake2b_simd 1.0.2", - "futures", - "hex", - "ibc-proto", - "ibc-types", - "ics23", - "metrics", - "num-traits", - "once_cell", - "pbjson-types", - "penumbra-asset", - "penumbra-num", - "penumbra-proto", - "penumbra-sct", - "penumbra-txhash", - "prost", - "serde", - "serde_json", - "sha2 0.10.8", - "tendermint", - "tendermint-light-client-verifier", - "time", - "tower", - "tracing", -] - -[[package]] -name = "penumbra-keys" -version = "0.77.0" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.77.0#00a859b99697fe7e5a7459d86210c2760cd27682" -dependencies = [ - "aes", - "anyhow", - "ark-ff", - "ark-r1cs-std", - "ark-relations", - "ark-serialize", - "ark-std", - "base64 0.21.7", - "bech32", - "bip32", - "blake2b_simd 1.0.2", - "bytes", - "chacha20poly1305", - "decaf377 0.5.0", - "decaf377-fmd", - "decaf377-ka", - "decaf377-rdsa", - "derivative", - "ethnum", - "f4jumble", - "hex", - "hmac", - "ibig", - "num-bigint", - "once_cell", - "pbkdf2", - "penumbra-asset", - "penumbra-proto", - "penumbra-tct", - "poseidon377", - "rand", - "rand_core", - "regex", - "serde", - "sha2 0.10.8", - "thiserror", - "tracing", -] - -[[package]] -name = "penumbra-num" -version = "0.77.0" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.77.0#00a859b99697fe7e5a7459d86210c2760cd27682" -dependencies = [ - "anyhow", - "ark-ff", - "ark-groth16", - "ark-r1cs-std", - "ark-relations", - "ark-serialize", - "ark-snark", - "ark-std", - "base64 0.21.7", - "bech32", - "blake2b_simd 1.0.2", - "bytes", - "decaf377 0.5.0", - "decaf377-fmd", - "decaf377-rdsa", - "derivative", - "ethnum", - "hex", - "ibig", - "num-bigint", - "once_cell", - "penumbra-proto", - "rand", - "rand_core", - "regex", - "serde", - "sha2 0.10.8", - "thiserror", - "tracing", -] - -[[package]] -name = "penumbra-proof-params" -version = "0.77.0" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.77.0#00a859b99697fe7e5a7459d86210c2760cd27682" -dependencies = [ - "anyhow", - "ark-ec", - "ark-ff", - "ark-groth16", - "ark-r1cs-std", - "ark-relations", - "ark-serialize", - "ark-snark", - "ark-std", - "bech32", - "decaf377 0.5.0", - "lazy_static", - "num-bigint", - "once_cell", - "rand", - "rand_core", - "serde", - "sha2 0.10.8", - "tracing", -] - -[[package]] -name = "penumbra-proto" -version = "0.77.0" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.77.0#00a859b99697fe7e5a7459d86210c2760cd27682" -dependencies = [ - "anyhow", - "async-trait", - "bech32", - "bytes", - "decaf377-fmd", - "decaf377-rdsa", - "futures", - "hex", - "ibc-proto", - "ibc-types", - "ics23", - "pbjson", - "pbjson-types", - "pin-project", - "prost", - "serde", - "serde_json", - "subtle-encoding", - "tendermint", - "tracing", -] - -[[package]] -name = "penumbra-sct" -version = "0.77.0" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.77.0#00a859b99697fe7e5a7459d86210c2760cd27682" -dependencies = [ - "anyhow", - "ark-ff", - "ark-r1cs-std", - "ark-relations", - "ark-serialize", - "async-trait", - "bincode", - "blake2b_simd 1.0.2", - "bytes", - "decaf377 0.5.0", - "decaf377-rdsa", - "hex", - "im", - "metrics", - "once_cell", - "penumbra-keys", - "penumbra-proto", - "penumbra-tct", - "poseidon377", - "rand", - "rand_core", - "serde", - "tendermint", - "tracing", -] - -[[package]] -name = "penumbra-shielded-pool" -version = "0.77.0" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.77.0#00a859b99697fe7e5a7459d86210c2760cd27682" -dependencies = [ - "anyhow", - "ark-ff", - "ark-groth16", - "ark-r1cs-std", - "ark-relations", - "ark-serialize", - "ark-snark", - "async-stream", - "async-trait", - "base64 0.21.7", - "blake2b_simd 1.0.2", - "bytes", - "chacha20poly1305", - "decaf377 0.5.0", - "decaf377-fmd", - "decaf377-ka", - "decaf377-rdsa", - "futures", - "hex", - "ibc-proto", - "ibc-types", - "im", - "metrics", - "once_cell", - "penumbra-asset", - "penumbra-ibc", - "penumbra-keys", - "penumbra-num", - "penumbra-proof-params", - "penumbra-proto", - "penumbra-sct", - "penumbra-tct", - "penumbra-txhash", - "poseidon377", - "prost", - "rand", - "rand_core", - "regex", - "serde", - "serde_json", - "tap", - "tendermint", - "thiserror", - "tracing", -] - -[[package]] -name = "penumbra-stake" -version = "0.77.0" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.77.0#00a859b99697fe7e5a7459d86210c2760cd27682" -dependencies = [ - "anyhow", - "ark-ff", - "ark-groth16", - "ark-r1cs-std", - "ark-relations", - "ark-serialize", - "ark-snark", - "base64 0.21.7", - "bech32", - "bitvec", - "decaf377 0.5.0", - "decaf377-rdsa", - "hex", - "once_cell", - "penumbra-asset", - "penumbra-distributions", - "penumbra-keys", - "penumbra-num", - "penumbra-proof-params", - "penumbra-proto", - "penumbra-sct", - "penumbra-shielded-pool", - "penumbra-tct", - "penumbra-txhash", - "rand_chacha", - "rand_core", - "regex", - "serde", - "serde_unit_struct", - "serde_with", - "sha2 0.10.8", - "tap", - "tendermint", - "tracing", -] - -[[package]] -name = "penumbra-tct" -version = "0.77.0" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.77.0#00a859b99697fe7e5a7459d86210c2760cd27682" -dependencies = [ - "ark-ed-on-bls12-377", - "ark-ff", - "ark-r1cs-std", - "ark-relations", - "ark-serialize", - "async-trait", - "blake2b_simd 1.0.2", - "decaf377 0.5.0", - "derivative", - "futures", - "hash_hasher", - "hex", - "im", - "once_cell", - "parking_lot", - "penumbra-proto", - "poseidon377", - "rand", - "serde", - "thiserror", - "tracing", -] - -[[package]] -name = "penumbra-transaction" -version = "0.77.0" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.77.0#00a859b99697fe7e5a7459d86210c2760cd27682" -dependencies = [ - "anyhow", - "ark-ff", - "ark-serialize", - "base64 0.21.7", - "bech32", - "blake2b_simd 1.0.2", - "bytes", - "chacha20poly1305", - "decaf377 0.5.0", - "decaf377-fmd", - "decaf377-ka", - "decaf377-rdsa", - "derivative", - "hex", - "ibc-proto", - "ibc-types", - "num-bigint", - "once_cell", - "pbjson-types", - "penumbra-asset", - "penumbra-auction", - "penumbra-community-pool", - "penumbra-dex", - "penumbra-fee", - "penumbra-governance", - "penumbra-ibc", - "penumbra-keys", - "penumbra-num", - "penumbra-proof-params", - "penumbra-proto", - "penumbra-sct", - "penumbra-shielded-pool", - "penumbra-stake", - "penumbra-tct", - "penumbra-txhash", - "poseidon377", - "rand", - "rand_core", - "regex", - "serde", - "serde_json", - "sha2 0.10.8", - "thiserror", - "tracing", -] - -[[package]] -name = "penumbra-txhash" -version = "0.77.0" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.77.0#00a859b99697fe7e5a7459d86210c2760cd27682" -dependencies = [ - "anyhow", - "blake2b_simd 1.0.2", - "hex", - "penumbra-proto", - "penumbra-tct", - "serde", -] - -[[package]] -name = "penumbra-wasm" -version = "2.0.0" -dependencies = [ - "anyhow", - "ark-ff", - "base64 0.22.1", - "console_error_panic_hook", - "decaf377 0.5.0", - "hex", - "indexed_db_futures", - "penumbra-asset", - "penumbra-auction", - "penumbra-compact-block", - "penumbra-dex", - "penumbra-fee", - "penumbra-keys", - "penumbra-num", - "penumbra-proof-params", - "penumbra-proto", - "penumbra-sct", - "penumbra-shielded-pool", - "penumbra-stake", - "penumbra-tct", - "penumbra-transaction", - "prost", - "rand_core", - "regex", - "serde", - "serde-wasm-bindgen", - "serde_json", - "thiserror", - "wasm-bindgen", - "wasm-bindgen-futures", - "wasm-bindgen-test", - "web-sys", -] - -[[package]] -name = "petgraph" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" -dependencies = [ - "fixedbitset", - "indexmap 2.2.5", -] - -[[package]] -name = "pin-project" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0302c4a0442c456bd56f841aee5c3bfd17967563f6fadc9ceb9f9c23cf3807e0" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266c042b60c9c76b8d53061e52b2e0d1116abc57cefc8c5cd671619a56ac3690" -dependencies = [ - "proc-macro2 1.0.79", - "quote", - "syn 2.0.58", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pkcs8" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" -dependencies = [ - "der", - "spki", -] - -[[package]] -name = "poly1305" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "048aeb476be11a4b6ca432ca569e375810de9294ae78f4774e78ea98a9246ede" -dependencies = [ - "cpufeatures", - "opaque-debug", - "universal-hash", -] - -[[package]] -name = "portable-atomic" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" - -[[package]] -name = "poseidon-parameters" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58236ff8bf455c13046c92f041e887c4fd0e64819387a81177d6c70ebeb41711" -dependencies = [ - "anyhow", - "ark-ff", - "num-integer", -] - -[[package]] -name = "poseidon-paramgen" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a69506f91189a68bff6c0e4f8c2beaf6b053430be7743059a0110477e9c28fda" -dependencies = [ - "anyhow", - "ark-ff", - "ark-std", - "getrandom", - "merlin", - "num", - "num-bigint", - "poseidon-parameters", - "rand_core", -] - -[[package]] -name = "poseidon-permutation" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a022268b53cec1e99c4bd8c81be249709e971b78a433d9f5556e31f3cd7730b0" -dependencies = [ - "ark-ff", - "ark-r1cs-std", - "ark-relations", - "ark-std", - "poseidon-parameters", -] - -[[package]] -name = "poseidon377" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11dbcae1c9e4624576dd7631a1f2419a18afeaeef104263d70b6f20256ea5b72" -dependencies = [ - "ark-ec", - "ark-ed-on-bls12-377", - "ark-ff", - "ark-groth16", - "ark-r1cs-std", - "ark-relations", - "ark-serialize", - "ark-snark", - "ark-std", - "decaf377 0.4.0", - "num-bigint", - "once_cell", - "poseidon-parameters", - "poseidon-paramgen", - "poseidon-permutation", - "tracing", -] - -[[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "prettyplease" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a41cf62165e97c7f814d2221421dbb9afcbcdb0a88068e5ea206e19951c2cbb5" -dependencies = [ - "proc-macro2 1.0.79", - "syn 2.0.58", -] - -[[package]] -name = "primitive-types" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" -dependencies = [ - "fixed-hash", - "impl-codec", - "impl-serde", - "uint", -] - -[[package]] -name = "proc-macro-crate" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b00f26d3400549137f92511a46ac1cd8ce37cb5598a96d382381458b992a5d24" -dependencies = [ - "toml_datetime", - "toml_edit", -] - -[[package]] -name = "proc-macro2" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "557facecbf90ff79faea80a08230d10c812016aa19198ed07d06de61f965b5cc" -dependencies = [ - "unicode-xid", -] - -[[package]] -name = "proc-macro2" -version = "1.0.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "prost" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29" -dependencies = [ - "bytes", - "prost-derive", -] - -[[package]] -name = "prost-build" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c55e02e35260070b6f716a2423c2ff1c3bb1642ddca6f99e1f26d06268a0e2d2" -dependencies = [ - "bytes", - "heck", - "itertools 0.10.5", - "log", - "multimap", - "once_cell", - "petgraph", - "prettyplease", - "prost", - "prost-types", - "regex", - "syn 2.0.58", - "tempfile", - "which", -] - -[[package]] -name = "prost-derive" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" -dependencies = [ - "anyhow", - "itertools 0.10.5", - "proc-macro2 1.0.79", - "quote", - "syn 2.0.58", -] - -[[package]] -name = "prost-types" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "193898f59edcf43c26227dcd4c8427f00d99d61e95dcde58dabd49fa291d470e" -dependencies = [ - "prost", -] - -[[package]] -name = "quote" -version = "1.0.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" -dependencies = [ - "proc-macro2 1.0.79", -] - -[[package]] -name = "radium" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "rand_xoshiro" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" -dependencies = [ - "rand_core", -] - -[[package]] -name = "redox_syscall" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "regex" -version = "1.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata 0.4.6", - "regex-syntax 0.8.3", -] - -[[package]] -name = "regex-automata" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" -dependencies = [ - "regex-syntax 0.6.29", -] - -[[package]] -name = "regex-automata" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax 0.8.3", -] - -[[package]] -name = "regex-syntax" -version = "0.6.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" - -[[package]] -name = "regex-syntax" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" - -[[package]] -name = "rfc6979" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" -dependencies = [ - "hmac", - "subtle", -] - -[[package]] -name = "ripemd" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" -dependencies = [ - "digest 0.10.7", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" - -[[package]] -name = "rustc-hex" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" - -[[package]] -name = "rustc_version" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" -dependencies = [ - "semver", -] - -[[package]] -name = "rustix" -version = "0.38.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" -dependencies = [ - "bitflags 2.4.2", - "errno", - "libc", - "linux-raw-sys", - "windows-sys", -] - -[[package]] -name = "ryu" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" - -[[package]] -name = "safe-proc-macro2" -version = "1.0.67" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fd85be67db87168aa3c13fd0da99f48f2ab005dccad5af5626138dc1df20eb6" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "safe-quote" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77e530f7831f3feafcd5f1aae406ac205dd998436b4007c8e80f03eca78a88f7" -dependencies = [ - "safe-proc-macro2", -] - -[[package]] -name = "safe-regex" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a15289bf322e0673d52756a18194167f2378ec1a15fe884af6e2d2cb934822b0" -dependencies = [ - "safe-regex-macro", -] - -[[package]] -name = "safe-regex-compiler" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fba76fae590a2aa665279deb1f57b5098cbace01a0c5e60e262fcf55f7c51542" -dependencies = [ - "safe-proc-macro2", - "safe-quote", -] - -[[package]] -name = "safe-regex-macro" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96c2e96b5c03f158d1b16ba79af515137795f4ad4e8de3f790518aae91f1d127" -dependencies = [ - "safe-proc-macro2", - "safe-regex-compiler", -] - -[[package]] -name = "scoped-tls" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "sec1" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" -dependencies = [ - "base16ct", - "der", - "generic-array", - "subtle", - "zeroize", -] - -[[package]] -name = "semver" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" - -[[package]] -name = "serde" -version = "1.0.202" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde-wasm-bindgen" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b" -dependencies = [ - "js-sys", - "serde", - "wasm-bindgen", -] - -[[package]] -name = "serde_bytes" -version = "0.11.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b8497c313fd43ab992087548117643f6fcd935cbf36f176ffda0aacf9591734" -dependencies = [ - "serde", -] - -[[package]] -name = "serde_derive" -version = "1.0.202" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838" -dependencies = [ - "proc-macro2 1.0.79", - "quote", - "syn 2.0.58", -] - -[[package]] -name = "serde_json" -version = "1.0.117" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "serde_repr" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b2e6b945e9d3df726b65d6ee24060aff8e3533d431f677a9695db04eff9dfdb" -dependencies = [ - "proc-macro2 1.0.79", - "quote", - "syn 2.0.58", -] - -[[package]] -name = "serde_unit_struct" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cee87479059950a55ed6089d755a105b8cdf16fbc51ea45a524ecff8da259987" -dependencies = [ - "serde_unit_struct_derive", -] - -[[package]] -name = "serde_unit_struct_derive" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f1b15838534b38fb67ffe60033fe3ffad48f916c175e8baa0400e0cdb958dec" -dependencies = [ - "quote", - "syn 2.0.58", -] - -[[package]] -name = "serde_with" -version = "3.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15d167997bd841ec232f5b2b8e0e26606df2e7caa4c31b95ea9ca52b200bd270" -dependencies = [ - "base64 0.21.7", - "chrono", - "hex", - "indexmap 1.9.3", - "indexmap 2.2.5", - "serde", - "serde_derive", - "serde_json", - "serde_with_macros", - "time", -] - -[[package]] -name = "serde_with_macros" -version = "3.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "865f9743393e638991566a8b7a479043c2c8da94a33e0a31f18214c9cae0a64d" -dependencies = [ - "darling", - "proc-macro2 1.0.79", - "quote", - "syn 2.0.58", -] - -[[package]] -name = "sha2" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" -dependencies = [ - "block-buffer 0.9.0", - "cfg-if", - "cpufeatures", - "digest 0.9.0", - "opaque-debug", -] - -[[package]] -name = "sha2" -version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest 0.10.7", -] - -[[package]] -name = "sha3" -version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" -dependencies = [ - "digest 0.10.7", - "keccak", -] - -[[package]] -name = "sharded-slab" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "signature" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" -dependencies = [ - "digest 0.10.7", - "rand_core", -] - -[[package]] -name = "sized-chunks" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16d69225bde7a69b235da73377861095455d298f2b970996eec25ddbb42b3d1e" -dependencies = [ - "bitmaps", - "typenum", -] - -[[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - -[[package]] -name = "smallvec" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" - -[[package]] -name = "spki" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" -dependencies = [ - "base64ct", - "der", -] - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - -[[package]] -name = "subtle" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" - -[[package]] -name = "subtle-encoding" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dcb1ed7b8330c5eed5441052651dd7a12c75e2ed88f2ec024ae1fa3a5e59945" -dependencies = [ - "zeroize", -] - -[[package]] -name = "subtle-ng" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "734676eb262c623cec13c3155096e08d1f8f29adce39ba17948b18dad1e54142" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2 1.0.79", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.58" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687" -dependencies = [ - "proc-macro2 1.0.79", - "quote", - "unicode-ident", -] - -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - -[[package]] -name = "tempfile" -version = "3.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" -dependencies = [ - "cfg-if", - "fastrand", - "rustix", - "windows-sys", -] - -[[package]] -name = "tendermint" -version = "0.34.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15ab8f0a25d0d2ad49ac615da054d6a76aa6603ff95f7d18bafdd34450a1a04b" -dependencies = [ - "bytes", - "digest 0.10.7", - "ed25519", - "ed25519-consensus", - "flex-error", - "futures", - "num-traits", - "once_cell", - "prost", - "prost-types", - "serde", - "serde_bytes", - "serde_json", - "serde_repr", - "sha2 0.10.8", - "signature", - "subtle", - "subtle-encoding", - "tendermint-proto", - "time", - "zeroize", -] - -[[package]] -name = "tendermint-light-client-verifier" -version = "0.34.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b8090d0eef9ad57b1b913b5e358e26145c86017e87338136509b94383a4af25" -dependencies = [ - "derive_more", - "flex-error", - "serde", - "tendermint", - "time", -] - -[[package]] -name = "tendermint-proto" -version = "0.34.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b797dd3d2beaaee91d2f065e7bdf239dc8d80bba4a183a288bc1279dd5a69a1e" -dependencies = [ - "bytes", - "flex-error", - "num-derive", - "num-traits", - "prost", - "prost-types", - "serde", - "serde_bytes", - "subtle-encoding", - "time", -] - -[[package]] -name = "thiserror" -version = "1.0.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" -dependencies = [ - "proc-macro2 1.0.79", - "quote", - "syn 2.0.58", -] - -[[package]] -name = "thread_local" -version = "1.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" -dependencies = [ - "cfg-if", - "once_cell", -] - -[[package]] -name = "time" -version = "0.3.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" -dependencies = [ - "deranged", - "itoa", - "num-conv", - "powerfmt", - "serde", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" - -[[package]] -name = "time-macros" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ba3a3ef41e6672a2f0f001392bb5dcd3ff0a9992d618ca761a11c3121547774" -dependencies = [ - "num-conv", - "time-core", -] - -[[package]] -name = "tokio" -version = "1.37.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" -dependencies = [ - "backtrace", - "pin-project-lite", -] - -[[package]] -name = "tokio-stream" -version = "0.1.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "toml_datetime" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" - -[[package]] -name = "toml_edit" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" -dependencies = [ - "indexmap 2.2.5", - "toml_datetime", - "winnow", -] - -[[package]] -name = "tower" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" -dependencies = [ - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tower-layer" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" - -[[package]] -name = "tower-service" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" - -[[package]] -name = "tracing" -version = "0.1.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" -dependencies = [ - "log", - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" -dependencies = [ - "proc-macro2 1.0.79", - "quote", - "syn 2.0.58", -] - -[[package]] -name = "tracing-core" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" -dependencies = [ - "once_cell", - "valuable", -] - -[[package]] -name = "tracing-log" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f751112709b4e791d8ce53e32c4ed2d353565a795ce84da2285393f41557bdf2" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - -[[package]] -name = "tracing-serde" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc6b213177105856957181934e4920de57730fc69bf42c37ee5bb664d406d9e1" -dependencies = [ - "serde", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.2.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" -dependencies = [ - "ansi_term", - "chrono", - "lazy_static", - "matchers", - "regex", - "serde", - "serde_json", - "sharded-slab", - "smallvec", - "thread_local", - "tracing", - "tracing-core", - "tracing-log", - "tracing-serde", -] - -[[package]] -name = "typenum" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" - -[[package]] -name = "uint" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" -dependencies = [ - "byteorder", - "crunchy", - "hex", - "static_assertions", -] - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "unicode-xid" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" - -[[package]] -name = "universal-hash" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" -dependencies = [ - "generic-array", - "subtle", -] - -[[package]] -name = "uuid" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560" -dependencies = [ - "getrandom", - "wasm-bindgen", -] - -[[package]] -name = "valuable" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasm-bindgen" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2 1.0.79", - "quote", - "syn 2.0.58", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" -dependencies = [ - "proc-macro2 1.0.79", - "quote", - "syn 2.0.58", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" - -[[package]] -name = "wasm-bindgen-test" -version = "0.3.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9bf62a58e0780af3e852044583deee40983e5886da43a271dd772379987667b" -dependencies = [ - "console_error_panic_hook", - "js-sys", - "scoped-tls", - "wasm-bindgen", - "wasm-bindgen-futures", - "wasm-bindgen-test-macro", -] - -[[package]] -name = "wasm-bindgen-test-macro" -version = "0.3.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7f89739351a2e03cb94beb799d47fb2cac01759b40ec441f7de39b00cbf7ef0" -dependencies = [ - "proc-macro2 1.0.79", - "quote", - "syn 2.0.58", -] - -[[package]] -name = "web-sys" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "which" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" -dependencies = [ - "either", - "home", - "once_cell", - "rustix", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-core" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" -dependencies = [ - "windows-targets 0.52.4", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.4", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - -[[package]] -name = "windows-targets" -version = "0.52.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" -dependencies = [ - "windows_aarch64_gnullvm 0.52.4", - "windows_aarch64_msvc 0.52.4", - "windows_i686_gnu 0.52.4", - "windows_i686_msvc 0.52.4", - "windows_x86_64_gnu 0.52.4", - "windows_x86_64_gnullvm 0.52.4", - "windows_x86_64_msvc 0.52.4", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" - -[[package]] -name = "winnow" -version = "0.5.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" -dependencies = [ - "memchr", -] - -[[package]] -name = "wyz" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" -dependencies = [ - "tap", -] - -[[package]] -name = "zerocopy" -version = "0.7.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" -dependencies = [ - "proc-macro2 1.0.79", - "quote", - "syn 2.0.58", -] - -[[package]] -name = "zeroize" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" -dependencies = [ - "zeroize_derive", -] - -[[package]] -name = "zeroize_derive" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" -dependencies = [ - "proc-macro2 1.0.79", - "quote", - "syn 2.0.58", -] diff --git a/packages/wasm/crate/Cargo.toml b/packages/wasm/crate/Cargo.toml deleted file mode 100644 index 8d1a5b08..00000000 --- a/packages/wasm/crate/Cargo.toml +++ /dev/null @@ -1,53 +0,0 @@ -[package] -name = "penumbra-wasm" -version = "2.0.0" -edition = "2021" - -[profile.release] -opt-level = "s" - -[lib] -crate-type = ["cdylib", "rlib"] - -[features] -default = ["console_error_panic_hook"] -mock-database = [] - -[dependencies] -# TODO: Use `tag` instead of `rev` once auctions land in a tagged release of -# core. -penumbra-auction = { git = "https://github.com/penumbra-zone/penumbra.git", tag = "v0.77.0", package = "penumbra-auction", default-features = false } -penumbra-asset = { git = "https://github.com/penumbra-zone/penumbra.git", tag = "v0.77.0", package = "penumbra-asset" } -penumbra-compact-block = { git = "https://github.com/penumbra-zone/penumbra.git", tag = "v0.77.0", package = "penumbra-compact-block", default-features = false } -penumbra-dex = { git = "https://github.com/penumbra-zone/penumbra.git", tag = "v0.77.0", package = "penumbra-dex", default-features = false } -penumbra-fee = { git = "https://github.com/penumbra-zone/penumbra.git", tag = "v0.77.0", package = "penumbra-fee", default-features = false } -penumbra-keys = { git = "https://github.com/penumbra-zone/penumbra.git", tag = "v0.77.0", package = "penumbra-keys" } -penumbra-num = { git = "https://github.com/penumbra-zone/penumbra.git", tag = "v0.77.0", package = "penumbra-num" } -penumbra-proof-params = { git = "https://github.com/penumbra-zone/penumbra.git", tag = "v0.77.0", package = "penumbra-proof-params", default-features = false } -penumbra-proto = { git = "https://github.com/penumbra-zone/penumbra.git", tag = "v0.77.0", package = "penumbra-proto", default-features = false } -penumbra-sct = { git = "https://github.com/penumbra-zone/penumbra.git", tag = "v0.77.0", package = "penumbra-sct", default-features = false } -penumbra-shielded-pool = { git = "https://github.com/penumbra-zone/penumbra.git", tag = "v0.77.0", package = "penumbra-shielded-pool", default-features = false } -penumbra-stake = { git = "https://github.com/penumbra-zone/penumbra.git", tag = "v0.77.0", package = "penumbra-stake", default-features = false } -penumbra-tct = { git = "https://github.com/penumbra-zone/penumbra.git", tag = "v0.77.0", package = "penumbra-tct" } -penumbra-transaction = { git = "https://github.com/penumbra-zone/penumbra.git", tag = "v0.77.0", package = "penumbra-transaction", default-features = false } - -anyhow = "1.0.86" -ark-ff = { version = "0.4.2", features = ["std"] } -base64 = "0.22.1" -console_error_panic_hook = { version = "0.1.7", optional = true } -decaf377 = { version = "0.5.0", features = ["r1cs"] } -hex = "0.4.3" -indexed_db_futures = "0.4.1" -prost = "0.12.6" -rand_core = { version = "0.6.4", features = ["getrandom"] } -regex = { version = "1.10.4" } -serde = { version = "1.0.202", features = ["derive"] } -serde-wasm-bindgen = "0.6.5" -thiserror = "1.0" -wasm-bindgen = "0.2.92" -wasm-bindgen-futures = "0.4.42" -web-sys = { version = "0.3.69", features = ["console"] } - -[dev-dependencies] -wasm-bindgen-test = "0.3.42" -serde_json = "1.0.117" diff --git a/packages/wasm/crate/src/asset.rs b/packages/wasm/crate/src/asset.rs deleted file mode 100644 index 65543778..00000000 --- a/packages/wasm/crate/src/asset.rs +++ /dev/null @@ -1,19 +0,0 @@ -use crate::error::WasmResult; -use penumbra_asset::asset::Id; -use penumbra_proto::DomainType; -use wasm_bindgen::prelude::*; - -/// generate the appropriate binary inner id for a binary-serialized protobuf -/// `AssetId` potentially containing an `altBaseDenom` or `altBech32m` string -/// field -/// -/// Arguments: -/// input_id_bin: `Uint8Array` representing a binary-serialized `AssetId` -/// -/// Returns: -/// `Uint8Array` representing the literal inner id -#[wasm_bindgen] -pub fn get_asset_id_inner(input_id_bin: &[u8]) -> WasmResult> { - let input_id = Id::decode(input_id_bin)?; - Ok(input_id.to_bytes().to_vec()) -} diff --git a/packages/wasm/crate/src/auction.rs b/packages/wasm/crate/src/auction.rs deleted file mode 100644 index 5b04ab15..00000000 --- a/packages/wasm/crate/src/auction.rs +++ /dev/null @@ -1,70 +0,0 @@ -use crate::{error::WasmResult, metadata::customize_symbol_inner, utils}; -use penumbra_asset::asset::Metadata; -use penumbra_auction::auction::{dutch::DutchAuctionDescription, AuctionId, AuctionNft}; -use penumbra_proto::DomainType; -use wasm_bindgen::prelude::wasm_bindgen; - -/// Given a `Uint8Array` encoding of a `DutchAuctionDescription`, returns that -/// auction's ID. -#[wasm_bindgen] -pub fn get_auction_id(description: &[u8]) -> WasmResult> { - utils::set_panic_hook(); - let description = DutchAuctionDescription::decode(description)?; - Ok(description.id().encode_to_vec()) -} - -/// Given a `Uint8Array` encoding of an `AuctionId` (along with a sequence -/// number), returns the metadata for the auction NFT describing that auction -/// and its current sequence number. -#[wasm_bindgen] -pub fn get_auction_nft_metadata(auction_id: &[u8], seq: u64) -> WasmResult> { - utils::set_panic_hook(); - let auction_id = AuctionId::decode(auction_id)?; - let nft = AuctionNft::new(auction_id, seq); - let metadata_proto = customize_symbol_inner(nft.metadata.to_proto())?; - let metadata_domain_type = Metadata::try_from(metadata_proto)?; - - Ok(metadata_domain_type.encode_to_vec()) -} - -#[cfg(test)] -mod tests { - use ark_ff::Zero; - use decaf377::Fq; - use penumbra_asset::{ - asset::{Id, Metadata}, - Value, - }; - use penumbra_auction::auction::dutch::DutchAuctionDescription; - use penumbra_num::Amount; - use penumbra_proto::DomainType; - - use crate::auction::get_auction_id; - - use super::get_auction_nft_metadata; - - #[test] - fn it_gets_correct_id_and_metadata() { - let description = DutchAuctionDescription { - start_height: 0, - end_height: 100, - input: Value { - amount: Amount::default(), - asset_id: Id(Fq::zero()), - }, - min_output: Amount::default(), - max_output: Amount::default(), - nonce: [0; 32], - output_id: Id(Fq::zero()), - step_count: 100u64, - }; - - let auction_id_bytes = get_auction_id(&description.encode_to_vec()).unwrap(); - let result_bytes = get_auction_nft_metadata(&auction_id_bytes, 1234).unwrap(); - let result = Metadata::decode::<&[u8]>(&result_bytes).unwrap(); - let result_proto = result.to_proto(); - - assert!(result_proto.symbol.starts_with("auction(")); - assert!(result_proto.display.starts_with("auctionnft_1234_pauctid1")); - } -} diff --git a/packages/wasm/crate/src/build.rs b/packages/wasm/crate/src/build.rs deleted file mode 100644 index 39e4aa23..00000000 --- a/packages/wasm/crate/src/build.rs +++ /dev/null @@ -1,37 +0,0 @@ -use penumbra_keys::FullViewingKey; -use penumbra_proto::DomainType; -use penumbra_transaction::{ - plan::{ActionPlan, TransactionPlan}, - WitnessData, -}; -use wasm_bindgen::prelude::wasm_bindgen; - -use crate::error::WasmResult; -use crate::utils; - -/// Builds a planned [`Action`] specified by -/// the [`ActionPlan`] in a [`TransactionPlan`]. -/// Arguments: -/// transaction_plan: `TransactionPlan` -/// action_plan: `ActionPlan` -/// full_viewing_key: `byte representation inner FullViewingKey` -/// witness_data: `WitnessData`` -/// Returns: `Action` -#[wasm_bindgen] -pub fn build_action( - transaction_plan: &[u8], - action_plan: &[u8], - full_viewing_key: &[u8], - witness_data: &[u8], -) -> WasmResult> { - utils::set_panic_hook(); - let transaction_plan = TransactionPlan::decode(transaction_plan)?; - let witness = WitnessData::decode(witness_data)?; - let action_plan = ActionPlan::decode(action_plan)?; - let full_viewing_key: FullViewingKey = FullViewingKey::decode(full_viewing_key)?; - - let memo_key = transaction_plan.memo.map(|memo_plan| memo_plan.key); - - let action = ActionPlan::build_unauth(action_plan, &full_viewing_key, &witness, memo_key)?; - Ok(action.encode_to_vec()) -} diff --git a/packages/wasm/crate/src/dex.rs b/packages/wasm/crate/src/dex.rs deleted file mode 100644 index 2ab63fae..00000000 --- a/packages/wasm/crate/src/dex.rs +++ /dev/null @@ -1,34 +0,0 @@ -use penumbra_dex::lp::position::{Id, Position, State}; -use penumbra_dex::lp::LpNft; -use penumbra_proto::DomainType; -use wasm_bindgen::prelude::wasm_bindgen; - -use crate::error::WasmResult; -use crate::utils; - -/// compute position id -/// Arguments: -/// position: `Uint8Array representing a Position` -/// Returns: ` Uint8Array representing a PositionId` -#[wasm_bindgen] -pub fn compute_position_id(position: &[u8]) -> WasmResult> { - utils::set_panic_hook(); - - let position = Position::decode(position)?; - Ok(position.id().encode_to_vec()) -} - -/// get LP NFT asset -/// Arguments: -/// position_value: `lp::position::Position` -/// position_state: `lp::position::State` -/// Returns: `Uint8Array` representing a `Metadata` -#[wasm_bindgen] -pub fn get_lpnft_asset(position_id: &[u8], position_state: &[u8]) -> WasmResult> { - utils::set_panic_hook(); - let position_id = Id::decode(position_id)?; - let position_state = State::decode(position_state)?; - let lp_nft = LpNft::new(position_id, position_state); - let denom = lp_nft.denom(); - Ok(denom.encode_to_vec()) -} diff --git a/packages/wasm/crate/src/error.rs b/packages/wasm/crate/src/error.rs deleted file mode 100644 index b8bd665e..00000000 --- a/packages/wasm/crate/src/error.rs +++ /dev/null @@ -1,81 +0,0 @@ -use std::convert::Infallible; -use std::num::TryFromIntError; - -use base64::DecodeError as Base64DecodeError; -use hex::FromHexError; -use penumbra_tct::error::{InsertBlockError, InsertEpochError, InsertError}; -use prost::DecodeError as ProstDecodeError; -use serde_wasm_bindgen::Error; -use thiserror::Error; -use wasm_bindgen::{JsError, JsValue}; -use web_sys::DomException; - -pub type WasmResult = Result; - -#[derive(Error, Debug)] -pub enum WasmError { - #[error("{0}")] - Anyhow(#[from] anyhow::Error), - - #[error("{0}")] - Base64DecodeError(#[from] Base64DecodeError), - - #[error("{0}")] - Dom(#[from] DomError), - - #[error("{0}")] - FromHexError(#[from] FromHexError), - - #[error("{0}")] - Infallible(#[from] Infallible), - - #[error("{0}")] - InsertBlockError(#[from] InsertBlockError), - - #[error("{0}")] - InsertEpochError(#[from] InsertEpochError), - - #[error("{0}")] - InsertError(#[from] InsertError), - - #[error("Decode error: {0}")] - ProstDecodeError(#[from] ProstDecodeError), - - #[error("{0}")] - RegexError(#[from] regex::Error), - - #[error("{0}")] - TryInt(#[from] TryFromIntError), - - #[error("{0}")] - Wasm(#[from] serde_wasm_bindgen::Error), -} - -impl From for serde_wasm_bindgen::Error { - fn from(wasm_err: WasmError) -> Self { - Error::new(wasm_err.to_string()) - } -} - -impl From for JsValue { - fn from(error: WasmError) -> Self { - JsError::from(error).into() - } -} - -#[derive(Debug)] -pub struct DomError(DomException); - -impl std::fmt::Display for DomError { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "DOM Exception: {:?}", self.0) - } -} - -impl std::error::Error for DomError {} - -impl From for WasmError { - fn from(dom_exception: DomException) -> Self { - WasmError::Dom(DomError(dom_exception)) - } -} diff --git a/packages/wasm/crate/src/keys.rs b/packages/wasm/crate/src/keys.rs deleted file mode 100644 index 739919d2..00000000 --- a/packages/wasm/crate/src/keys.rs +++ /dev/null @@ -1,127 +0,0 @@ -use std::str::FromStr; - -use anyhow; -use penumbra_keys::keys::{Bip44Path, SeedPhrase, SpendKey}; -use penumbra_keys::{Address, FullViewingKey}; -use penumbra_proof_params::{ - CONVERT_PROOF_PROVING_KEY, DELEGATOR_VOTE_PROOF_PROVING_KEY, OUTPUT_PROOF_PROVING_KEY, - SPEND_PROOF_PROVING_KEY, SWAPCLAIM_PROOF_PROVING_KEY, SWAP_PROOF_PROVING_KEY, -}; -use penumbra_proto::core::keys::v1 as pb; -use penumbra_proto::core::keys::v1::WalletId; -use penumbra_proto::{DomainType, Message}; -use rand_core::OsRng; -use wasm_bindgen::prelude::*; - -use crate::error::WasmResult; -use crate::utils; - -/// Loads the proving key as a collection of bytes, and to sets the keys in memory -/// dynamicaly at runtime. Failure to bundle the proving keys in the wasm binary -/// or call the load function will fail to generate a proof. Consumers of this -/// function will additionally require downloading the proving key parameter `.bin` -/// file for each key type. -#[wasm_bindgen] -pub fn load_proving_key(key: &[u8], key_type: &str) -> WasmResult<()> { - // Map key type with proving keys. - let proving_key_map = match key_type { - "spend" => &SPEND_PROOF_PROVING_KEY, - "output" => &OUTPUT_PROOF_PROVING_KEY, - "delegatorVote" => &DELEGATOR_VOTE_PROOF_PROVING_KEY, - "swap" => &SWAP_PROOF_PROVING_KEY, - "swapClaim" => &SWAPCLAIM_PROOF_PROVING_KEY, - "undelegateClaim" => &CONVERT_PROOF_PROVING_KEY, - _ => return Err(anyhow::anyhow!("Unsupported key type").into()), - }; - - // Load proving key. - proving_key_map.try_load_unchecked(key)?; - Ok(()) -} - -/// generate a spend key from a seed phrase -/// Arguments: -/// seed_phrase: `string` -/// Returns: `Uint8Array representing inner SpendKey` -#[wasm_bindgen] -pub fn generate_spend_key(seed_phrase: &str) -> WasmResult> { - utils::set_panic_hook(); - - let seed = SeedPhrase::from_str(seed_phrase)?; - let path = Bip44Path::new(0); - let spend_key = SpendKey::from_seed_phrase_bip44(seed, &path); - Ok(spend_key.encode_to_vec()) -} - -/// get full viewing key from spend key -/// Arguments: -/// spend_key: `byte representation inner SpendKey` -/// Returns: `Uint8Array representing inner FullViewingKey` -#[wasm_bindgen] -pub fn get_full_viewing_key(spend_key: &[u8]) -> WasmResult> { - utils::set_panic_hook(); - - let spend_key: SpendKey = SpendKey::decode(spend_key)?; - let fvk: &FullViewingKey = spend_key.full_viewing_key(); - Ok(fvk.encode_to_vec()) -} - -/// Wallet id: the hash of a full viewing key, used as an account identifier -/// Arguments: -/// full_viewing_key: `byte representation inner FullViewingKey` -/// Returns: `WalletId` -#[wasm_bindgen] -pub fn get_wallet_id(full_viewing_key: &[u8]) -> WasmResult> { - utils::set_panic_hook(); - - let fvk: FullViewingKey = FullViewingKey::decode(full_viewing_key)?; - // Can do `fvk.wallet_id().encode_to_vec()` when Domain impl added to WalletId in core - let wallet_id_proto = WalletId::from(fvk.wallet_id()); - Ok(wallet_id_proto.encode_to_vec()) -} - -/// get address by index using FVK -/// Arguments: -/// full_viewing_key: `byte representation inner FullViewingKey` -/// index: `u32` -/// Returns: `Uint8Array representing inner Address` -#[wasm_bindgen] -pub fn get_address_by_index(full_viewing_key: &[u8], index: u32) -> WasmResult> { - utils::set_panic_hook(); - - let fvk: FullViewingKey = FullViewingKey::decode(full_viewing_key)?; - let (address, _dtk) = fvk.incoming().payment_address(index.into()); - Ok(address.encode_to_vec()) -} - -/// get ephemeral (randomizer) address using FVK -/// The derivation tree is like "spend key / address index / ephemeral address" so we must also pass index as an argument -/// Arguments: -/// full_viewing_key: `byte representation inner FullViewingKey` -/// index: `u32` -/// Returns: `Uint8Array representing inner Address` -#[wasm_bindgen] -pub fn get_ephemeral_address(full_viewing_key: &[u8], index: u32) -> WasmResult> { - utils::set_panic_hook(); - - let fvk: FullViewingKey = FullViewingKey::decode(full_viewing_key)?; - let (address, _dtk) = fvk.ephemeral_address(OsRng, index.into()); - Ok(address.encode_to_vec()) -} - -/// Returns the AddressIndex of an address. -/// If it is not controlled by the FVK, it returns a `None` -/// Arguments: -/// full_viewing_key: `byte representation inner FullViewingKey` -/// address: `byte representation inner Address` -/// Returns: `Option` -#[wasm_bindgen] -pub fn get_index_by_address(full_viewing_key: &[u8], address: &[u8]) -> WasmResult { - utils::set_panic_hook(); - - let address: Address = Address::decode(address)?; - let fvk: FullViewingKey = FullViewingKey::decode(full_viewing_key)?; - let index: Option = fvk.address_index(&address).map(Into::into); - let result = serde_wasm_bindgen::to_value(&index)?; - Ok(result) -} diff --git a/packages/wasm/crate/src/lib.rs b/packages/wasm/crate/src/lib.rs deleted file mode 100644 index 5bdbe91f..00000000 --- a/packages/wasm/crate/src/lib.rs +++ /dev/null @@ -1,21 +0,0 @@ -#![allow(dead_code)] -// Requires nightly. -#![cfg_attr(docsrs, feature(doc_auto_cfg))] - -extern crate core; - -pub mod asset; -pub mod auction; -pub mod build; -pub mod dex; -pub mod error; -pub mod keys; -pub mod metadata; -pub mod note_record; -pub mod planner; -pub mod storage; -pub mod swap_record; -pub mod tree; -pub mod tx; -pub mod utils; -pub mod view_server; diff --git a/packages/wasm/crate/src/metadata.rs b/packages/wasm/crate/src/metadata.rs deleted file mode 100644 index 5055fc25..00000000 --- a/packages/wasm/crate/src/metadata.rs +++ /dev/null @@ -1,244 +0,0 @@ -use anyhow::anyhow; -use penumbra_asset::asset::Metadata as MetadataDomainType; -use penumbra_proto::{core::asset::v1::Metadata, DomainType}; -use regex::Regex; -use wasm_bindgen::prelude::wasm_bindgen; - -use crate::{error::WasmResult, utils}; - -pub static UNBONDING_TOKEN_REGEX: &str = "^uunbonding_(?Pstart_at_(?P[0-9]+)_(?Ppenumbravalid1(?P[a-zA-HJ-NP-Z0-9]+)))$"; -pub static DELEGATION_TOKEN_REGEX: &str = - "^udelegation_(?Ppenumbravalid1(?P[a-zA-HJ-NP-Z0-9]+))$"; -pub static AUCTION_NFT_REGEX: &str = - "^auctionnft_(?P(?[a-z_0-9]+)_pauctid1(?P[a-zA-HJ-NP-Z0-9]+))$"; -pub static SHORTENED_ID_LENGTH: usize = 8; - -/// Given a binary-encoded `Metadata`, returns a new binary-encoded `Metadata` -/// with the symbol customized if the token is one of several specific types -/// that don't have built-in symbols. -#[wasm_bindgen] -pub fn customize_symbol(metadata_bytes: &[u8]) -> WasmResult> { - utils::set_panic_hook(); - - let metadata_domain_type = MetadataDomainType::decode(metadata_bytes)?; - let metadata_proto = customize_symbol_inner(metadata_domain_type.to_proto())?; - - match MetadataDomainType::try_from(metadata_proto) { - Ok(customized_metadata_domain_type) => Ok(customized_metadata_domain_type.encode_to_vec()), - Err(error) => Err(error.into()), - } -} - -/// Given a `Metadata`, returns a new `Metadata` with the symbol customized if -/// the token is one of several specific types that don't have built-in symbols. -pub fn customize_symbol_inner(metadata: Metadata) -> WasmResult { - let unbonding_re = Regex::new(UNBONDING_TOKEN_REGEX)?; - let delegation_re = Regex::new(DELEGATION_TOKEN_REGEX)?; - let auction_re = Regex::new(AUCTION_NFT_REGEX)?; - - if let Some(captures) = unbonding_re.captures(&metadata.base) { - let shortened_id = shorten_id(&captures)?; - let start_match = captures - .name("start") - .ok_or_else(|| anyhow!(" not matched in unbonding token regex"))? - .as_str(); - - return Ok(Metadata { - symbol: format!("unbondUMat{start_match}({shortened_id}…)"), - ..metadata - }); - } else if let Some(captures) = delegation_re.captures(&metadata.base) { - let shortened_id = shorten_id(&captures)?; - - return Ok(Metadata { - symbol: format!("delUM({shortened_id}…)"), - ..metadata - }); - } else if let Some(captures) = auction_re.captures(&metadata.base) { - let shortened_id = shorten_id(&captures)?; - let seq_num = get_seq_num(&captures)?; - - return Ok(Metadata { - symbol: format!("auction@{seq_num}({shortened_id}…)"), - ..metadata - }); - } - - Ok(metadata) -} - -fn shorten_id(captures: ®ex::Captures) -> WasmResult { - let id_match = captures - .name("id") - .ok_or_else(|| anyhow!(" not matched in token regex"))?; - Ok(id_match - .as_str() - .chars() - .take(SHORTENED_ID_LENGTH) - .collect()) -} - -fn get_seq_num(captures: ®ex::Captures) -> WasmResult { - Ok(captures - .name("seq_num") - .ok_or_else(|| anyhow!(" not matched in auction NFT token regex"))? - .as_str() - .chars() - .collect()) -} - -#[cfg(test)] -mod test_helpers { - use penumbra_proto::core::asset::v1::DenomUnit; - - use super::*; - - pub fn get_metadata_for(display_denom: &str, base_denom_is_display_denom: bool) -> Metadata { - let mut denom_units = Vec::new(); - denom_units.push(DenomUnit { - aliases: Vec::new(), - denom: if base_denom_is_display_denom { - String::from(display_denom) - } else { - format!("u{display_denom}") - }, - exponent: 0, - }); - - if !base_denom_is_display_denom { - denom_units.push(DenomUnit { - aliases: Vec::new(), - denom: String::from(display_denom), - exponent: 6, - }); - } - - Metadata { - base: if base_denom_is_display_denom { - String::from(display_denom) - } else { - format!("u{display_denom}") - }, - description: String::from(""), - denom_units, - display: String::from(display_denom), - images: Vec::new(), - name: String::from(""), - penumbra_asset_id: None, - symbol: String::from(""), - priority_score: 0, - } - } - - #[test] - fn it_interpolates_display_denom() { - assert_eq!(get_metadata_for("penumbra", false).base, "upenumbra"); - assert_eq!(get_metadata_for("penumbra", false).display, "penumbra"); - assert_eq!( - get_metadata_for("penumbra", false).denom_units[0].denom, - "upenumbra" - ); - assert_eq!( - get_metadata_for("penumbra", false).denom_units[1].denom, - "penumbra" - ); - } -} - -#[cfg(test)] -mod customize_symbol_inner_tests { - use super::*; - - #[test] - fn it_returns_non_staking_metadata_as_is() { - let metadata = Metadata { - name: String::from("Penumbra"), - symbol: String::from("UM"), - ..test_helpers::get_metadata_for("penumbra", false) - }; - let customized_metadata = customize_symbol_inner(metadata.clone()).unwrap(); - - assert_eq!(metadata, customized_metadata); - } - - #[test] - fn it_modifies_unbonding_token_symbol() { - let metadata = Metadata { - name: String::from("Unbonding Token"), - symbol: String::from(""), - ..test_helpers::get_metadata_for( - "unbonding_start_at_1234_penumbravalid1abcdef123456", - false, - ) - }; - let customized_metadata = customize_symbol_inner(metadata.clone()).unwrap(); - - assert_eq!(customized_metadata.symbol, "unbondUMat1234(abcdef12…)"); - } - - #[test] - fn it_modifies_delegation_token_symbol() { - let metadata = Metadata { - name: String::from("Delegation Token"), - symbol: String::from(""), - ..test_helpers::get_metadata_for("delegation_penumbravalid1abcdef123456", false) - }; - let customized_metadata = customize_symbol_inner(metadata.clone()).unwrap(); - - assert_eq!(customized_metadata.symbol, "delUM(abcdef12…)"); - } - - #[test] - fn it_modifies_auction_nft_symbol_with_seq_num() { - let metadata = Metadata { - name: String::from(""), - symbol: String::from(""), - ..test_helpers::get_metadata_for( - "auctionnft_0_pauctid1jqyupqnzznyfpq940mv0ac33pyx77s7af3kgdw4nstjmp3567dks8n5amh", - true, - ) - }; - let customized_metadata = customize_symbol_inner(metadata.clone()).unwrap(); - - assert_eq!(customized_metadata.symbol, "auction@0(jqyupqnz…)"); - - let metadata = Metadata { - name: String::from(""), - symbol: String::from(""), - ..test_helpers::get_metadata_for( - "auctionnft_123_pauctid1jqyupqnzznyfpq940mv0ac33pyx77s7af3kgdw4nstjmp3567dks8n5amh", - true, - ) - }; - let customized_metadata = customize_symbol_inner(metadata.clone()).unwrap(); - - assert_eq!(customized_metadata.symbol, "auction@123(jqyupqnz…)"); - } -} - -#[cfg(test)] -mod customize_symbol_tests { - use super::*; - - #[test] - /// `customize_symbol` is just a thin wrapper around - /// `customize_symbol_inner` that allows metadata to be passed in as a byte - /// array. So we'll just do a basic test to make sure it works as expected, - /// rather than exercising every use case. - fn it_works() { - let metadata = Metadata { - name: String::from("Delegation Token"), - symbol: String::from(""), - ..test_helpers::get_metadata_for("delegation_penumbravalid1abcdef123456", false) - }; - let metadata_as_bytes = MetadataDomainType::try_from(metadata) - .unwrap() - .encode_to_vec(); - let customized_metadata_bytes = customize_symbol(&metadata_as_bytes).unwrap(); - let customized_metadata_result = - MetadataDomainType::decode::<&[u8]>(&customized_metadata_bytes); - let customized_metadata_proto = customized_metadata_result.unwrap().to_proto(); - - assert_eq!(customized_metadata_proto.symbol, "delUM(abcdef12...)"); - } -} diff --git a/packages/wasm/crate/src/note_record.rs b/packages/wasm/crate/src/note_record.rs deleted file mode 100644 index df889572..00000000 --- a/packages/wasm/crate/src/note_record.rs +++ /dev/null @@ -1,77 +0,0 @@ -use penumbra_keys::{keys::AddressIndex, AddressView}; -use penumbra_proto::{view::v1 as pb, DomainType}; -use penumbra_sct::{CommitmentSource, Nullifier}; -use penumbra_shielded_pool::{note, Note}; -use penumbra_tct as tct; -use serde::{Deserialize, Serialize}; -use std::convert::{TryFrom, TryInto}; - -/// Corresponds to the SpendableNoteRecord proto -#[derive(Serialize, Deserialize, Debug, Clone)] -#[serde(try_from = "pb::SpendableNoteRecord", into = "pb::SpendableNoteRecord")] -pub struct SpendableNoteRecord { - pub note_commitment: note::StateCommitment, - pub note: Note, - pub address_index: AddressIndex, - pub nullifier: Nullifier, - pub height_created: u64, - pub height_spent: Option, - pub position: tct::Position, - pub source: CommitmentSource, - pub return_address: Option, -} - -impl DomainType for SpendableNoteRecord { - type Proto = pb::SpendableNoteRecord; -} -impl From for pb::SpendableNoteRecord { - fn from(v: SpendableNoteRecord) -> Self { - pb::SpendableNoteRecord { - note_commitment: Some(v.note_commitment.into()), - note: Some(v.note.into()), - address_index: Some(v.address_index.into()), - nullifier: Some(v.nullifier.into()), - height_created: v.height_created, - height_spent: v.height_spent.unwrap_or(0), - position: v.position.into(), - source: Some(v.source.into()), - return_address: v.return_address.map(Into::into), - } - } -} - -impl TryFrom for SpendableNoteRecord { - type Error = anyhow::Error; - fn try_from(v: pb::SpendableNoteRecord) -> Result { - Ok(SpendableNoteRecord { - note_commitment: v - .note_commitment - .ok_or_else(|| anyhow::anyhow!("missing note commitment"))? - .try_into()?, - note: v - .note - .ok_or_else(|| anyhow::anyhow!("missing note"))? - .try_into()?, - address_index: v - .address_index - .ok_or_else(|| anyhow::anyhow!("missing address index"))? - .try_into()?, - nullifier: v - .nullifier - .ok_or_else(|| anyhow::anyhow!("missing nullifier"))? - .try_into()?, - height_created: v.height_created, - height_spent: if v.height_spent > 0 { - Some(v.height_spent) - } else { - None - }, - position: v.position.into(), - source: v - .source - .ok_or_else(|| anyhow::anyhow!("missing note source"))? - .try_into()?, - return_address: v.return_address.map(TryInto::try_into).transpose()?, - }) - } -} diff --git a/packages/wasm/crate/src/planner.rs b/packages/wasm/crate/src/planner.rs deleted file mode 100644 index 3d9d0c51..00000000 --- a/packages/wasm/crate/src/planner.rs +++ /dev/null @@ -1,534 +0,0 @@ -use crate::metadata::customize_symbol_inner; -use crate::note_record::SpendableNoteRecord; -use crate::storage::{IndexedDBStorage, OutstandingReserves}; -use crate::utils; -use crate::{error::WasmResult, swap_record::SwapRecord}; -use anyhow::anyhow; -use ark_ff::UniformRand; -use decaf377::{Fq, Fr}; -use penumbra_asset::asset::{Id, Metadata}; -use penumbra_asset::Value; -use penumbra_auction::auction::dutch::actions::ActionDutchAuctionWithdrawPlan; -use penumbra_auction::auction::dutch::{ - ActionDutchAuctionEnd, ActionDutchAuctionSchedule, DutchAuctionDescription, -}; -use penumbra_auction::auction::{AuctionId, AuctionNft}; -use penumbra_dex::swap_claim::SwapClaimPlan; -use penumbra_dex::{ - swap::{SwapPlaintext, SwapPlan}, - TradingPair, -}; -use penumbra_fee::{FeeTier, GasPrices}; -use penumbra_keys::keys::AddressIndex; -use penumbra_keys::FullViewingKey; -use penumbra_num::Amount; -use penumbra_proto::core::app::v1::AppParameters; -use penumbra_proto::core::component::ibc; -use penumbra_proto::view::v1::{ - transaction_planner_request as tpr, NotesRequest, TransactionPlannerRequest, -}; -use penumbra_proto::DomainType; -use penumbra_sct::params::SctParameters; -use penumbra_shielded_pool::{fmd, OutputPlan, SpendPlan}; -use penumbra_stake::rate::RateData; -use penumbra_stake::{IdentityKey, Penalty, Undelegate, UndelegateClaimPlan}; -use penumbra_transaction::gas::swap_claim_gas_cost; -use penumbra_transaction::memo::MemoPlaintext; -use penumbra_transaction::ActionList; -use penumbra_transaction::{plan::MemoPlan, ActionPlan, TransactionParameters}; -use prost::Message; -use rand_core::{OsRng, RngCore}; -use std::collections::BTreeMap; -use std::mem; -use wasm_bindgen::prelude::wasm_bindgen; -use wasm_bindgen::JsValue; - -/// Prioritize notes to spend to release value of a specific transaction. -/// -/// Various logic is possible for note selection. Currently, this method -/// prioritizes notes sent to a one-time address, then notes with the largest -/// value: -/// -/// - Prioritizing notes sent to one-time addresses optimizes for a future in -/// which we implement DAGSync keyed by fuzzy message detection (which will not -/// be able to detect notes sent to one-time addresses). Spending these notes -/// immediately converts them into change notes, sent to the default address for -/// the users' account, which are detectable. -/// -/// - Prioritizing notes with the largest value optimizes for gas used by the -/// transaction. -/// -/// We may want to make note prioritization configurable in the future. For -/// instance, a user might prefer a note prioritization strategy that harvested -/// capital losses when possible, using cost basis information retained by the -/// view server. -fn prioritize_and_filter_spendable_notes( - records: Vec, -) -> Vec { - let mut filtered = records - .into_iter() - .filter(|record| record.note.amount() > Amount::zero()) - .collect::>(); - - filtered.sort_by(|a, b| { - // Sort by whether the note was sent to an ephemeral address... - match ( - a.address_index.is_ephemeral(), - b.address_index.is_ephemeral(), - ) { - (true, false) => std::cmp::Ordering::Less, - (false, true) => std::cmp::Ordering::Greater, - // ... then by largest amount. - _ => b.note.amount().cmp(&a.note.amount()), - } - }); - - filtered -} - -/// When planning an undelegate action, there may not be metadata yet in the -/// IndexedDB database for the unbonding token that the transaction will output. -/// That's because unbonding tokens are tied to a specific height. If unbonding -/// token metadata for a given validator and a given height doesn't exist yet, -/// we'll generate it here and save it to the database, so that the undelegate -/// action renders correctly in the transaction approval dialog. -async fn save_unbonding_token_metadata_if_needed( - undelegate: &Undelegate, - storage: &IndexedDBStorage, -) -> WasmResult<()> { - let metadata = undelegate.unbonding_token().denom(); - - save_metadata_if_needed(metadata, storage).await -} - -/// When planning Dutch auction-related actions, there will not be metadata yet -/// in the IndexedDB database for the auction NFT that the transaction will -/// output. That's because auction NFTs are derived from information about the -/// auction (for example, an NFT corresponding to a newly started auction is -/// dervived from the auction description parameters, which include a nonce). So -/// we'll generate the metadata here and save it to the database, so that the -/// action renders correctly in the transaction approval dialog. -async fn save_auction_nft_metadata_if_needed( - id: AuctionId, - storage: &IndexedDBStorage, - seq: u64, -) -> WasmResult<()> { - let nft = AuctionNft::new(id, seq); - let metadata = nft.metadata; - - save_metadata_if_needed(metadata, storage).await -} - -async fn save_metadata_if_needed(metadata: Metadata, storage: &IndexedDBStorage) -> WasmResult<()> { - if storage.get_asset(&metadata.id()).await?.is_none() { - let metadata_proto = metadata.to_proto(); - let customized_metadata_proto = customize_symbol_inner(metadata_proto)?; - let customized_metadata = Metadata::try_from(customized_metadata_proto)?; - storage.add_asset(&customized_metadata).await - } else { - Ok(()) - } -} - -/// Process a `TransactionPlannerRequest`, returning a `TransactionPlan` -#[wasm_bindgen] -pub async fn plan_transaction( - idb_constants: JsValue, - request: &[u8], - full_viewing_key: &[u8], -) -> WasmResult { - utils::set_panic_hook(); - - let request = TransactionPlannerRequest::decode(request)?; - - let mut source_address_index: AddressIndex = request - .source - .map(TryInto::try_into) - .transpose()? - .unwrap_or_default(); - - // Wipe out the randomizer for the provided source, since - // 1. All randomizers correspond to the same account - // 2. Using one-time addresses for change addresses is undesirable. - source_address_index.randomizer = [0u8; 12]; - - let fvk: FullViewingKey = FullViewingKey::decode(full_viewing_key)?; - - // Compute the change address for this transaction. - let (change_address, _) = fvk - .incoming() - .payment_address(source_address_index.account.into()); - - let storage = IndexedDBStorage::new(serde_wasm_bindgen::from_value(idb_constants)?).await?; - - let fmd_params: fmd::Parameters = storage - .get_fmd_params() - .await? - .ok_or_else(|| anyhow!("FmdParameters not available"))?; - - let app_parameters: AppParameters = storage - .get_app_params() - .await? - .ok_or_else(|| anyhow!("AppParameters not available"))?; - - let sct_params: SctParameters = app_parameters - .sct_params - .ok_or_else(|| anyhow!("SctParameters not available"))? - .try_into()?; - - let chain_id: String = app_parameters.chain_id; - - let transaction_parameters = TransactionParameters { - chain_id, - ..Default::default() - }; - - let gas_prices: GasPrices = { - let gas_prices: penumbra_proto::core::component::fee::v1::GasPrices = - serde_wasm_bindgen::from_value( - storage - .get_gas_prices() - .await? - .ok_or_else(|| anyhow!("GasPrices not available"))?, - )?; - gas_prices.try_into()? - }; - - let fee_tier = match request.fee_mode { - None => FeeTier::default(), - Some(tpr::FeeMode::AutoFee(tier)) => tier.try_into()?, - Some(tpr::FeeMode::ManualFee(_)) => { - return Err(anyhow!("Manual fee mode not yet implemented").into()); - } - }; - - let mut actions_list = ActionList::default(); - - // Phase 1: process all of the user-supplied intents into complete action plans. - - for tpr::Output { value, address } in request.outputs { - let value = value - .ok_or_else(|| anyhow!("missing value in output"))? - .try_into()?; - let address = address - .ok_or_else(|| anyhow!("missing address in output"))? - .try_into()?; - let output = OutputPlan::new(&mut OsRng, value, address); - - actions_list.push(output); - } - - for tpr::Swap { - value, - target_asset, - // The prepaid fee will instead be calculated directly in the rust planner logic. - // - // TODO: external consumers of prax may decide to enable manaual fees, and there may be - // additional checks required to make sure the fees satisfy to the balancing checks - // for swap claims. - fee: _, - claim_address, - } in request.swaps - { - let value: Value = value - .ok_or_else(|| anyhow!("missing value in swap"))? - .try_into()?; - let target_asset = target_asset - .ok_or_else(|| anyhow!("missing target asset in swap"))? - .try_into()?; - let claim_address = claim_address - .ok_or_else(|| anyhow!("missing claim address in swap"))? - .try_into()?; - - // This is the prepaid fee for the swap claim. We don't expect much of a drift in gas - // prices in a few blocks, and the fee tier adjustments should be enough to cover it. - let estimated_claim_fee = gas_prices.fee(&swap_claim_gas_cost()).apply_tier(fee_tier); - - // Determine the canonical order for the assets being swapped. - // This will determine whether the input amount is assigned to delta_1 or delta_2. - let trading_pair = TradingPair::new(value.asset_id, target_asset); - - // If `trading_pair.asset_1` is the input asset, then `delta_1` is the input amount, - // and `delta_2` is 0. - // - // Otherwise, `delta_1` is 0, and `delta_2` is the input amount. - let (delta_1, delta_2) = if trading_pair.asset_1() == value.asset_id { - (value.amount, 0u64.into()) - } else { - (0u64.into(), value.amount) - }; - - // If there is no input, then there is no swap. - if delta_1 == Amount::zero() && delta_2 == Amount::zero() { - return Err(anyhow!("No input value for swap").into()); - } - - // Create the `SwapPlaintext` representing the swap to be performed: - let swap_plaintext = SwapPlaintext::new( - &mut OsRng, - trading_pair, - delta_1, - delta_2, - estimated_claim_fee, - claim_address, - ); - let swap = SwapPlan::new(&mut OsRng, swap_plaintext); - - actions_list.push(swap); - } - - for tpr::SwapClaim { swap_commitment } in request.swap_claims { - let swap_commitment = - swap_commitment.ok_or_else(|| anyhow!("missing swap commitment in swap claim"))?; - - let swap_record: SwapRecord = storage - .get_swap_by_commitment(swap_commitment) - .await? - .ok_or_else(|| anyhow!("Swap record not found"))? - .try_into()?; - - let swap_claim = SwapClaimPlan { - swap_plaintext: swap_record.swap, - position: swap_record.position, - output_data: swap_record.output_data, - epoch_duration: sct_params.epoch_duration, - proof_blinding_r: Fq::rand(&mut OsRng), - proof_blinding_s: Fq::rand(&mut OsRng), - }; - - actions_list.push(swap_claim); - } - - for tpr::Delegate { amount, rate_data } in request.delegations { - let epoch = storage.get_latest_known_epoch().await?.unwrap(); - let amount = amount - .ok_or_else(|| anyhow!("missing amount in delegation"))? - .try_into()?; - let rate_data: RateData = rate_data - .ok_or_else(|| anyhow!("missing rate data in delegation"))? - .try_into()?; - let delegate = rate_data.build_delegate(epoch.into(), amount); - - actions_list.push(delegate); - } - - for tpr::Undelegate { value, rate_data } in request.undelegations { - let epoch = storage.get_latest_known_epoch().await?.unwrap(); - let value: Value = value - .ok_or_else(|| anyhow!("missing value in undelegation"))? - .try_into()?; - let rate_data: RateData = rate_data - .ok_or_else(|| anyhow!("missing rate data in undelegation"))? - .try_into()?; - let undelegate = rate_data.build_undelegate(epoch.into(), value.amount); - save_unbonding_token_metadata_if_needed(&undelegate, &storage).await?; - - actions_list.push(undelegate); - } - - for tpr::UndelegateClaim { - validator_identity, - unbonding_start_height, - penalty, - unbonding_amount, - .. - } in request.undelegation_claims - { - let validator_identity: IdentityKey = validator_identity - .ok_or_else(|| anyhow!("missing validator identity in undelegation claim"))? - .try_into()?; - let penalty: Penalty = penalty - .ok_or_else(|| anyhow!("missing penalty in undelegation claim"))? - .try_into()?; - let unbonding_amount: Amount = unbonding_amount - .ok_or_else(|| anyhow!("missing unbonding amount in undelegation claim"))? - .try_into()?; - - let undelegate_claim_plan = UndelegateClaimPlan { - validator_identity, - unbonding_start_height, - penalty, - unbonding_amount, - balance_blinding: Fr::rand(&mut OsRng), - proof_blinding_r: Fq::rand(&mut OsRng), - proof_blinding_s: Fq::rand(&mut OsRng), - }; - - actions_list.push(ActionPlan::UndelegateClaim(undelegate_claim_plan)); - } - - #[allow(clippy::never_loop)] - for ibc::v1::IbcRelay { .. } in request.ibc_relay_actions { - return Err(anyhow!("IbcRelay not yet implemented").into()); - } - - for ics20_withdrawal in request.ics20_withdrawals { - actions_list.push(ActionPlan::Ics20Withdrawal(ics20_withdrawal.try_into()?)); - } - - #[allow(clippy::never_loop)] - for tpr::PositionOpen { .. } in request.position_opens { - return Err(anyhow!("PositionOpen not yet implemented").into()); - } - - #[allow(clippy::never_loop)] - for tpr::PositionClose { .. } in request.position_closes { - return Err(anyhow!("PositionClose not yet implemented").into()); - } - - #[allow(clippy::never_loop)] - for tpr::PositionWithdraw { .. } in request.position_withdraws { - return Err(anyhow!("PositionWithdraw not yet implemented").into()); - } - - for tpr::ActionDutchAuctionSchedule { description } in request.dutch_auction_schedule_actions { - let description = description - .ok_or_else(|| anyhow!("missing description in Dutch auction schedule action"))?; - let input: Value = description - .input - .ok_or_else(|| anyhow!("missing input in Dutch auction schedule action"))? - .try_into()?; - let output_id: Id = description - .output_id - .ok_or_else(|| anyhow!("missing output ID in Dutch auction schedule action"))? - .try_into()?; - let min_output: Amount = description - .min_output - .ok_or_else(|| anyhow!("missing min output in Dutch auction schedule action"))? - .try_into()?; - let max_output: Amount = description - .max_output - .ok_or_else(|| anyhow!("missing max output in Dutch auction schedule action"))? - .try_into()?; - let mut nonce = [0u8; 32]; - OsRng.fill_bytes(&mut nonce); - - let description = DutchAuctionDescription { - start_height: description.start_height, - end_height: description.end_height, - step_count: description.step_count, - input, - output_id, - min_output, - max_output, - nonce, - }; - - save_auction_nft_metadata_if_needed(description.id(), &storage, 0).await?; - - actions_list.push(ActionPlan::ActionDutchAuctionSchedule( - ActionDutchAuctionSchedule { description }, - )); - } - - for tpr::ActionDutchAuctionEnd { auction_id } in request.dutch_auction_end_actions { - let auction_id: AuctionId = auction_id - .ok_or_else(|| anyhow!("missing auction ID in Dutch auction end action"))? - .try_into()?; - - save_auction_nft_metadata_if_needed( - auction_id, &storage, - // When ending a Dutch auction, the sequence number is always 1 - 1, - ) - .await?; - - actions_list.push(ActionPlan::ActionDutchAuctionEnd(ActionDutchAuctionEnd { - auction_id, - })); - } - - for tpr::ActionDutchAuctionWithdraw { auction_id, seq } in - request.dutch_auction_withdraw_actions - { - let auction_id: AuctionId = auction_id - .ok_or_else(|| anyhow!("missing auction ID in Dutch auction withdraw action"))? - .try_into()?; - - save_auction_nft_metadata_if_needed(auction_id, &storage, seq).await?; - let outstanding_reserves: OutstandingReserves = - storage.get_auction_oustanding_reserves(auction_id).await?; - - actions_list.push(ActionPlan::ActionDutchAuctionWithdraw( - ActionDutchAuctionWithdrawPlan { - auction_id, - seq, - reserves_input: outstanding_reserves.input.try_into()?, - reserves_output: outstanding_reserves.output.try_into()?, - }, - )); - } - - // Phase 2: balance the transaction with information from the view service. - // - // It's possible that adding spends could increase the gas, increasing - // the fee amount, and so on, so we add spends iteratively. However, we - // need to query all the notes we'll use for planning upfront, so we - // don't accidentally try to use the same one twice. - - // Compute an initial fee estimate based on the actions we have so far. - actions_list.refresh_fee_and_change(OsRng, &gas_prices, &fee_tier, &change_address); - - let mut notes_by_asset_id = BTreeMap::new(); - for required in actions_list.balance_with_fee().required() { - // Find all the notes of this asset in the source account. - let records = storage - .get_notes(NotesRequest { - include_spent: false, - asset_id: Some(required.asset_id.into()), - address_index: Some(source_address_index.into()), - amount_to_spend: None, - }) - .await?; - notes_by_asset_id.insert( - required.asset_id, - prioritize_and_filter_spendable_notes(records), - ); - } - - let mut iterations = 0usize; - - // Now iterate over the action list's imbalances to balance the transaction. - while let Some(required) = actions_list.balance_with_fee().required().next() { - // Find a single note to spend towards the required balance. - let note = notes_by_asset_id - .get_mut(&required.asset_id) - .and_then(|notes| notes.pop()) - .ok_or_else(|| { - anyhow!( - "Failed to retrieve or ran out of notes for asset {}, required amount {}", - required.asset_id, - required.amount - ) - })?; - - // Add a spend for that note to the action list. - actions_list.push(SpendPlan::new(&mut OsRng, note.note, note.position)); - - // Refresh the fee estimate and change outputs. - actions_list.refresh_fee_and_change(OsRng, &gas_prices, &fee_tier, &change_address); - - iterations += 1; - if iterations > 100 { - return Err(anyhow!("failed to plan transaction after 100 iterations").into()); - } - } - - // Add memo to the transaction plan. - let memo = if let Some(pb_memo_plaintext) = request.memo { - Some(MemoPlan::new(&mut OsRng, pb_memo_plaintext.try_into()?)) - } else if actions_list.requires_memo() { - // If a memo was not provided, but is required (because we have outputs), - // auto-create one with the change address. - let plaintext = MemoPlaintext::new(change_address, String::new())?; - Some(MemoPlan::new(&mut OsRng, plaintext)) - } else { - None - }; - - // Reset the planner in case it were reused. - let plan = - mem::take(&mut actions_list).into_plan(OsRng, &fmd_params, transaction_parameters, memo)?; - - Ok(serde_wasm_bindgen::to_value(&plan)?) -} diff --git a/packages/wasm/crate/src/storage.rs b/packages/wasm/crate/src/storage.rs deleted file mode 100644 index 39648cdb..00000000 --- a/packages/wasm/crate/src/storage.rs +++ /dev/null @@ -1,397 +0,0 @@ -#[allow(unused_imports)] -use std::future::IntoFuture; - -use anyhow::Error; -use indexed_db_futures::{ - prelude::{IdbObjectStoreParameters, IdbOpenDbRequestLike, OpenDbRequest}, - IdbDatabase, IdbKeyPath, IdbQuerySource, IdbVersionChangeEvent, -}; -use penumbra_asset::asset::{self, Id, Metadata}; -use penumbra_auction::auction::AuctionId; -use penumbra_keys::keys::AddressIndex; -use penumbra_num::Amount; -use penumbra_proto::{ - core::{app::v1::AppParameters, asset::v1::Value, component::sct::v1::Epoch}, - crypto::tct::v1::StateCommitment, - view::v1::{NotesRequest, SwapRecord, TransactionInfo}, - DomainType, -}; -use penumbra_sct::Nullifier; -use penumbra_shielded_pool::{fmd, note, Note}; -use serde::{Deserialize, Serialize}; -use wasm_bindgen::JsValue; -use web_sys::IdbTransactionMode::Readwrite; - -use crate::error::{WasmError, WasmResult}; -use crate::note_record::SpendableNoteRecord; - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct IndexedDbConstants { - pub name: String, - pub version: u32, - pub tables: Tables, -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct Tables { - pub assets: String, - pub advice_notes: String, - pub spendable_notes: String, - pub swaps: String, - pub fmd_parameters: String, - pub app_parameters: String, - pub gas_prices: String, - pub epochs: String, - pub transactions: String, - pub full_sync_height: String, - pub auctions: String, - pub auction_outstanding_reserves: String, -} - -pub struct IndexedDBStorage { - db: IdbDatabase, - constants: IndexedDbConstants, -} - -impl IndexedDBStorage { - pub async fn new(constants: IndexedDbConstants) -> WasmResult { - #[allow(unused_mut)] - let mut db_req: OpenDbRequest = IdbDatabase::open_u32(&constants.name, constants.version)?; - - // Conditionally mock sample `IdbDatabase` database for testing purposes - #[cfg(feature = "mock-database")] - let db_req = IndexedDBStorage::mock_test_database(db_req) - .into_future() - .await; - - let db: IdbDatabase = db_req.into_future().await?; - - Ok(IndexedDBStorage { db, constants }) - } - - pub async fn mock_test_database(mut db_req: OpenDbRequest) -> OpenDbRequest { - db_req.set_on_upgrade_needed(Some(|evt: &IdbVersionChangeEvent| -> Result<(), JsValue> { - // Check if the object store exists; create it if it doesn't - if evt.db().name() == "penumbra-db-wasm-test" { - let note_key: JsValue = serde_wasm_bindgen::to_value("noteCommitment.inner")?; - let note_object_store_params = IdbObjectStoreParameters::new() - .key_path(Some(&IdbKeyPath::new(note_key))) - .to_owned(); - let note_object_store = evt.db().create_object_store_with_params( - "SPENDABLE_NOTES", - ¬e_object_store_params, - )?; - - let nullifier_key: JsValue = serde_wasm_bindgen::to_value("nullifier.inner")?; - note_object_store.create_index_with_params( - "nullifier", - &IdbKeyPath::new(nullifier_key), - web_sys::IdbIndexParameters::new().unique(false), - )?; - evt.db().create_object_store("TREE_LAST_POSITION")?; - evt.db().create_object_store("TREE_LAST_FORGOTTEN")?; - - let commitment_key: JsValue = serde_wasm_bindgen::to_value("commitment.inner")?; - let commitment_object_store_params = IdbObjectStoreParameters::new() - .key_path(Some(&IdbKeyPath::new(commitment_key))) - .to_owned(); - evt.db().create_object_store_with_params( - "TREE_COMMITMENTS", - &commitment_object_store_params, - )?; - evt.db().create_object_store("TREE_HASHES")?; - evt.db().create_object_store("FMD_PARAMETERS")?; - evt.db().create_object_store("APP_PARAMETERS")?; - evt.db().create_object_store("GAS_PRICES")?; - } - Ok(()) - })); - - db_req - } - - pub fn get_database(&self) -> *const IdbDatabase { - &self.db - } - - pub async fn get_notes(&self, request: NotesRequest) -> WasmResult> { - let idb_tx = self - .db - .transaction_on_one(&self.constants.tables.spendable_notes)?; - let store = idb_tx.object_store(&self.constants.tables.spendable_notes)?; - - let asset_id: Option = request.asset_id.map(TryInto::try_into).transpose()?; - let address_index: Option = - request.address_index.map(TryInto::try_into).transpose()?; - let amount_to_spend: Option = - request.amount_to_spend.map(TryInto::try_into).transpose()?; - - if let (None, Some(_)) = (asset_id, amount_to_spend) { - return Err( - anyhow::anyhow!("specified amount_to_spend without asset_id filter").into(), - ); - } - - let mut records = Vec::new(); - let mut total = Amount::zero(); - - let raw_values = store.get_all()?.await?; - for raw_record in raw_values { - let record: SpendableNoteRecord = serde_wasm_bindgen::from_value(raw_record)?; - - if !request.include_spent && record.height_spent.is_some() { - continue; - } - - if Some(record.note.asset_id()) != asset_id { - continue; - } - - // Planner should omit the address index randomizer and compare only the account index - if let Some(ai) = address_index { - if record.address_index.account != ai.account { - continue; - } - } - - total += record.note.amount(); - records.push(record); - - if let Some(amount_to_spend) = amount_to_spend { - if total >= amount_to_spend { - break; - } - } - } - - Ok(records) - } - - pub async fn get_asset(&self, id: &Id) -> WasmResult> { - let tx = self.db.transaction_on_one(&self.constants.tables.assets)?; - let store = tx.object_store(&self.constants.tables.assets)?; - - Ok(store - .get_owned(byte_array_to_base64(&id.to_proto().inner))? - .await? - .map(serde_wasm_bindgen::from_value) - .transpose()?) - } - - pub async fn add_asset(&self, metadata: &Metadata) -> WasmResult<()> { - let tx = self - .db - .transaction_on_one_with_mode(&self.constants.tables.assets, Readwrite)?; - let store = tx.object_store(&self.constants.tables.assets)?; - let metadata_js = serde_wasm_bindgen::to_value(&metadata.to_proto())?; - - store.put_val_owned(&metadata_js)?; - - Ok(()) - } - - pub async fn get_full_sync_height(&self) -> WasmResult> { - let tx = self - .db - .transaction_on_one(&self.constants.tables.full_sync_height)?; - let store = tx.object_store(&self.constants.tables.full_sync_height)?; - - Ok(store - .get_owned("height")? - .await? - .map(serde_wasm_bindgen::from_value) - .transpose()?) - } - - pub async fn get_note( - &self, - commitment: ¬e::StateCommitment, - ) -> WasmResult> { - let tx = self - .db - .transaction_on_one(&self.constants.tables.spendable_notes)?; - let store = tx.object_store(&self.constants.tables.spendable_notes)?; - - Ok(store - .get_owned(byte_array_to_base64(&commitment.to_proto().inner))? - .await? - .map(serde_wasm_bindgen::from_value) - .transpose()?) - } - - pub async fn get_note_by_nullifier( - &self, - nullifier: &Nullifier, - ) -> WasmResult> { - let tx = self - .db - .transaction_on_one(&self.constants.tables.spendable_notes)?; - let store = tx.object_store(&self.constants.tables.spendable_notes)?; - - Ok(store - .index("nullifier")? - .get_owned(byte_array_to_base64(&nullifier.to_proto().inner))? - .await? - .map(serde_wasm_bindgen::from_value) - .transpose()?) - } - - pub async fn store_advice(&self, note: Note) -> WasmResult<()> { - let tx = self - .db - .transaction_on_one_with_mode(&self.constants.tables.advice_notes, Readwrite)?; - let store = tx.object_store(&self.constants.tables.advice_notes)?; - - let note_proto: penumbra_proto::core::component::shielded_pool::v1::Note = - note.clone().into(); - let note_js = serde_wasm_bindgen::to_value(¬e_proto)?; - - let commitment_proto = note.commit().to_proto(); - - store.put_key_val_owned(byte_array_to_base64(&commitment_proto.inner), ¬e_js)?; - - Ok(()) - } - - pub async fn read_advice(&self, commitment: note::StateCommitment) -> WasmResult> { - let tx = self - .db - .transaction_on_one(&self.constants.tables.advice_notes)?; - let store = tx.object_store(&self.constants.tables.advice_notes)?; - - let commitment_proto = commitment.to_proto(); - - Ok(store - .get_owned(byte_array_to_base64(&commitment_proto.inner))? - .await? - .map(serde_wasm_bindgen::from_value) - .transpose()?) - } - - pub async fn get_swap_by_commitment( - &self, - swap_commitment: StateCommitment, - ) -> WasmResult> { - let tx = self.db.transaction_on_one(&self.constants.tables.swaps)?; - let store = tx.object_store(&self.constants.tables.swaps)?; - - Ok(store - .get_owned(byte_array_to_base64(&swap_commitment.inner))? - .await? - .map(serde_wasm_bindgen::from_value) - .transpose()?) - } - - pub async fn get_swap_by_nullifier( - &self, - nullifier: &Nullifier, - ) -> WasmResult> { - let tx = self.db.transaction_on_one(&self.constants.tables.swaps)?; - let store = tx.object_store(&self.constants.tables.swaps)?; - - Ok(store - .index("nullifier")? - .get_owned(byte_array_to_base64(&nullifier.to_proto().inner))? - .await? - .map(serde_wasm_bindgen::from_value) - .transpose()?) - } - - pub async fn get_fmd_params(&self) -> WasmResult> { - let tx = self - .db - .transaction_on_one(&self.constants.tables.fmd_parameters)?; - let store = tx.object_store(&self.constants.tables.fmd_parameters)?; - - Ok(store - .get_owned("params")? - .await? - .map(serde_wasm_bindgen::from_value) - .transpose()?) - } - - pub async fn get_app_params(&self) -> WasmResult> { - let tx = self - .db - .transaction_on_one(&self.constants.tables.app_parameters)?; - let store = tx.object_store(&self.constants.tables.app_parameters)?; - - Ok(store - .get_owned("params")? - .await? - .map(serde_wasm_bindgen::from_value) - .transpose()?) - } - - pub async fn get_gas_prices(&self) -> WasmResult> { - let tx = self - .db - .transaction_on_one(&self.constants.tables.gas_prices)?; - let store = tx.object_store(&self.constants.tables.gas_prices)?; - - Ok(store.get_owned("gas_prices")?.await?) - // TODO GasPrices is missing domain type impl, requiring this - // .map(serde_wasm_bindgen::from_value) - // .transpose()?) - } - - pub async fn get_latest_known_epoch(&self) -> WasmResult> { - let tx = self.db.transaction_on_one(&self.constants.tables.epochs)?; - let store = tx.object_store(&self.constants.tables.epochs)?; - - Ok(store - .open_cursor_with_direction(web_sys::IdbCursorDirection::Prev)? - .await? - .and_then(|cursor| serde_wasm_bindgen::from_value(cursor.value()).ok())) - } - - pub async fn get_transaction_infos(&self) -> WasmResult> { - let tx = self - .db - .transaction_on_one(&self.constants.tables.transactions)?; - let store = tx.object_store(&self.constants.tables.transactions)?; - - let mut records = Vec::new(); - let raw_values = store.get_all()?.await?; - - for raw_value in raw_values { - let record: TransactionInfo = serde_wasm_bindgen::from_value(raw_value)?; - records.push(record); - } - - Ok(records) - } - - pub async fn get_auction_oustanding_reserves( - &self, - auction_id: AuctionId, - ) -> WasmResult { - let result = self - .db - .transaction_on_one(&self.constants.tables.auction_outstanding_reserves)? - .object_store(&self.constants.tables.auction_outstanding_reserves)? - .get::(&byte_array_to_base64(&auction_id.to_proto().inner).into())? - .await? - .map(serde_wasm_bindgen::from_value::) - .unwrap_or(Err(WasmError::Anyhow(Error::msg( - "could not find reserves", - )) - .into())); - - if let Ok(outstanding_reserves) = result { - Ok(outstanding_reserves) - } else { - Err(WasmError::Anyhow(Error::msg("could not find reserves"))) - } - } -} - -fn byte_array_to_base64(byte_array: &Vec) -> String { - base64::Engine::encode(&base64::engine::general_purpose::STANDARD, byte_array) -} - -#[derive(Serialize, Deserialize)] -pub struct OutstandingReserves { - pub input: Value, - pub output: Value, -} diff --git a/packages/wasm/crate/src/swap_record.rs b/packages/wasm/crate/src/swap_record.rs deleted file mode 100644 index 4ab9dc61..00000000 --- a/packages/wasm/crate/src/swap_record.rs +++ /dev/null @@ -1,70 +0,0 @@ -use penumbra_dex::{swap::SwapPlaintext, BatchSwapOutputData}; -use penumbra_proto::{view::v1 as pb, DomainType}; -use penumbra_sct::{CommitmentSource, Nullifier}; -use penumbra_tct as tct; -use std::convert::{TryFrom, TryInto}; - -use serde::{Deserialize, Serialize}; - -#[derive(Serialize, Deserialize, Debug, Clone)] -#[serde(try_from = "pb::SwapRecord", into = "pb::SwapRecord")] -pub struct SwapRecord { - pub swap_commitment: tct::StateCommitment, - pub swap: SwapPlaintext, - pub position: tct::Position, - pub nullifier: Nullifier, - pub output_data: BatchSwapOutputData, - pub height_claimed: Option, - pub source: CommitmentSource, -} - -impl DomainType for SwapRecord { - type Proto = pb::SwapRecord; -} -impl From for pb::SwapRecord { - fn from(msg: SwapRecord) -> Self { - pb::SwapRecord { - swap_commitment: Some(msg.swap_commitment.into()), - swap: Some(msg.swap.into()), - position: msg.position.into(), - nullifier: Some(msg.nullifier.into()), - output_data: Some(msg.output_data.into()), - height_claimed: msg.height_claimed.unwrap_or(0), - source: Some(msg.source.into()), - } - } -} - -impl TryFrom for SwapRecord { - type Error = anyhow::Error; - fn try_from(value: pb::SwapRecord) -> Result { - Ok(Self { - swap_commitment: value - .swap_commitment - .ok_or_else(|| anyhow::anyhow!("missing swap_commitment"))? - .try_into()?, - swap: value - .swap - .ok_or_else(|| anyhow::anyhow!("missing swap"))? - .try_into()?, - position: value.position.into(), - nullifier: value - .nullifier - .ok_or_else(|| anyhow::anyhow!("missing nullifier"))? - .try_into()?, - output_data: value - .output_data - .ok_or_else(|| anyhow::anyhow!("missing output_data"))? - .try_into()?, - height_claimed: if value.height_claimed > 0 { - Some(value.height_claimed) - } else { - None - }, - source: value - .source - .ok_or_else(|| anyhow::anyhow!("missing source"))? - .try_into()?, - }) - } -} diff --git a/packages/wasm/crate/src/tree.rs b/packages/wasm/crate/src/tree.rs deleted file mode 100644 index 6603f6cf..00000000 --- a/packages/wasm/crate/src/tree.rs +++ /dev/null @@ -1,18 +0,0 @@ -use penumbra_proto::DomainType; -use penumbra_sct::epoch::Epoch; -use penumbra_tct::Position; -use wasm_bindgen::prelude::wasm_bindgen; - -use crate::error::WasmResult; - -#[wasm_bindgen] -pub fn sct_position(block_height: u64, epoch_bytes: &[u8]) -> WasmResult { - let epoch = Epoch::decode(epoch_bytes)?; - let epoch_index = u16::try_from(epoch.index)?; - // The block index is determined by looking at how many blocks have elapsed since - // the start of the epoch. - let block_index = u16::try_from(block_height - epoch.start_height)?; - - let position = Position::from((epoch_index, block_index, 0u16)); - Ok(position.into()) -} diff --git a/packages/wasm/crate/src/tx.rs b/packages/wasm/crate/src/tx.rs deleted file mode 100644 index 1355744d..00000000 --- a/packages/wasm/crate/src/tx.rs +++ /dev/null @@ -1,424 +0,0 @@ -use std::collections::{BTreeMap, BTreeSet}; -use std::convert::TryInto; - -use anyhow::anyhow; -use penumbra_auction::auction::dutch::actions::view::{ - ActionDutchAuctionScheduleView, ActionDutchAuctionWithdrawView, -}; -use penumbra_dex::BatchSwapOutputData; -use penumbra_keys::keys::SpendKey; -use penumbra_keys::FullViewingKey; -use penumbra_proto::core::transaction::v1::{TransactionPerspective, TransactionView}; -use penumbra_proto::DomainType; -use penumbra_sct::{CommitmentSource, Nullifier}; -use penumbra_tct::{Position, Proof, StateCommitment}; -use penumbra_transaction::plan::TransactionPlan; -use penumbra_transaction::txhash::TransactionId; -use penumbra_transaction::Action; -use penumbra_transaction::{AuthorizationData, Transaction, WitnessData}; -use prost::Message; -use rand_core::OsRng; -use wasm_bindgen::prelude::wasm_bindgen; -use wasm_bindgen::JsValue; - -use crate::error::{WasmError, WasmResult}; -use crate::storage::IndexedDBStorage; -use crate::storage::IndexedDbConstants; -use crate::utils; -use crate::view_server::{load_tree, StoredTree}; - -/// authorize transaction (sign transaction using spend key) -/// Arguments: -/// spend_key: `byte representation inner SpendKey` -/// transaction_plan: `pb::TransactionPlan` -/// Returns: `pb::AuthorizationData` -#[wasm_bindgen] -pub fn authorize(spend_key: &[u8], transaction_plan: &[u8]) -> WasmResult> { - utils::set_panic_hook(); - - let spend_key: SpendKey = SpendKey::decode(spend_key)?; - let plan = TransactionPlan::decode(transaction_plan)?; - - let auth_data: AuthorizationData = plan.authorize(OsRng, &spend_key)?; - Ok(auth_data.encode_to_vec()) -} - -/// Get witness data -/// Obtaining witness data is directly related to SCT so we need to pass the tree data -/// Arguments: -/// transaction_plan: `pb::TransactionPlan` -/// stored_tree: `StoredTree` -/// Returns: `pb::WitnessData` -#[wasm_bindgen] -pub fn witness(transaction_plan: &[u8], stored_tree: JsValue) -> WasmResult> { - utils::set_panic_hook(); - - let plan = TransactionPlan::decode(transaction_plan)?; - let stored_tree: StoredTree = serde_wasm_bindgen::from_value(stored_tree)?; - let sct = load_tree(stored_tree); - - let note_commitments: Vec = plan - .spend_plans() - .filter(|plan| plan.note.amount() != 0u64.into()) - .map(|spend| spend.note.commit()) - .chain( - plan.swap_claim_plans() - .map(|swap_claim| swap_claim.swap_plaintext.swap_commitment()), - ) - .collect(); - - let anchor = sct.root(); - - // Obtain an auth path for each requested note commitment - - let auth_paths = note_commitments - .iter() - .map(|nc| { - sct.witness(*nc) - .ok_or(anyhow!("note commitment is in the SCT")) - }) - .collect::, anyhow::Error>>()?; - - // Release the read lock on the SCT - drop(sct); - - let mut witness_data = WitnessData { - anchor, - state_commitment_proofs: auth_paths - .into_iter() - .map(|proof| (proof.commitment(), proof)) - .collect(), - }; - - // Now we need to augment the witness data with dummy proofs such that - // note commitments corresponding to dummy spends also have proofs. - for nc in plan - .spend_plans() - .filter(|plan| plan.note.amount() == 0u64.into()) - .map(|plan| plan.note.commit()) - { - witness_data.add_proof(nc, Proof::dummy(&mut OsRng, nc)); - } - - Ok(witness_data.encode_to_vec()) -} - -/// Build serial tx -/// Building a transaction may take some time, -/// depending on CPU performance and number of actions in transaction_plan -/// Arguments: -/// full_viewing_key: `byte representation inner FullViewingKey` -/// transaction_plan: `pb::TransactionPlan` -/// witness_data: `pb::WitnessData` -/// auth_data: `pb::AuthorizationData` -/// Returns: `pb::Transaction` -#[wasm_bindgen] -pub fn build( - full_viewing_key: &[u8], - transaction_plan: &[u8], - witness_data: &[u8], - auth_data: &[u8], -) -> WasmResult> { - utils::set_panic_hook(); - - let plan = TransactionPlan::decode(transaction_plan)?; - let witness = WitnessData::decode(witness_data)?; - let auth = AuthorizationData::decode(auth_data)?; - let fvk: FullViewingKey = FullViewingKey::decode(full_viewing_key)?; - - let tx: Transaction = plan.build(&fvk, &witness, &auth)?; - - Ok(tx.encode_to_vec()) -} - -/// Build parallel tx -/// Building a transaction may take some time, -/// depending on CPU performance and number of actions in transaction_plan -/// Arguments: -/// actions: `Vec` -/// transaction_plan: `pb::TransactionPlan` -/// witness_data: `pb::WitnessData` -/// auth_data: `pb::AuthorizationData` -/// Returns: `pb::Transaction` -#[wasm_bindgen] -pub fn build_parallel( - actions: JsValue, - transaction_plan: &[u8], - witness_data: &[u8], - auth_data: &[u8], -) -> WasmResult> { - utils::set_panic_hook(); - - let plan = TransactionPlan::decode(transaction_plan)?; - let witness = WitnessData::decode(witness_data)?; - let auth = AuthorizationData::decode(auth_data)?; - let actions: Vec = serde_wasm_bindgen::from_value(actions)?; - - let transaction = plan.clone().build_unauth_with_actions(actions, &witness)?; - - let tx = plan.apply_auth_data(&auth, transaction)?; - - Ok(tx.encode_to_vec()) -} - -#[wasm_bindgen(getter_with_clone)] -pub struct TxpAndTxvBytes { - pub txp: Vec, - pub txv: Vec, -} - -/// Get transaction perspective, transaction view -/// Arguments: -/// full_viewing_key: `FullViewingKey` inner bytes -/// tx: Binary-encoded `Transaction` message -/// idb_constants: IndexedDbConstants -/// Returns: `{ txp: Uint8Array, txv: Uint8Array }` representing binary-encoded `TransactionPerspective` and `TransactionView` -#[wasm_bindgen] -pub async fn transaction_perspective_and_view( - full_viewing_key: &[u8], - tx: &[u8], - idb_constants: JsValue, -) -> WasmResult { - utils::set_panic_hook(); - - let transaction = Transaction::decode(tx)?; - let constants = serde_wasm_bindgen::from_value(idb_constants)?; - let fvk = FullViewingKey::decode(full_viewing_key)?; - let (txp, txv) = transaction_info_inner(fvk, transaction, constants).await?; - - Ok(TxpAndTxvBytes { - txp: txp.encode_to_vec(), - txv: txv.encode_to_vec(), - }) -} - -async fn transaction_info_inner( - fvk: FullViewingKey, - tx: Transaction, - idb_constants: IndexedDbConstants, -) -> Result<(TransactionPerspective, TransactionView), WasmError> { - let storage = IndexedDBStorage::new(idb_constants).await?; - - // First, create a TxP with the payload keys visible to our FVK and no other data. - let mut txp = penumbra_transaction::TransactionPerspective { - payload_keys: tx.payload_keys(&fvk)?, - transaction_id: tx.id(), - ..Default::default() - }; - - // Next, extend the TxP with the openings of commitments known to our view server - // but not included in the transaction body, for instance spent notes or swap claim outputs. - for action in tx.actions() { - match action { - Action::Spend(spend) => { - let nullifier = spend.body.nullifier; - // An error here indicates we don't know the nullifier, so we omit it from the Perspective. - if let Some(spendable_note_record) = - storage.get_note_by_nullifier(&nullifier).await? - { - txp.spend_nullifiers - .insert(nullifier, spendable_note_record.note.clone()); - } - } - Action::Swap(swap) => { - let commitment = swap.body.payload.commitment; - if let Some(swap_record) = storage.get_swap_by_commitment(commitment.into()).await? - { - // Add swap output to perspective - if let Some(output_data) = swap_record.output_data { - let bsod = BatchSwapOutputData::try_from(output_data)?; - txp.batch_swap_output_data.push(bsod) - } - - // Add swap claim to perspective - let swap_position = Position::from(swap_record.position); - add_swap_claim_txn_to_perspective( - &storage, - &fvk, - &mut txp, - &commitment, - swap_position, - ) - .await?; - } - } - Action::SwapClaim(claim) => { - let nullifier = claim.body.nullifier; - - storage - .get_swap_by_nullifier(&nullifier) - .await? - .and_then(|swap_record| swap_record.source) - .into_iter() - .try_for_each(|source| { - let commitment_source: Result = - source.try_into(); - if let Some(id) = commitment_source.unwrap().id() { - txp.creation_transaction_ids_by_nullifier - .insert(nullifier, TransactionId(id)); - } - - Some(()) - }); - - let output_1_record = storage - .get_note(&claim.body.output_1_commitment) - .await? - .ok_or(anyhow!( - "Error generating TxP: SwapClaim output 1 commitment not found", - ))?; - - let output_2_record = storage - .get_note(&claim.body.output_2_commitment) - .await? - .ok_or(anyhow!( - "Error generating TxP: SwapClaim output 2 commitment not found" - ))?; - - txp.advice_notes - .insert(claim.body.output_1_commitment, output_1_record.note.clone()); - txp.advice_notes - .insert(claim.body.output_2_commitment, output_2_record.note.clone()); - } - _ => {} - } - } - - // Now, generate a stub TxV from our minimal TxP, and inspect it to see what data we should - // augment the minimal TxP with to provide additional context (e.g., filling in denoms for - // visible asset IDs). - let min_view = tx.view_from_perspective(&txp); - let mut address_views = BTreeMap::new(); - let mut asset_ids = BTreeSet::new(); - for action_view in min_view.action_views() { - use penumbra_dex::{swap::SwapView, swap_claim::SwapClaimView}; - use penumbra_transaction::view::action_view::{ - ActionView, DelegatorVoteView, OutputView, SpendView, - }; - match action_view { - ActionView::Spend(SpendView::Visible { note, .. }) => { - address_views.insert( - note.address().encode_to_vec(), - fvk.view_address(note.address()), - ); - asset_ids.insert(note.asset_id()); - } - ActionView::Output(OutputView::Visible { note, .. }) => { - address_views.insert( - note.address().encode_to_vec(), - fvk.view_address(note.address()), - ); - asset_ids.insert(note.asset_id()); - - // Also add an AddressView for the return address in the memo. - let memo = tx.decrypt_memo(&fvk)?; - address_views.insert( - memo.return_address().encode_to_vec(), - fvk.view_address(note.address()), - ); - } - ActionView::Swap(SwapView::Visible { swap_plaintext, .. }) => { - let address = swap_plaintext.claim_address.clone(); - let address_view = fvk.view_address(swap_plaintext.claim_address.clone()); - address_views.insert(address.encode_to_vec(), address_view); - asset_ids.insert(swap_plaintext.trading_pair.asset_1()); - asset_ids.insert(swap_plaintext.trading_pair.asset_2()); - } - ActionView::SwapClaim(SwapClaimView::Visible { - output_1, output_2, .. - }) => { - // Both will be sent to the same address so this only needs to be added once - address_views.insert( - output_1.address().encode_to_vec(), - fvk.view_address(output_1.address()), - ); - asset_ids.insert(output_1.asset_id()); - asset_ids.insert(output_2.asset_id()); - } - ActionView::DelegatorVote(DelegatorVoteView::Visible { note, .. }) => { - let address = note.address(); - let address_view = fvk.view_address(address.clone()); - address_views.insert(address.encode_to_vec(), address_view); - asset_ids.insert(note.asset_id()); - } - ActionView::ActionDutchAuctionSchedule(ActionDutchAuctionScheduleView { - action, - .. - }) => { - asset_ids.insert(action.description.output_id); - asset_ids.insert(action.description.input.asset_id); - } - ActionView::ActionDutchAuctionWithdraw(ActionDutchAuctionWithdrawView { - reserves, - .. - }) => reserves.iter().for_each(|reserve| { - asset_ids.insert(reserve.asset_id()); - }), - _ => {} - } - } - - // Now, extend the TxP with information helpful to understand the data it can view: - - let mut denoms = Vec::new(); - - for id in asset_ids { - if let Some(denom) = storage.get_asset(&id).await? { - denoms.push(denom.clone()); - } - } - - txp.denoms.extend(denoms.into_iter()); - - txp.address_views = address_views.into_values().collect(); - - // Finally, compute the full TxV from the full TxP: - let txv = tx.view_from_perspective(&txp); - - Ok((txp.into(), txv.into())) -} - -async fn add_swap_claim_txn_to_perspective( - storage: &IndexedDBStorage, - fvk: &FullViewingKey, - txp: &mut penumbra_transaction::TransactionPerspective, - commitment: &StateCommitment, - swap_position: Position, -) -> Result<(), WasmError> { - let derived_nullifier_from_swap = - Nullifier::derive(fvk.nullifier_key(), swap_position, commitment); - - let transaction_infos = storage.get_transaction_infos().await?; - - for transaction_info in transaction_infos { - transaction_info - .transaction - .and_then(|transaction| transaction.body) - .iter() - .for_each(|body| { - for action in body.actions.iter() { - let tranasction_id = action - .action - .as_ref() - .and_then(|action| match action { - penumbra_proto::core::transaction::v1::action::Action::SwapClaim( - swap_claim, - ) => swap_claim.body.as_ref(), - _ => None, - }) - .and_then(|body| body.nullifier.as_ref()) - .filter(|&nullifier| nullifier == &derived_nullifier_from_swap.to_proto()) - .and(transaction_info.id.as_ref()) - .and_then(|id| TransactionId::try_from(id.clone()).ok()); - - if let Some(transaction_id) = tranasction_id { - txp.nullification_transaction_ids_by_commitment - .insert(*commitment, transaction_id); - break; - } - } - }); - } - - Ok(()) -} diff --git a/packages/wasm/crate/src/utils.rs b/packages/wasm/crate/src/utils.rs deleted file mode 100644 index b1d7929d..00000000 --- a/packages/wasm/crate/src/utils.rs +++ /dev/null @@ -1,10 +0,0 @@ -pub fn set_panic_hook() { - // When the `console_error_panic_hook` feature is enabled, we can call the - // `set_panic_hook` function at least once during initialization, and then - // we will get better error messages if our code ever panics. - // - // For more details see - // https://github.com/rustwasm/console_error_panic_hook#readme - #[cfg(feature = "console_error_panic_hook")] - console_error_panic_hook::set_once(); -} diff --git a/packages/wasm/crate/src/view_server.rs b/packages/wasm/crate/src/view_server.rs deleted file mode 100644 index af524069..00000000 --- a/packages/wasm/crate/src/view_server.rs +++ /dev/null @@ -1,316 +0,0 @@ -use penumbra_asset::asset::{Id, Metadata}; -use penumbra_compact_block::{CompactBlock, StatePayload}; -use penumbra_keys::FullViewingKey; -use penumbra_proto::DomainType; -use penumbra_sct::Nullifier; -use penumbra_shielded_pool::note; -use penumbra_tct as tct; -use penumbra_tct::Witness::*; -use serde::{Deserialize, Serialize}; -use serde_wasm_bindgen::Serializer; -use std::collections::BTreeMap; -use tct::storage::{StoreCommitment, StoreHash, StoredPosition, Updates}; -use tct::{Forgotten, Tree}; -use wasm_bindgen::prelude::wasm_bindgen; -use wasm_bindgen::JsValue; - -use crate::error::WasmResult; -use crate::note_record::SpendableNoteRecord; -use crate::storage::IndexedDBStorage; -use crate::swap_record::SwapRecord; -use crate::utils; - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct StoredTree { - last_position: Option, - last_forgotten: Option, - hashes: Vec, - commitments: Vec, -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct ScanBlockResult { - height: u64, - sct_updates: Updates, - new_notes: Vec, - new_swaps: Vec, -} - -impl ScanBlockResult { - pub fn new( - height: u64, - sct_updates: Updates, - new_notes: Vec, - new_swaps: Vec, - ) -> ScanBlockResult { - Self { - height, - sct_updates, - new_notes, - new_swaps, - } - } -} - -#[wasm_bindgen] -pub struct ViewServer { - latest_height: u64, - epoch_duration: u64, - fvk: FullViewingKey, - notes: BTreeMap, - swaps: BTreeMap, - denoms: BTreeMap, - sct: Tree, - storage: IndexedDBStorage, - last_position: Option, - last_forgotten: Option, -} - -#[wasm_bindgen] -impl ViewServer { - /// Create new instances of `ViewServer` - /// Function opens a connection to indexedDb - /// Arguments: - /// full_viewing_key: `byte representation inner FullViewingKey` - /// epoch_duration: `u64` - /// stored_tree: `StoredTree` - /// idb_constants: `IndexedDbConstants` - /// Returns: `ViewServer` - #[wasm_bindgen] - pub async fn new( - full_viewing_key: &[u8], - epoch_duration: u64, - stored_tree: JsValue, - idb_constants: JsValue, - ) -> WasmResult { - utils::set_panic_hook(); - - let fvk: FullViewingKey = FullViewingKey::decode(full_viewing_key)?; - let stored_tree: StoredTree = serde_wasm_bindgen::from_value(stored_tree)?; - let tree = load_tree(stored_tree); - let constants = serde_wasm_bindgen::from_value(idb_constants)?; - let view_server = Self { - latest_height: u64::MAX, - fvk, - epoch_duration, - notes: Default::default(), - denoms: Default::default(), - sct: tree, - swaps: Default::default(), - storage: IndexedDBStorage::new(constants).await?, - last_position: None, - last_forgotten: None, - }; - Ok(view_server) - } - - /// Scans block for notes, swaps - /// Returns true if the block contains new notes, swaps or false if the block is empty for us - /// compact_block: `v1::CompactBlock` - /// Scan results are saved in-memory rather than returned - /// Use `flush_updates()` to get the scan results - /// Returns: `bool` - #[wasm_bindgen] - pub async fn scan_block(&mut self, compact_block: &[u8]) -> WasmResult { - utils::set_panic_hook(); - - let block = CompactBlock::decode(compact_block)?; - - let mut found_new_data: bool = false; - - for state_payload in block.state_payloads { - let clone_payload = state_payload.clone(); - - match state_payload { - StatePayload::Note { note: payload, .. } => { - match payload.trial_decrypt(&self.fvk) { - Some(note) => { - let note_position = self.sct.insert(Keep, payload.note_commitment)?; - - let source = clone_payload.source().clone(); - let nullifier = Nullifier::derive( - self.fvk.nullifier_key(), - note_position, - clone_payload.commitment(), - ); - let address_index = self - .fvk - .incoming() - .index_for_diversifier(note.diversifier()); - - let note_record = SpendableNoteRecord { - note_commitment: *clone_payload.commitment(), - height_spent: None, - height_created: block.height, - note: note.clone(), - address_index, - nullifier, - position: note_position, - source, - return_address: None, - }; - self.notes - .insert(payload.note_commitment, note_record.clone()); - found_new_data = true; - } - None => { - self.sct.insert(Forget, payload.note_commitment)?; - } - } - } - StatePayload::Swap { swap: payload, .. } => { - match payload.trial_decrypt(&self.fvk) { - Some(swap) => { - let swap_position = self.sct.insert(Keep, payload.commitment)?; - let batch_data = - block.swap_outputs.get(&swap.trading_pair).ok_or_else(|| { - anyhow::anyhow!("server gave invalid compact block") - })?; - - let source = clone_payload.source().clone(); - let nullifier = Nullifier::derive( - self.fvk.nullifier_key(), - swap_position, - clone_payload.commitment(), - ); - - let swap_record = SwapRecord { - swap_commitment: *clone_payload.commitment(), - swap: swap.clone(), - position: swap_position, - nullifier, - source, - output_data: *batch_data, - height_claimed: None, - }; - self.swaps.insert(payload.commitment, swap_record); - - let batch_data = - block.swap_outputs.get(&swap.trading_pair).ok_or_else(|| { - anyhow::anyhow!("server gave invalid compact block") - })?; - - let (output_1, output_2) = swap.output_notes(batch_data); - - self.storage.store_advice(output_1).await?; - self.storage.store_advice(output_2).await?; - found_new_data = true; - } - None => { - self.sct.insert(Forget, payload.commitment)?; - } - } - } - StatePayload::RolledUp { commitment, .. } => { - // This is a note we anticipated, so retain its auth path. - - let advice_result = self.storage.read_advice(commitment).await?; - - match advice_result { - None => { - self.sct.insert(Forget, commitment)?; - } - Some(note) => { - let position = self.sct.insert(Keep, commitment)?; - - let address_index_1 = self - .fvk - .incoming() - .index_for_diversifier(note.diversifier()); - - let nullifier = - Nullifier::derive(self.fvk.nullifier_key(), position, &commitment); - - let source = clone_payload.source().clone(); - - let spendable_note = SpendableNoteRecord { - note_commitment: note.commit(), - height_spent: None, - height_created: block.height, - note: note.clone(), - address_index: address_index_1, - nullifier, - position, - source, - return_address: None, - }; - self.notes - .insert(spendable_note.note_commitment, spendable_note.clone()); - found_new_data = true; - } - } - } - } - } - - self.sct.end_block()?; - if block.epoch_root.is_some() { - self.sct.end_epoch()?; - } - - self.latest_height = block.height; - - Ok(found_new_data) - } - - /// Get new notes, swaps, SCT state updates - /// Function also clears state - /// Returns: `ScanBlockResult` - #[wasm_bindgen] - pub fn flush_updates(&mut self) -> WasmResult { - utils::set_panic_hook(); - - let sct_updates: Updates = self - .sct - .updates( - self.last_position.unwrap_or_default(), - self.last_forgotten.unwrap_or_default(), - ) - .collect::(); - - let updates = ScanBlockResult { - height: self.latest_height, - sct_updates: sct_updates.clone(), - new_notes: self.notes.clone().into_values().collect(), - new_swaps: self.swaps.clone().into_values().collect(), - }; - - self.notes = Default::default(); - self.swaps = Default::default(); - - self.last_position = sct_updates.set_position; - self.last_forgotten = sct_updates.set_forgotten; - - let serializer = Serializer::new().serialize_large_number_types_as_bigints(true); - let result = updates.serialize(&serializer)?; - Ok(result) - } - - /// SCT root can be compared with the root obtained by GRPC and verify that there is no divergence - /// Returns: `Uint8Array representing a Root` - #[wasm_bindgen] - pub fn get_sct_root(&mut self) -> WasmResult> { - utils::set_panic_hook(); - - let root = self.sct.root(); - Ok(root.encode_to_vec()) - } -} - -pub fn load_tree(stored_tree: StoredTree) -> Tree { - let stored_position: StoredPosition = stored_tree.last_position.unwrap_or_default(); - let mut add_commitments = Tree::load( - stored_position, - stored_tree.last_forgotten.unwrap_or_default(), - ); - - for store_commitment in &stored_tree.commitments { - add_commitments.insert(store_commitment.position, store_commitment.commitment) - } - let mut add_hashes = add_commitments.load_hashes(); - - for stored_hash in &stored_tree.hashes { - add_hashes.insert(stored_hash.position, stored_hash.height, stored_hash.hash); - } - add_hashes.finish() -} diff --git a/packages/wasm/crate/tests/build.rs b/packages/wasm/crate/tests/build.rs deleted file mode 100644 index 93a8fa89..00000000 --- a/packages/wasm/crate/tests/build.rs +++ /dev/null @@ -1,571 +0,0 @@ -extern crate penumbra_wasm; - -#[cfg(test)] -mod tests { - use indexed_db_futures::prelude::{ - IdbDatabase, IdbObjectStore, IdbQuerySource, IdbTransaction, IdbTransactionMode, - }; - use penumbra_asset::STAKING_TOKEN_ASSET_ID; - use penumbra_dex::DexParameters; - use penumbra_keys::keys::SpendKey; - use penumbra_keys::FullViewingKey; - use penumbra_proto::core::app::v1::AppParameters; - use penumbra_proto::core::component::fee::v1::GasPrices; - use penumbra_proto::core::transaction::v1; - use penumbra_proto::view::v1::transaction_planner_request::Output; - use penumbra_proto::view::v1::TransactionPlannerRequest; - use penumbra_proto::{ - core::{ - asset::v1::Value, component::shielded_pool::v1::FmdParameters, keys::v1::Address, - transaction::v1::MemoPlaintext, - }, - view::v1::SpendableNoteRecord, - DomainType, - }; - use penumbra_sct::params::SctParameters; - use penumbra_tct::{structure::Hash, Forgotten}; - use penumbra_transaction::{ - plan::{ActionPlan, TransactionPlan}, - Action, Transaction, - }; - use prost::Message; - use serde::{Deserialize, Serialize}; - use std::str::FromStr; - use wasm_bindgen::JsValue; - use wasm_bindgen_test::*; - - use penumbra_wasm::planner::plan_transaction; - use penumbra_wasm::{ - build::build_action, - keys::load_proving_key, - storage::IndexedDBStorage, - tx::{authorize, build, build_parallel, witness}, - }; - - wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); - #[wasm_bindgen_test] - async fn mock_build_serial_and_parallel() { - // Limit the use of Penumbra Rust libraries since we're mocking JS calls - // that are based on constructing objects according to protobuf definitions. - - // Load the proving key parameters as byte arrays. - let spend_key: &[u8] = include_bytes!("../../../keys/keys/spend_pk.bin"); - let output_key: &[u8] = include_bytes!("../../../keys/keys/output_pk.bin"); - let delegator_vote_key: &[u8] = include_bytes!("../../../keys/keys/delegator_vote_pk.bin"); - let swap_key: &[u8] = include_bytes!("../../../keys/keys/swap_pk.bin"); - let swapclaim_key: &[u8] = include_bytes!("../../../keys/keys/swapclaim_pk.bin"); - let convert_key: &[u8] = include_bytes!("../../../keys/keys/convert_pk.bin"); - - // Dynamically load the proving keys at runtime for each key type. - load_proving_key(spend_key, "spend").expect("can load spend key"); - load_proving_key(output_key, "output").expect("can load output key"); - load_proving_key(delegator_vote_key, "delegatorVote").expect("can load delegator vote key"); - load_proving_key(swap_key, "swap").expect("can load swap key"); - load_proving_key(swapclaim_key, "swapClaim").expect("can load swapclaim key"); - load_proving_key(convert_key, "undelegateClaim").expect("can load convert key"); - - // Define database parameters. - #[derive(Clone, Debug, Serialize, Deserialize)] - pub struct IndexedDbConstants { - name: String, - version: u32, - tables: Tables, - } - - #[derive(Clone, Debug, Serialize, Deserialize)] - pub struct Tables { - assets: String, - advice_notes: String, - spendable_notes: String, - swaps: String, - fmd_parameters: String, - app_parameters: String, - gas_prices: String, - epochs: String, - transactions: String, - full_sync_height: String, - auctions: String, - auction_outstanding_reserves: String, - } - - // Define `IndexDB` table parameters and constants. - let tables: Tables = Tables { - assets: "ASSETS".to_string(), - advice_notes: "ADVICE_NOTES".to_string(), - spendable_notes: "SPENDABLE_NOTES".to_string(), - swaps: "SWAPS".to_string(), - fmd_parameters: "FMD_PARAMETERS".to_string(), - app_parameters: "APP_PARAMETERS".to_string(), - gas_prices: "GAS_PRICES".to_string(), - epochs: "EPOCHS".to_string(), - transactions: "TRANSACTIONS".to_string(), - full_sync_height: "FULL_SYNC_HEIGHT".to_string(), - auctions: "AUCTIONS".to_string(), - auction_outstanding_reserves: "AUCTION_OUTSTANDING_RESERVES".to_string(), - }; - - let constants: IndexedDbConstants = IndexedDbConstants { - name: "penumbra-db-wasm-test".to_string(), - version: 1, - tables, - }; - - // Sample chain and fmd parameters. - let chain_id = "penumbra-testnet-iapetus".to_string(); - let sct_params = SctParameters { - epoch_duration: 5u64, - }; - let dex_params = DexParameters { - fixed_candidates: Vec::new(), - is_enabled: true, - max_hops: 5u32, - max_positions_per_pair: 0, - }; - - let app_params = AppParameters { - dex_params: Some(dex_params.to_proto()), - chain_id, - sct_params: Some(sct_params.to_proto()), - community_pool_params: None, - governance_params: None, - ibc_params: None, - stake_params: None, - fee_params: None, - distributions_params: None, - funding_params: None, - shielded_pool_params: None, - auction_params: None, - }; - - let fmd_params = FmdParameters { - precision_bits: 0u32, - as_of_block_height: 1u64, - }; - let gas_prices = GasPrices { - asset_id: Some((*STAKING_TOKEN_ASSET_ID).into()), - block_space_price: 0, - compact_block_space_price: 0, - verification_price: 0, - execution_price: 0, - }; - - // Serialize the parameters into `JsValue`. - let js_app_params_value: JsValue = serde_wasm_bindgen::to_value(&app_params).unwrap(); - let js_fmd_params_value: JsValue = serde_wasm_bindgen::to_value(&fmd_params).unwrap(); - let js_constants_params_value: JsValue = serde_wasm_bindgen::to_value(&constants).unwrap(); - let js_gas_prices_value: JsValue = serde_wasm_bindgen::to_value(&gas_prices).unwrap(); - - // Create spendable UTXO note in JSON format. - let spendable_note_json = r#" - { - "note_commitment": { - "inner": "MY7PmcrH4fhjFOoMIKEdF+x9EUhZ9CS/CIfVco7Y5wU=" - }, - "note": { - "value": { - "amount": { - "lo": "1000000", - "hi": "0" - }, - "asset_id": { - "inner": "nwPDkQq3OvLnBwGTD+nmv1Ifb2GEmFCgNHrU++9BsRE=", - "alt_bech32m": "", - "alt_base_denom": "" - } - }, - "rseed": "p2w4O1ognDJtKVqhHK2qsUbV+1AEM/gn58uWYQ5v3sM=", - "address": { - "inner": "F6T1P51M1QOu8NGhKTMdJTy72TDhB2h00uvlIUcXVdovybq4ZcOwROB+1VE/ar4thEDNPanAcaYOrL+FugN8e19pvr93ZqmTjUdOLic+w+U=", - "alt_bech32m": "" - } - }, - "address_index": { - "account": "0", - "randomizer": "AAAAAAAAAAAAAAAA" - }, - "nullifier": { - "inner": "8TvyFVKk16PHcOEAgl0QV4/92xdVpLdXI+zP87lBrQ8=" - }, - "height_created": "250305", - "height_spent": "0", - "position": "3204061134848", - "source": { - "transaction": { - "id": "oJ9Bo9v22srtUmKdTAMVwPOuGumWE2cAuBbZHci8B1I=" - } - } - } - "#; - - // Convert note to `SpendableNoteRecord`. - let spendable_note: SpendableNoteRecord = - serde_json::from_str(spendable_note_json).unwrap(); - - // Define neccessary parameters to mock `TransactionPlannerRequest` in JSON format. - let address_json = r#" - { - "alt_bech32m": "penumbra1dugkjttfezh4gfkqs77377gnjlvmkkehusx6953udxeescc0qpgk6gqc0jmrsjq8xphzrg938843p0e63z09vt8lzzmef0q330e5njuwh4290n8pemcmx70sasym0lcjkstgzc", - "inner": "" - } - "#; - let value_json = r#" - { - "amount": { - "lo": "1", - "hi": "0" - }, - "asset_id": { - "inner": "nwPDkQq3OvLnBwGTD+nmv1Ifb2GEmFCgNHrU++9BsRE=", - "alt_bech32m": "", - "alt_base_denom": "" - } - } - "#; - - // Convert fields to JsValue. - let address: Address = serde_json::from_str(address_json).unwrap(); - let value: Value = serde_json::from_str(value_json).unwrap(); - - // Add memo to plan. - let memo: MemoPlaintext = MemoPlaintext { - return_address: Some(address.clone()), - text: "sample memo".to_string(), - }; - - // Retrieve private database handle with public getters. - let storage = IndexedDBStorage::new( - serde_wasm_bindgen::from_value(js_constants_params_value.clone()).unwrap(), - ) - .await - .unwrap(); - // let storage_ref: &IndexedDBStorage = unsafe { &*storage }; - let database: *const IdbDatabase = storage.get_database(); - let database_ref: &IdbDatabase = unsafe { &*database }; - - // Define SCT-related structs. - #[derive(Clone, Debug, Serialize, Deserialize)] - pub struct Position { - epoch: u64, - block: u64, - commitment: u64, - } - - #[derive(Clone, Debug, Serialize, Deserialize)] - #[allow(non_snake_case)] - pub struct StoredPosition { - Position: Position, - } - - #[derive(Clone, Debug, Serialize, Deserialize)] - pub struct StoreHash { - position: Position, - height: u64, - hash: Hash, - essential: bool, - } - - #[derive(Clone, Debug, Serialize, Deserialize)] - pub struct StoreCommitment { - commitment: Commitment, - position: Position, - } - - #[derive(Clone, Debug, Serialize, Deserialize)] - pub struct Commitment { - inner: String, - } - - #[derive(Clone, Debug, Serialize, Deserialize)] - pub struct StateCommitmentTree { - last_position: Position, - last_forgotten: u64, - hashes: StoreHash, - commitments: StoreCommitment, - } - - #[derive(Clone, Debug, Serialize, Deserialize)] - pub struct SctUpdates { - store_commitments: StoreCommitment, - set_position: StoredPosition, - set_forgotten: u64, - } - - #[derive(Clone, Debug, Serialize, Deserialize)] - pub struct StoredTree { - last_position: Option, - last_forgotten: Option, - hashes: Vec, - commitments: Vec, - } - - // Define a sample SCT update. - #[allow(non_snake_case)] - let sctUpdates = SctUpdates { - store_commitments: StoreCommitment { - commitment: Commitment { - inner: "MY7PmcrH4fhjFOoMIKEdF+x9EUhZ9CS/CIfVco7Y5wU=".to_string(), - }, - position: Position { - epoch: 746u64, - block: 237u64, - commitment: 0u64, - }, - }, - set_position: StoredPosition { - Position: Position { - epoch: 750u64, - block: 710u64, - commitment: 0u64, - }, - }, - set_forgotten: 3u64, - }; - - // Populate database with records (CRUD). - let tx_note: IdbTransaction = database_ref - .transaction_on_one_with_mode("SPENDABLE_NOTES", IdbTransactionMode::Readwrite) - .unwrap(); - let tx_tree_commitments: IdbTransaction = database_ref - .transaction_on_one_with_mode("TREE_COMMITMENTS", IdbTransactionMode::Readwrite) - .unwrap(); - let tx_tree_last_position: IdbTransaction = database_ref - .transaction_on_one_with_mode("TREE_LAST_POSITION", IdbTransactionMode::Readwrite) - .unwrap(); - let tx_tree_last_forgotten: IdbTransaction = database_ref - .transaction_on_one_with_mode("TREE_LAST_FORGOTTEN", IdbTransactionMode::Readwrite) - .unwrap(); - let tx_fmd: IdbTransaction = database_ref - .transaction_on_one_with_mode("FMD_PARAMETERS", IdbTransactionMode::Readwrite) - .unwrap(); - let tx_app: IdbTransaction = database_ref - .transaction_on_one_with_mode("APP_PARAMETERS", IdbTransactionMode::Readwrite) - .unwrap(); - let tx_gas: IdbTransaction = database_ref - .transaction_on_one_with_mode("GAS_PRICES", IdbTransactionMode::Readwrite) - .unwrap(); - - let store_note: IdbObjectStore = tx_note.object_store("SPENDABLE_NOTES").unwrap(); - let store_tree_commitments: IdbObjectStore = tx_tree_commitments - .object_store("TREE_COMMITMENTS") - .unwrap(); - let store_tree_last_position: IdbObjectStore = tx_tree_last_position - .object_store("TREE_LAST_POSITION") - .unwrap(); - let store_tree_last_forgotten: IdbObjectStore = tx_tree_last_forgotten - .object_store("TREE_LAST_FORGOTTEN") - .unwrap(); - let store_fmd: IdbObjectStore = tx_fmd.object_store("FMD_PARAMETERS").unwrap(); - let store_app: IdbObjectStore = tx_app.object_store("APP_PARAMETERS").unwrap(); - let store_gas: IdbObjectStore = tx_gas.object_store("GAS_PRICES").unwrap(); - - let spendable_note_json = serde_wasm_bindgen::to_value(&spendable_note).unwrap(); - let tree_commitments_json = - serde_wasm_bindgen::to_value(&sctUpdates.store_commitments).unwrap(); - let tree_position_json_value = - serde_wasm_bindgen::to_value(&sctUpdates.set_position).unwrap(); - let tree_position_json_key = serde_wasm_bindgen::to_value(&"last_position").unwrap(); - let tree_last_forgotten_json_value = - serde_wasm_bindgen::to_value(&sctUpdates.set_forgotten).unwrap(); - let tree_last_forgotten_json_key: JsValue = - serde_wasm_bindgen::to_value(&"last_forgotten").unwrap(); - let fmd_json_key: JsValue = serde_wasm_bindgen::to_value(&"params").unwrap(); - let app_json_key: JsValue = serde_wasm_bindgen::to_value(&"params").unwrap(); - let gas_json_key: JsValue = serde_wasm_bindgen::to_value(&"gas_prices").unwrap(); - - store_note.put_val(&spendable_note_json).unwrap(); - store_tree_commitments - .put_val(&tree_commitments_json) - .unwrap(); - store_tree_last_position - .put_key_val(&tree_position_json_key, &tree_position_json_value) - .unwrap(); - store_tree_last_forgotten - .put_key_val( - &tree_last_forgotten_json_key, - &tree_last_forgotten_json_value, - ) - .unwrap(); - store_fmd - .put_key_val(&fmd_json_key, &js_fmd_params_value) - .unwrap(); - store_app - .put_key_val(&app_json_key, &js_app_params_value) - .unwrap(); - store_gas - .put_key_val(&gas_json_key, &js_gas_prices_value) - .unwrap(); - - // -------------- 1. Query transaction plan performing a spend -------------- - - #[allow(deprecated)] // Remove if/when `epoch_index` is removed - let planner_request = TransactionPlannerRequest { - epoch: None, - epoch_index: 0, - expiry_height: 0, - memo: Some(memo), - source: None, - outputs: vec![Output { - address: Some(address), - value: Some(value), - }], - swaps: vec![], - swap_claims: vec![], - delegations: vec![], - undelegations: vec![], - undelegation_claims: vec![], - ibc_relay_actions: vec![], - ics20_withdrawals: vec![], - position_opens: vec![], - position_closes: vec![], - position_withdraws: vec![], - fee_mode: None, - dutch_auction_schedule_actions: vec![], - dutch_auction_end_actions: vec![], - dutch_auction_withdraw_actions: vec![], - }; - - // Viewing key to reveal asset balances and transactions. - let full_viewing_key = FullViewingKey::from_str("penumbrafullviewingkey1mnm04x7yx5tyznswlp0sxs8nsxtgxr9p98dp0msuek8fzxuknuzawjpct8zdevcvm3tsph0wvsuw33x2q42e7sf29q904hwerma8xzgrxsgq2").unwrap(); - - let plan_js_value: JsValue = plan_transaction( - js_constants_params_value, - &planner_request.encode_to_vec(), - full_viewing_key.encode_to_vec().as_slice(), - ) - .await - .unwrap(); - let plan_proto: v1::TransactionPlan = - serde_wasm_bindgen::from_value(plan_js_value.clone()).unwrap(); - let plan = TransactionPlan::try_from(plan_proto).unwrap(); - let plan_slice = &*plan.encode_to_vec(); - - // -------------- 2. Generate authorization data from spend key and transaction plan -------------- - - let spend_key = SpendKey::from_str( - "penumbraspendkey1qul0huewkcmemljd5m3vz3awqt7442tjg2dudahvzu6eyj9qf0eszrnguh", - ) - .unwrap(); - - let authorization_data = - authorize(spend_key.encode_to_vec().as_slice(), plan_slice).unwrap(); - - // -------------- 3. Generate witness -------------- - - // Retrieve SCT from storage. - let tx_last_position: IdbTransaction<'_> = database_ref - .transaction_on_one("TREE_LAST_POSITION") - .unwrap(); - let store_last_position = tx_last_position.object_store("TREE_LAST_POSITION").unwrap(); - let value_last_position: Option = store_last_position - .get_owned("last_position") - .unwrap() - .await - .unwrap(); - - let tx_last_forgotten = database_ref - .transaction_on_one("TREE_LAST_FORGOTTEN") - .unwrap(); - let store_last_forgotten = tx_last_forgotten - .object_store("TREE_LAST_FORGOTTEN") - .unwrap(); - let value_last_forgotten: Option = store_last_forgotten - .get_owned("last_forgotten") - .unwrap() - .await - .unwrap(); - - let tx_commitments = database_ref.transaction_on_one("TREE_COMMITMENTS").unwrap(); - let store_commitments = tx_commitments.object_store("TREE_COMMITMENTS").unwrap(); - let value_commitments = store_commitments - .get_owned("MY7PmcrH4fhjFOoMIKEdF+x9EUhZ9CS/CIfVco7Y5wU=") - .unwrap() - .await - .unwrap(); - - // Convert retrieved values to `JsValue`. - let last_position_json: StoredPosition = - serde_wasm_bindgen::from_value(value_last_position.unwrap()).unwrap(); - let last_forgotten_json: Forgotten = - serde_wasm_bindgen::from_value(value_last_forgotten.unwrap()).unwrap(); - let commitments_jsvalue: StoreCommitment = - serde_wasm_bindgen::from_value(JsValue::from(value_commitments.clone())).unwrap(); - - // Reconstruct SCT struct. - let vec_store_commitments: Vec = vec![commitments_jsvalue.clone()]; - - let sct = StoredTree { - last_position: Some(last_position_json.clone()), - last_forgotten: Some(last_forgotten_json), - hashes: [].to_vec(), - commitments: vec_store_commitments, - }; - - // Convert SCT to `JsValue`. - let sct_json = serde_wasm_bindgen::to_value(&sct).unwrap(); - - // Generate witness data from SCT and specific transaction plan. - let witness_data = witness(plan_slice, sct_json).unwrap(); - - // -------------- 4. Build the (1) Serial Transaction and (2) Parallel Transaction -------------- - - let mut actions: Vec = Vec::new(); - - for i in plan.actions.clone() { - if let ActionPlan::Spend(ref _spend_plan) = i { - let action_vec = build_action( - plan_slice, - i.encode_to_vec().as_slice(), - full_viewing_key.encode_to_vec().as_slice(), - &witness_data, - ) - .unwrap(); - let action = Action::decode(&*action_vec).unwrap(); - actions.push(action); - } - if let ActionPlan::Output(ref _output_plan) = i { - let action_vec = build_action( - plan_slice, - i.encode_to_vec().as_slice(), - full_viewing_key.encode_to_vec().as_slice(), - &witness_data, - ) - .unwrap(); - let action = Action::decode(&*action_vec).unwrap(); - actions.push(action); - } - } - - // Deserialize actions. - let action_deserialized: JsValue = serde_wasm_bindgen::to_value(&actions).unwrap(); - - // Execute parallel spend transaction and generate proof. - let parallel_transaction = build_parallel( - action_deserialized, - plan_slice, - &witness_data, - &authorization_data, - ) - .unwrap(); - console_log!("Parallel transaction is: {:?}", parallel_transaction); - - // Execute serial spend transaction and generate proof. - let serial_transaction = build( - full_viewing_key.encode_to_vec().as_slice(), - plan_slice, - &witness_data, - &authorization_data, - ) - .unwrap(); - console_log!("Serial transaction is: {:?}", serial_transaction); - - // Deserialize transactions and stringify actions in the transaction body into JSON - let serial_result = Transaction::decode(&*serial_transaction).unwrap(); - let parallel_result = Transaction::decode(&*parallel_transaction).unwrap(); - let serial_json = serde_json::to_string(&serial_result.transaction_body.actions).unwrap(); - let parallel_json = - serde_json::to_string(¶llel_result.transaction_body.actions).unwrap(); - - // Perform assertion check - assert_eq!(serial_json, parallel_json); - } -} diff --git a/packages/wasm/crate/tests/deserialize.rs b/packages/wasm/crate/tests/deserialize.rs deleted file mode 100644 index 995f2687..00000000 --- a/packages/wasm/crate/tests/deserialize.rs +++ /dev/null @@ -1,35 +0,0 @@ -use penumbra_proto::core::component::ibc::v1::Ics20Withdrawal as PbIcs20Withdrawal; -use penumbra_shielded_pool::Ics20Withdrawal; - -#[test] -fn height_properly_serializes_from_json() { - let data = r#" - { - "amount": { - "lo": "12000000" - }, - "denom": { - "denom": "upenumbra" - }, - "destinationChainAddress": "xyz", - "returnAddress": { - "inner": "by+DwROtdzWZu+W+gQ+e7pJ328aBf4Lng1dtnnkH971ebSC4O1+fQE+QmMNQ0iEg1/ARaF6yop4BurwW0Z1B7v0/o3AYchf6IEMYBxGyN18=" - }, - "timeoutHeight": { - "revisionNumber": "5", - "revisionHeight": "3928271" - }, - "timeoutTime": "1701471437169", - "sourceChannel": "channel-0" - } - "#; - - let withdrawal_proto: PbIcs20Withdrawal = serde_json::from_str(data).unwrap(); - let height = withdrawal_proto.clone().timeout_height.unwrap(); - assert_eq!(height.revision_number, 5u64); - assert_eq!(height.revision_height, 3928271u64); - - let domain_type: Ics20Withdrawal = withdrawal_proto.try_into().unwrap(); - assert_eq!(domain_type.timeout_height.revision_number, 5u64); - assert_eq!(domain_type.timeout_height.revision_height, 3928271u64); -} diff --git a/packages/wasm/crate/tests/keys.rs b/packages/wasm/crate/tests/keys.rs deleted file mode 100644 index 5df81218..00000000 --- a/packages/wasm/crate/tests/keys.rs +++ /dev/null @@ -1,34 +0,0 @@ -extern crate core; - -use penumbra_keys::FullViewingKey; -use penumbra_proto::core::keys::v1::WalletId; -use penumbra_proto::{DomainType, Message}; -use penumbra_wasm::keys::get_wallet_id; -use std::str::FromStr; - -#[test] -fn successfully_get_wallet_id() { - let fvk = FullViewingKey::from_str("penumbrafullviewingkey1sjeaceqzgaeye2ksnz8q73mp6rpx2ykdtzs8wurrnhwdn8vqwuxhxtjdndrjc74udjh0uch0tatnrd93q50wp9pfk86h3lgpew8lsqsz2a6la").unwrap(); - let wallet_id = WalletId::decode( - get_wallet_id(fvk.encode_to_vec().as_slice()) - .unwrap() - .as_slice(), - ) - .unwrap(); - let expected_bech32_str = - "penumbrawalletid15r7q7qsf3hhsgj0g530n7ng9acdacmmx9ajknjz38dyt90u9gcgsmjre75".to_string(); - let walet_id_str = penumbra_keys::keys::WalletId::try_from(wallet_id) - .unwrap() - .to_string(); - - assert_eq!(expected_bech32_str, walet_id_str); -} - -#[test] -#[ignore] -// revise this test since we cannot call wasm-bindgen imported functions on non-wasm targets -fn raises_if_fvk_invalid() { - let fvk = FullViewingKey::from_str("penumbrafullviewingkey1sjeaceqzgaeye2ksnz8q73mp6rpx2ykdtzs8wurrnhwdn8vqwuxhxtjdndrjc74udjh0uch0tatnrd93q50wp9pfk86h3lgpew8lsqsz2a6la").unwrap(); - let err = get_wallet_id(fvk.encode_to_vec().as_slice()).unwrap_err(); - assert_eq!("invalid length", err.to_string()); -} diff --git a/packages/wasm/eslint.config.mjs b/packages/wasm/eslint.config.mjs deleted file mode 100644 index a53ed8e5..00000000 --- a/packages/wasm/eslint.config.mjs +++ /dev/null @@ -1,13 +0,0 @@ -import { penumbraEslintConfig } from '@penumbra-zone/eslint-config'; -import { config, parser } from 'typescript-eslint'; - -export default config({ - ...penumbraEslintConfig, - languageOptions: { - parser, - parserOptions: { - project: true, - tsconfigRootDir: import.meta.dirname, - }, - }, -}); diff --git a/packages/wasm/package.json b/packages/wasm/package.json deleted file mode 100644 index 0a7b6310..00000000 --- a/packages/wasm/package.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "name": "@penumbra-zone/wasm", - "version": "7.1.0", - "private": true, - "license": "(MIT OR Apache-2.0)", - "type": "module", - "scripts": { - "build": "tsc --build", - "clean": "rm -rfv dist wasm package penumbra-zone-wasm-*.tgz", - "clean:rust": "cargo clean --manifest-path ./crate/Cargo.toml", - "compile": "cd crate && wasm-pack build --no-pack --target bundler --out-name index --out-dir ../wasm && touch ../wasm/.npmignore", - "dev": "cargo watch -C ./crate --postpone -- pnpm turbo run compile", - "format:rust": "cd crate && cargo fmt --all", - "lint": "eslint src", - "lint:rust": "cd crate && cargo fmt --all -- --check && cargo clippy -- -D warnings && cargo clippy --tests -- -D warnings", - "prebuild": "tsc --build --clean", - "prepack": "$npm_execpath run build", - "test": "vitest run", - "test:rust": "cd crate && wasm-pack test --headless --firefox -- --test build --target wasm32-unknown-unknown --release --features 'mock-database'" - }, - "files": [ - "wasm", - "dist" - ], - "exports": { - "./*": "./src/*.ts" - }, - "publishConfig": { - "exports": { - "./*": { - "types": "./dist/*.d.ts", - "default": "./dist/*.js" - } - } - }, - "dependencies": { - "@penumbra-zone/protobuf": "workspace:*", - "@penumbra-zone/types": "workspace:*", - "zod": "^3.23.8" - }, - "devDependencies": { - "@buf/penumbra-zone_penumbra.bufbuild_es": "1.9.0-20240528180215-8fe1c79485f8.1", - "@bufbuild/protobuf": "^1.10.0", - "@penumbra-zone/bech32m": "workspace:*", - "fake-indexeddb": "^6.0.0" - }, - "optionalDependencies": { - "@penumbra-zone/keys": "workspace:*" - }, - "peerDependencies": { - "@buf/penumbra-zone_penumbra.bufbuild_es": "1.9.0-20240528180215-8fe1c79485f8.1", - "@bufbuild/protobuf": "^1.10.0" - } -} diff --git a/packages/wasm/src/address.test.ts b/packages/wasm/src/address.test.ts deleted file mode 100644 index 0399e5c5..00000000 --- a/packages/wasm/src/address.test.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { describe, expect, it } from 'vitest'; -import { generateSpendKey, getAddressByIndex, getFullViewingKey } from './keys'; -import { getAddressIndexByAddress, isControlledAddress } from './address'; -import { addressFromBech32m } from '@penumbra-zone/bech32m/penumbra'; -import { Address } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb'; - -describe('address', () => { - const seedPhrase = - 'benefit cherry cannon tooth exhibit law avocado spare tooth that amount pumpkin scene foil tape mobile shine apology add crouch situate sun business explain'; - const spendKey = generateSpendKey(seedPhrase); - const fullViewingKey = getFullViewingKey(spendKey); - - describe('getAddressIndexByAddress()', () => { - it('works with controlled addr', () => { - const address = getAddressByIndex(fullViewingKey, 1); - - expect(getAddressIndexByAddress(fullViewingKey, address)!.account).toBe(1); - }); - - it('returns undefined with uncontrolled addr', () => { - const address = new Address( - addressFromBech32m( - 'penumbra1ftmn2a3hf8pxe0e48es8u9rqhny4xggq9wn2caxcjnfwfhwr5s0t3y6nzs9gx3ty5czd0sd9ssfgjt2pcxrq93yvgk2gu3ynmayuwgddkxthce8l445v8x6v07y2sjd8djcr6v', - ), - ); - - expect(getAddressIndexByAddress(fullViewingKey, address)).toBeUndefined(); - }); - }); - - describe('isControlledAddress()', () => { - it('returns true if the address is controlled', () => { - const address = getAddressByIndex(fullViewingKey, 1); - - expect(isControlledAddress(fullViewingKey, address)).toBe(true); - }); - - it('returns false if the address is not controlled', () => { - const spendKey = generateSpendKey(seedPhrase); - const fullViewingKey = getFullViewingKey(spendKey); - const address = new Address( - addressFromBech32m( - 'penumbra1ftmn2a3hf8pxe0e48es8u9rqhny4xggq9wn2caxcjnfwfhwr5s0t3y6nzs9gx3ty5czd0sd9ssfgjt2pcxrq93yvgk2gu3ynmayuwgddkxthce8l445v8x6v07y2sjd8djcr6v', - ), - ); - - expect(isControlledAddress(fullViewingKey, address)).toBe(false); - }); - - it('returns false if the address is undefined', () => { - expect(isControlledAddress(fullViewingKey, undefined)).toBe(false); - }); - }); -}); diff --git a/packages/wasm/src/address.ts b/packages/wasm/src/address.ts deleted file mode 100644 index dbeffc76..00000000 --- a/packages/wasm/src/address.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { get_index_by_address } from '../wasm'; -import { - Address, - AddressIndex, - FullViewingKey, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb'; -import { JsonValue } from '@bufbuild/protobuf'; - -export const getAddressIndexByAddress = ( - fullViewingKey: FullViewingKey, - address: Address, -): AddressIndex | undefined => { - const res = get_index_by_address(fullViewingKey.toBinary(), address.toBinary()) as JsonValue; - return res ? AddressIndex.fromJson(res) : undefined; -}; - -// Only an address controlled by the FVK can view its index -export const isControlledAddress = (fullViewingKey: FullViewingKey, address?: Address): boolean => { - if (!address) return false; - - const viewableIndex = get_index_by_address( - fullViewingKey.toBinary(), - address.toBinary(), - ) as JsonValue; - return Boolean(viewableIndex); -}; diff --git a/packages/wasm/src/asset.test.ts b/packages/wasm/src/asset.test.ts deleted file mode 100644 index e45088e6..00000000 --- a/packages/wasm/src/asset.test.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { describe, test, expect } from 'vitest'; -import { assetIdFromBaseDenom } from './asset'; -import { AssetId } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; -import { randomBytes } from 'crypto'; -import { assetIdFromBech32m } from '@penumbra-zone/bech32m/passet'; - -// not human legible or restricted to any charset -const randomString = (byteLength = 32) => - randomBytes(1 + Math.random() * (byteLength - 1)).toString(); - -describe('assetIdFromBaseDenom', () => { - test('should return the correct asset id for a known asset id', () => { - const upenumbraFromBech32m = new AssetId( - assetIdFromBech32m('passet1984fctenw8m2fpl8a9wzguzp7j34d7vravryuhft808nyt9fdggqxmanqm'), - ); - - const upenumbraFromBaseDenom = assetIdFromBaseDenom('upenumbra'); - - expect(AssetId.equals(upenumbraFromBech32m, upenumbraFromBaseDenom)).toBeTruthy(); - }); - - test('should return a 32-byte asset id for any string', () => { - const randomIds = Array.from(Array(10), randomString).map(denom => assetIdFromBaseDenom(denom)); - - expect( - randomIds.every( - id => id instanceof AssetId && id.inner instanceof Uint8Array && id.inner.length === 32, - ), - ).toBeTruthy(); - }); - - test('should return same asset id for same string', () => { - const sameAltBaseDenom = randomString(); - const a1 = assetIdFromBaseDenom(sameAltBaseDenom); - const a2 = assetIdFromBaseDenom(sameAltBaseDenom); - - expect(a1.inner).toEqual(a2.inner); - }); - - test( - 'should return different asset id for different strings', - { retry: 2 }, // there is a chance that this test could fail randomly :) - () => { - const someAltBaseDenom = randomString(); - const differentAltBaseDenom = randomString(); - const a = assetIdFromBaseDenom(someAltBaseDenom); - const b = assetIdFromBaseDenom(differentAltBaseDenom); - - expect(a.inner).not.toEqual(b.inner); - }, - ); -}); diff --git a/packages/wasm/src/asset.ts b/packages/wasm/src/asset.ts deleted file mode 100644 index 20218364..00000000 --- a/packages/wasm/src/asset.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { AssetId } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; -import { get_asset_id_inner } from '../wasm'; - -/** - * Converts a base denom name string to an `AssetId` with inner binary field - * @param altBaseDenom an asset's base denomination name - * @returns the appropriate `AssetId` with binary inner field - */ -export const assetIdFromBaseDenom = (altBaseDenom: string) => { - const inner = get_asset_id_inner(new AssetId({ altBaseDenom }).toBinary()); - return new AssetId({ inner }); -}; diff --git a/packages/wasm/src/auction.ts b/packages/wasm/src/auction.ts deleted file mode 100644 index e6354625..00000000 --- a/packages/wasm/src/auction.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { - AuctionId, - DutchAuctionDescription, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/auction/v1/auction_pb'; -import { get_auction_id, get_auction_nft_metadata } from '../wasm'; -import { Metadata } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; - -export const getAuctionId = (dutchAuctionDescription: DutchAuctionDescription): AuctionId => { - const result = get_auction_id(dutchAuctionDescription.toBinary()); - return AuctionId.fromBinary(result); -}; - -export const getAuctionNftMetadata = (auctionId: AuctionId, seq: bigint): Metadata => { - const result = get_auction_nft_metadata(auctionId.toBinary(), seq); - return Metadata.fromBinary(result); -}; diff --git a/packages/wasm/src/build.ts b/packages/wasm/src/build.ts deleted file mode 100644 index 8ce4b3aa..00000000 --- a/packages/wasm/src/build.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { - Action, - AuthorizationData, - Transaction, - TransactionPlan, - WitnessData, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/transaction/v1/transaction_pb'; -import type { StateCommitmentTree } from '@penumbra-zone/types/state-commitment-tree'; -import { authorize, build_action, build_parallel, load_proving_key, witness } from '../wasm'; -import { - FullViewingKey, - SpendKey, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb'; - -export const authorizePlan = (spendKey: SpendKey, txPlan: TransactionPlan): AuthorizationData => { - const result = authorize(spendKey.toBinary(), txPlan.toBinary()); - return AuthorizationData.fromBinary(result); -}; - -export const getWitness = (txPlan: TransactionPlan, sct: StateCommitmentTree): WitnessData => { - const result = witness(txPlan.toBinary(), sct); - return WitnessData.fromBinary(result); -}; - -export const buildParallel = ( - batchActions: Action[], - txPlan: TransactionPlan, - witnessData: WitnessData, - authData: AuthorizationData, -): Transaction => { - const result = build_parallel( - batchActions.map(action => action.toJson()), - txPlan.toBinary(), - witnessData.toBinary(), - authData.toBinary(), - ); - return Transaction.fromBinary(result); -}; - -export const buildActionParallel = async ( - txPlan: TransactionPlan, - witnessData: WitnessData, - fullViewingKey: FullViewingKey, - actionId: number, - keyPath?: string, -): Promise => { - // Conditionally read proving keys from disk and load keys into WASM binary - const actionPlan = txPlan.actions[actionId]; - if (!actionPlan?.action.case) throw new Error('No action key provided'); - if (keyPath) await loadProvingKey(actionPlan.action.case, keyPath); - - const result = build_action( - txPlan.toBinary(), - actionPlan.toBinary(), - fullViewingKey.toBinary(), - witnessData.toBinary(), - ); - - return Action.fromBinary(result); -}; - -const loadProvingKey = async ( - actionType: Exclude, - keyPath: string, -) => { - const key = new Uint8Array(await (await fetch(keyPath)).arrayBuffer()); - load_proving_key(key, actionType); -}; diff --git a/packages/wasm/src/dex.ts b/packages/wasm/src/dex.ts deleted file mode 100644 index 2886fb8b..00000000 --- a/packages/wasm/src/dex.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { compute_position_id, get_lpnft_asset } from '../wasm'; -import { - Position, - PositionId, - PositionState, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/dex/v1/dex_pb'; -import { Metadata } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; - -export const computePositionId = (position: Position): PositionId => { - const bytes = compute_position_id(position.toBinary()); - return PositionId.fromBinary(bytes); -}; - -export const getLpNftMetadata = ( - positionId: PositionId, - positionState: PositionState, -): Metadata => { - const result = get_lpnft_asset(positionId.toBinary(), positionState.toBinary()); - return Metadata.fromBinary(result); -}; diff --git a/packages/wasm/src/keys.test.ts b/packages/wasm/src/keys.test.ts deleted file mode 100644 index 84c563ab..00000000 --- a/packages/wasm/src/keys.test.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { describe, expect, it } from 'vitest'; -import { - generateSpendKey, - getAddressByIndex, - getEphemeralByIndex, - getFullViewingKey, - getWalletId, -} from './keys'; - -describe('keys', () => { - const seedPhrase = - 'benefit cherry cannon tooth exhibit law avocado spare tooth that amount pumpkin scene foil tape mobile shine apology add crouch situate sun business explain'; - - describe('generateSpendKey()', () => { - it('does not raise zod validation error', () => { - expect(() => { - generateSpendKey(seedPhrase); - }).not.toThrow(); - }); - }); - - describe('generateFullViewingKey()', () => { - it('does not raise zod validation error', () => { - const spendKey = generateSpendKey(seedPhrase); - - expect(() => { - getFullViewingKey(spendKey); - }).not.toThrow(); - }); - }); - - describe('generateAddressByIndex()', () => { - it('does not raise zod validation error', () => { - const spendKey = generateSpendKey(seedPhrase); - const fullViewingKey = getFullViewingKey(spendKey); - - expect(() => { - getAddressByIndex(fullViewingKey, 0); - }).not.toThrow(); - }); - }); - - describe('getEphemeralByIndex()', () => { - it('does not raise zod validation error', () => { - const spendKey = generateSpendKey(seedPhrase); - const fullViewingKey = getFullViewingKey(spendKey); - - expect(() => { - getEphemeralByIndex(fullViewingKey, 0); - }).not.toThrow(); - }); - }); - - describe('getWalletId()', () => { - it('does not raise zod validation error', () => { - const spendKey = generateSpendKey(seedPhrase); - const fullViewingKey = getFullViewingKey(spendKey); - - expect(() => { - getWalletId(fullViewingKey); - }).not.toThrow(); - }); - }); -}); diff --git a/packages/wasm/src/keys.ts b/packages/wasm/src/keys.ts deleted file mode 100644 index d4492294..00000000 --- a/packages/wasm/src/keys.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { - generate_spend_key, - get_address_by_index, - get_ephemeral_address, - get_full_viewing_key, - get_wallet_id, -} from '../wasm'; -import { - Address, - FullViewingKey, - SpendKey, - WalletId, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb'; - -export const generateSpendKey = (seedPhrase: string) => - SpendKey.fromBinary(generate_spend_key(seedPhrase)); - -export const getFullViewingKey = (spendKey: SpendKey) => - FullViewingKey.fromBinary(get_full_viewing_key(spendKey.toBinary())); - -export const getAddressByIndex = (fullViewingKey: FullViewingKey, index: number) => { - const bytes = get_address_by_index(fullViewingKey.toBinary(), index); - return Address.fromBinary(bytes); -}; - -export const getEphemeralByIndex = (fullViewingKey: FullViewingKey, index: number) => { - const bytes = get_ephemeral_address(fullViewingKey.toBinary(), index); - return Address.fromBinary(bytes); -}; - -export const getWalletId = (fullViewingKey: FullViewingKey) => - WalletId.fromBinary(get_wallet_id(fullViewingKey.toBinary())); diff --git a/packages/wasm/src/metadata.ts b/packages/wasm/src/metadata.ts deleted file mode 100644 index af311caa..00000000 --- a/packages/wasm/src/metadata.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Metadata } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; -import { customize_symbol } from '../wasm'; - -/** - * Given a `Metadata`, returns a new `Metadata` with the symbol customized if - * the token is one of several specific types that don't have built-in symbols. - */ -export const customizeSymbol = (metadata: Metadata): Metadata => - Metadata.fromBinary(customize_symbol(metadata.toBinary())); diff --git a/packages/wasm/src/planner.ts b/packages/wasm/src/planner.ts deleted file mode 100644 index e5b96e45..00000000 --- a/packages/wasm/src/planner.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { TransactionPlan } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/transaction/v1/transaction_pb'; -import { TransactionPlannerRequest } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; -import { JsonValue } from '@bufbuild/protobuf'; -import { plan_transaction } from '../wasm'; -import type { IdbConstants } from '@penumbra-zone/types/indexed-db'; -import { FullViewingKey } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb'; - -export const planTransaction = async ( - idbConstants: IdbConstants, - request: TransactionPlannerRequest, - fullViewingKey: FullViewingKey, -) => { - const plan = (await plan_transaction( - idbConstants, - request.toBinary(), - fullViewingKey.toBinary(), - )) as JsonValue; - return TransactionPlan.fromJson(plan); -}; diff --git a/packages/wasm/src/transaction.ts b/packages/wasm/src/transaction.ts deleted file mode 100644 index 0c0a636d..00000000 --- a/packages/wasm/src/transaction.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { transaction_perspective_and_view } from '../wasm'; -import { - Transaction, - TransactionPerspective, - TransactionView, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/transaction/v1/transaction_pb'; -import type { IdbConstants } from '@penumbra-zone/types/indexed-db'; -import { FullViewingKey } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb'; - -export const generateTransactionInfo = async ( - fullViewingKey: FullViewingKey, - tx: Transaction, - idbConstants: IdbConstants, -) => { - const { txp, txv } = await transaction_perspective_and_view( - fullViewingKey.toBinary(), - tx.toBinary(), - idbConstants, - ); - - return { - txp: TransactionPerspective.fromBinary(txp), - txv: TransactionView.fromBinary(txv), - }; -}; diff --git a/packages/wasm/src/tree.ts b/packages/wasm/src/tree.ts deleted file mode 100644 index 9987e8f4..00000000 --- a/packages/wasm/src/tree.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { sct_position } from '../wasm'; -import { Epoch } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/sct/v1/sct_pb'; - -/** - * Returns a serialized representation of a SCT position - */ -export const sctPosition = (blockHeight: bigint, epoch: Epoch): bigint => { - return sct_position(blockHeight, epoch.toBinary()); -}; diff --git a/packages/wasm/src/view-server.test.ts b/packages/wasm/src/view-server.test.ts deleted file mode 100644 index 86249464..00000000 --- a/packages/wasm/src/view-server.test.ts +++ /dev/null @@ -1,36 +0,0 @@ -import 'fake-indexeddb/auto'; // Instanitating ViewServer requires opening up IndexedDb connection -import { describe, expect, it } from 'vitest'; -import { generateSpendKey, getFullViewingKey } from './keys'; -import { ViewServer } from '../wasm'; -import { IDB_TABLES, IdbConstants } from '@penumbra-zone/types/indexed-db'; - -describe('wasmViewServer', () => { - it('does not raise zod validation error', async () => { - const seedPhrase = - 'benefit cherry cannon tooth exhibit law avocado spare tooth that amount pumpkin scene foil tape mobile shine apology add crouch situate sun business explain'; - - const spendKey = generateSpendKey(seedPhrase); - const fullViewingKey = getFullViewingKey(spendKey); - const idbConstants = { - name: 'dbName', - version: 123, - tables: IDB_TABLES, - } satisfies IdbConstants; - - const storedTree = { - hashes: [], - commitments: [], - last_forgotten: 0, - last_position: { - Position: { - epoch: 0, - block: 0, - commitment: 0, - }, - }, - }; - - const vsServer = ViewServer.new(fullViewingKey.toBinary(), 719n, storedTree, idbConstants); - await expect(vsServer).resolves.not.toThrow(); - }); -}); diff --git a/packages/wasm/src/view-server.ts b/packages/wasm/src/view-server.ts deleted file mode 100644 index f1f9baf3..00000000 --- a/packages/wasm/src/view-server.ts +++ /dev/null @@ -1,92 +0,0 @@ -import { ViewServer as WasmViewServer } from '../wasm'; -import { CompactBlock } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/compact_block/v1/compact_block_pb'; -import { MerkleRoot } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/crypto/tct/v1/tct_pb'; -import { JsonObject, JsonValue } from '@bufbuild/protobuf'; -import { - SpendableNoteRecord, - SwapRecord, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; -import { - ScanBlockResult, - SctUpdatesSchema, - StateCommitmentTree, -} from '@penumbra-zone/types/state-commitment-tree'; -import type { IdbConstants } from '@penumbra-zone/types/indexed-db'; -import type { ViewServerInterface } from '@penumbra-zone/types/servers'; -import { validateSchema } from '@penumbra-zone/types/validation'; -import { FullViewingKey } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb'; - -interface ViewServerProps { - fullViewingKey: FullViewingKey; - epochDuration: bigint; - getStoredTree: () => Promise; - idbConstants: IdbConstants; -} - -interface FlushResult { - height?: string | number | bigint; - sct_updates?: JsonObject; - new_notes?: JsonValue[]; - new_swaps?: JsonValue[]; -} - -export class ViewServer implements ViewServerInterface { - private constructor( - private wasmViewServer: WasmViewServer, - public readonly fullViewingKey: FullViewingKey, - private readonly epochDuration: bigint, - private readonly getStoredTree: () => Promise, - private readonly idbConstants: IdbConstants, - ) {} - - static async initialize({ - fullViewingKey, - epochDuration, - getStoredTree, - idbConstants, - }: ViewServerProps): Promise { - const wvs = await WasmViewServer.new( - fullViewingKey.toBinary(), - epochDuration, - await getStoredTree(), - idbConstants, - ); - return new this(wvs, fullViewingKey, epochDuration, getStoredTree, idbConstants); - } - - // Decrypts blocks with viewing key for notes, swaps, and updates revealed for user - // Makes update to internal state-commitment-tree as a side effect. - // Should extract updates via this.flushUpdates(). - async scanBlock(compactBlock: CompactBlock): Promise { - const res = compactBlock.toBinary(); - return this.wasmViewServer.scan_block(res); - } - - // Resets the state of the wasmViewServer to the one set in storage - async resetTreeToStored() { - this.wasmViewServer = await WasmViewServer.new( - this.fullViewingKey.toBinary(), - this.epochDuration, - await this.getStoredTree(), - this.idbConstants, - ); - } - - getSctRoot(): MerkleRoot { - const bytes = this.wasmViewServer.get_sct_root(); - return MerkleRoot.fromBinary(bytes); - } - - // As blocks are scanned, the internal wasmViewServer tree is being updated. - // Flush updates clears the state and returns all the updates since the last checkpoint. - flushUpdates(): ScanBlockResult { - const result = this.wasmViewServer.flush_updates() as FlushResult; - const { height, sct_updates, new_notes, new_swaps } = result; - return { - height: BigInt(height ?? 0), - sctUpdates: validateSchema(SctUpdatesSchema, sct_updates), - newNotes: (new_notes ?? []).map(n => SpendableNoteRecord.fromJson(n)), - newSwaps: (new_swaps ?? []).map(s => SwapRecord.fromJson(s)), - }; - } -} diff --git a/packages/wasm/tsconfig.json b/packages/wasm/tsconfig.json deleted file mode 100644 index 639c57e7..00000000 --- a/packages/wasm/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "tsconfig/base.json", - "include": ["src"], - "exclude": ["node_modules", "crate", "dist"], - "compilerOptions": { - "outDir": "dist", - "rootDir": "src" - } -} diff --git a/packages/wasm/vitest.config.ts b/packages/wasm/vitest.config.ts deleted file mode 100644 index 1ae230cc..00000000 --- a/packages/wasm/vitest.config.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { defineConfig } from 'vitest/config'; -import wasm from 'vite-plugin-wasm'; - -export default defineConfig({ - plugins: [wasm()], -}); diff --git a/packages/wasm/wasm/.npmignore b/packages/wasm/wasm/.npmignore deleted file mode 100644 index e69de29b..00000000 diff --git a/packages/zquery/CHANGELOG.md b/packages/zquery/CHANGELOG.md deleted file mode 100644 index 0d5b5fa2..00000000 --- a/packages/zquery/CHANGELOG.md +++ /dev/null @@ -1,7 +0,0 @@ -# @penumbra-zone/zquery - -## 1.0.0 - -### Major Changes - -- 6b06e04: Introduce ZQuery package and use throughout minifront diff --git a/packages/zquery/eslint.config.mjs b/packages/zquery/eslint.config.mjs deleted file mode 100644 index a53ed8e5..00000000 --- a/packages/zquery/eslint.config.mjs +++ /dev/null @@ -1,13 +0,0 @@ -import { penumbraEslintConfig } from '@penumbra-zone/eslint-config'; -import { config, parser } from 'typescript-eslint'; - -export default config({ - ...penumbraEslintConfig, - languageOptions: { - parser, - parserOptions: { - project: true, - tsconfigRootDir: import.meta.dirname, - }, - }, -}); diff --git a/packages/zquery/package.json b/packages/zquery/package.json deleted file mode 100644 index f2d12657..00000000 --- a/packages/zquery/package.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "@penumbra-zone/zquery", - "version": "1.0.0", - "private": true, - "license": "(MIT OR Apache-2.0)", - "main": "src/index.ts", - "dependencies": { - "react": "^18.3.1", - "zustand": "^4.5.2" - }, - "devDependencies": { - "@types/react": "^18.3.2", - "vitest": "^1.6.0" - } -} diff --git a/packages/zquery/src/index.test.ts b/packages/zquery/src/index.test.ts deleted file mode 100644 index 0972e8b1..00000000 --- a/packages/zquery/src/index.test.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { beforeEach, describe, expect, it, vi } from 'vitest'; -import { createZQuery } from '.'; -import { UseStore } from './types'; - -describe('createZQuery()', () => { - type MockState = null; - let mockUseStore: UseStore; - let mockState: MockState; - - beforeEach(() => { - mockState = null; - mockUseStore = Object.assign((selector: (state: MockState) => T) => selector(mockState), { - getState: () => mockState, - }); - }); - - describe('the return value', () => { - const result = createZQuery({ - name: 'puppyPhotos', - fetch: () => Promise.resolve(null), - getUseStore: () => mockUseStore, - set: () => { - /* no-op */ - }, - get: () => ({ - _zQueryInternal: { - fetch: vi.fn(), - }, - loading: false, - revalidate: vi.fn(), - data: undefined, - error: undefined, - }), - }); - - it('includes hooks and a Zustand slice that use the passed-in name', () => { - expect(result).toHaveProperty('puppyPhotos'); - expect(result.usePuppyPhotos).toBeTypeOf('function'); - expect(result.useRevalidatePuppyPhotos).toBeTypeOf('function'); - }); - - it('includes the correct default state', () => { - expect(result.puppyPhotos).toEqual({ - data: undefined, - error: undefined, - loading: false, - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - revalidate: expect.any(Function), - _zQueryInternal: { - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - fetch: expect.any(Function), - }, - }); - }); - }); -}); diff --git a/packages/zquery/src/index.ts b/packages/zquery/src/index.ts deleted file mode 100644 index 0bf19b2c..00000000 --- a/packages/zquery/src/index.ts +++ /dev/null @@ -1,261 +0,0 @@ -import { useEffect } from 'react'; -import { useShallow } from 'zustand/react/shallow'; -import type { CreateZQueryStreamingProps, CreateZQueryUnaryProps, ZQuery } from './types'; - -export type { ZQueryState } from './types'; - -/** `hello world` -> `Hello world` */ -const capitalize = (str: Str): Capitalize => - (str.charAt(0).toUpperCase() + str.slice(1)) as Capitalize; - -/** - * Some of the `createZQuery` props work differently depending on whether - * `props.fetch` returns a promise or an `AsyncIterable`. This utility function - * is a type predicate that informs our code both at compile- and run-time which - * type of props and data we're working with. - */ -const isStreaming = < - Name extends string, - State, - DataType, - FetchArgs extends unknown[], - ProcessedDataType, ->( - props: - | CreateZQueryUnaryProps - | CreateZQueryStreamingProps, -): props is CreateZQueryStreamingProps => - !!props.stream; - -/** - * Creates a ZQuery object that can be used to store server data in Zustand - * state. - * - * ## Usage - * First, create a ZQuery object (see individual parameters for docs on how to - * use them): - * - * ```ts - * export const { puppyPhotos, usePuppyPhotos, useRevalidatePuppyPhotos } = createZQuery({ - * name: 'puppyPhotos', - * fetch: asyncFunctionThatFetchesAndReturnsPuppyPhotos, - * getUseStore: () => useStore, - * set: setter => { - * useStore.setState(state => { - * ...state, - * puppyPhotos: setter(state), - * }), - * }, - * get: state => state.puppyPhotos, - * }) - * ``` - * - * Then, attach the property with the object's name to your Zustand state: - * - * ```ts - * const useStore = create()(set => ({ - * // ... - * puppyPhotos, // destructured from the return value of `createZQuery()` above - * })) - * ``` - * - * Finally, in your component, use the hooks as needed: - * - * ```tsx - * import { usePuppyPhotos, useRevalidatePuppyPhotos } from './state' - * - * const PuppyPhotos = () => { - * const puppyPhotos = usePuppyPhotos() - * const revalidate = useRevalidatePuppyPhotos() - * - * return ( - *
- * {puppyPhotos.error &&
{JSON.stringify(puppyPhotos.error)}
} - * {puppyPhotos.data?.map(puppyPhoto => ( - * {puppyPhoto.alt} - * ))} - * - * - *
- * ) - * } - * ``` - */ -export function createZQuery< - State, - Name extends string, - DataType, - FetchArgs extends unknown[], - ProcessedDataType extends DataType = DataType, ->( - props: CreateZQueryUnaryProps, -): ZQuery; - -export function createZQuery< - State, - Name extends string, - DataType, - FetchArgs extends unknown[], - ProcessedDataType, ->( - props: CreateZQueryStreamingProps, -): ZQuery; - -export function createZQuery< - State, - Name extends string, - DataType, - FetchArgs extends unknown[], - ProcessedDataType = DataType, ->( - props: - | CreateZQueryUnaryProps - | CreateZQueryStreamingProps, -): ZQuery { - const { name, get, set, getUseStore } = props; - - const setAbortController = (abortController: AbortController | undefined) => { - set(prevState => ({ - ...prevState, - _zQueryInternal: { - ...prevState._zQueryInternal, - abortController, - }, - })); - }; - - const incrementReferenceCounter = () => { - const newReferenceCount = get(getUseStore().getState())._zQueryInternal.referenceCount + 1; - - set(prevState => ({ - ...prevState, - _zQueryInternal: { - ...prevState._zQueryInternal, - referenceCount: newReferenceCount, - }, - })); - - return newReferenceCount; - }; - - const decrementReferenceCounter = () => { - const newReferenceCount = get(getUseStore().getState())._zQueryInternal.referenceCount - 1; - - set(prevState => ({ - ...prevState, - _zQueryInternal: { - ...prevState._zQueryInternal, - referenceCount: newReferenceCount, - }, - })); - - return newReferenceCount; - }; - - return { - [`use${capitalize(name)}`]: (...args: FetchArgs) => { - const useStore = getUseStore(); - - useEffect(() => { - const fetch = get(useStore.getState())._zQueryInternal.fetch; - - { - const newReferenceCount = incrementReferenceCounter(); - - if (newReferenceCount === 1) { - setAbortController(new AbortController()); - void fetch(...args); - } - } - - const onUnmount = () => { - const newReferenceCount = decrementReferenceCounter(); - - if (newReferenceCount === 0) { - get(useStore.getState())._zQueryInternal.abortController?.abort(); - setAbortController(undefined); - } - }; - - return onUnmount; - }, [fetch]); - - const returnValue = useStore( - useShallow(state => { - const zQuery = get(state); - - return { - data: zQuery.data, - loading: zQuery.loading, - error: zQuery.error, - }; - }), - ); - - return returnValue; - }, - - [`useRevalidate${capitalize(name)}`]: () => { - const useStore = getUseStore(); - const returnValue = useStore(useShallow((state: State) => get(state).revalidate)); - return returnValue; - }, - - [name]: { - data: undefined, - loading: false, - error: undefined, - - revalidate: (...args: FetchArgs) => { - const { _zQueryInternal } = get(getUseStore().getState()); - _zQueryInternal.abortController?.abort(); - setAbortController(new AbortController()); - void _zQueryInternal.fetch(...args); - }, - - _zQueryInternal: { - referenceCount: 0, - - fetch: async (...args: FetchArgs) => { - const abortController = get(getUseStore().getState())._zQueryInternal.abortController; - // We have to use the `props` object (rather than its destructured - // properties) since we're passing the full `props` object to - // `isStreaming`, which is a type predicate. If we use previously - // destructured properties after the type predicate, the type - // predicate won't apply to them, since the type predicate was called - // after destructuring. - if (isStreaming(props)) { - const result = props.fetch(...args); - - props.set(prevState => ({ - ...prevState, - data: undefined, - })); - - try { - for await (const item of result) { - if (abortController?.signal.aborted) return; - - props.set(prevState => ({ - ...prevState, - data: props.stream(prevState.data, item), - })); - } - } catch (error) { - props.set(prevState => ({ ...prevState, error })); - } - } else { - try { - const data = await props.fetch(...args); - props.set(prevState => ({ ...prevState, data })); - } catch (error) { - props.set(prevState => ({ ...prevState, error })); - } - } - }, - }, - }, - } as ZQuery; -} diff --git a/packages/zquery/src/types.ts b/packages/zquery/src/types.ts deleted file mode 100644 index c5120b1c..00000000 --- a/packages/zquery/src/types.ts +++ /dev/null @@ -1,190 +0,0 @@ -export interface ZQueryState { - data?: DataType | undefined; - loading: boolean; - error?: unknown; - - revalidate: (...args: FetchArgs) => void; - - _zQueryInternal: { - referenceCount: number; - fetch: (...args: FetchArgs) => Promise; - abortController?: AbortController; - }; -} - -interface CreateZQueryCommonProps { - /** The name of this property in the state/slice. */ - name: Name; - /** - * A function that returns your `useStore` object -- e.g.: `() => useStore` - * - * If you passed `useStore` directly to `createZQuery`, which is called while - * defining `useStore`, you'd get a circular dependency. To work around that, - * pass a function that returns `useStore`, so that it can be used later (once - * `useStore` is defined). - */ - getUseStore: () => UseStore; -} - -export interface CreateZQueryUnaryProps< - Name extends string, - State, - DataType, - FetchArgs extends unknown[], -> extends CreateZQueryCommonProps { - stream?: undefined; - /** A function that executes the query. */ - fetch: (...args: FetchArgs) => Promise; - /** - * A selector that takes the root Zustand state and returns just this ZQuery - * state object. - * - * This ZQuery object doesn't know anything about the store or where this - * ZQuery object is located within it, so it can't call - * `getUseStore().getState()` and then navigate to its own location within - * state. Thus, you need to pass it a selector so it can find itself. - * - * ```ts - * createZQuery({ - * // ... - * // ... - * // ... - * // ... - * get: state => state.deeply.nested.object, - * }) - * ``` - */ - get: (state: State) => ZQueryState; - /** - * A setter that takes an updated ZQuery state object and assigns it to the - * location in your overall Zustand state object where this ZQuery state - * object is located. - * - * This ZQuery object doesn't know anything about the store or where this - * ZQuery object is located within it, so it can't call `set()` with the - * necessary spreads/etc. to ensure that the rest of the state is untouched - * when the ZQuery state is updated. So your setter needs to handle that. For - * example, if you have a deeply nested ZQuery object (located at - * `state.deeply.nested.object`) and you're using Zustand's Immer middleware - * to be able to imitate object mutations, you could pass this setter: - * - * ```ts - * createZQuery({ - * // ... - * // ... - * // ... - * set: newValue => { - * // `newValue` is the entire ZQuery state object, and can be assigned - * // as-is to the property that holds the ZQuery state. - * useStore.setState(state => { - * state.deeply.nested.object = newValue; - * }) - * }, - * // ... - * }) - * ``` - */ - set: (setter: >(prevState: T) => T) => void; -} - -export interface CreateZQueryStreamingProps< - Name extends string, - State, - DataType, - FetchArgs extends unknown[], - ProcessedDataType, -> extends CreateZQueryCommonProps { - /** A function that executes the query. */ - fetch: (...args: FetchArgs) => AsyncIterable; - /** - * Set to `true` if `fetch` will return a streaming response in the form of an - * `AsyncIterable`. - * - * Or, if you wish to modify the streaming results as they come in before - * they're added to the state, set this to a function that takes the current state - * as its first argument and the streamed item as its second, and returns the - * desired new state (or a promise containing the desired new state). This can - * be useful for e.g. sorting items in the state as new items are streamed. - */ - stream: (prevData: ProcessedDataType | undefined, item: DataType) => ProcessedDataType; - /** - * A selector that takes the root Zustand state and returns just this ZQuery - * state object. - * - * This ZQuery object doesn't know anything about the store or where this - * ZQuery object is located within it, so it can't call - * `getUseStore().getState()` and then navigate to its own location within - * state. Thus, you need to pass it a selector so it can find itself. - * - * ```ts - * createZQuery({ - * // ... - * // ... - * // ... - * // ... - * get: state => state.deeply.nested.object, - * }) - * ``` - */ - get: (state: State) => ZQueryState; - /** - * A setter that takes an updated ZQuery state object and assigns it to the - * location in your overall Zustand state object where this ZQuery state - * object is located. - * - * This ZQuery object doesn't know anything about the store or where this - * ZQuery object is located within it, so it can't call `set()` with the - * necessary spreads/etc. to ensure that the rest of the state is untouched - * when the ZQuery state is updated. So your setter needs to handle that. For - * example, if you have a deeply nested ZQuery object (located at - * `state.deeply.nested.object`) and you're using Zustand's Immer middleware - * to be able to imitate object mutations, you could pass this setter: - * - * ```ts - * createZQuery({ - * // ... - * // ... - * // ... - * set: newValue => { - * // `newValue` is the entire ZQuery state object, and can be assigned - * // as-is to the property that holds the ZQuery state. - * useStore.setState(state => { - * state.deeply.nested.object = newValue; - * }) - * }, - * // ... - * }) - * ``` - */ - set: ( - setter: >( - prevState: T, - ) => T, - ) => void; -} - -/** - * A simplified version of `UseBoundStore>`. - * - * We only use the `useStore()` hook and the `useStore.getState()` method in - * ZQuery, and we don't want to have to accommodate all of the different types - * that a `useStore` object can have when used with various middlewares, etc. - * For example, a "normal" `useStore` object is typed as - * `UseBoundStore>`, but a `useStore` object created with Immer - * middleware is typed as `UseBoundStore>>`. A - * function that accepts a `useStore` of the former type won't accept a - * `useStore` of the latter type (or of various other store types that mutated - * by middleware), so we'll just create a loose typing for `useStore` that can - * accommodate whatever middleware is being used. - */ -export type UseStore = ((selector: (state: State) => T) => T) & { getState(): State }; - -export type ZQuery = { - [key in `use${Capitalize}`]: (...args: FetchArgs) => { - data?: DataType; - loading: boolean; - error?: unknown; - }; -} & { - [key in `useRevalidate${Capitalize}`]: () => (...args: FetchArgs) => void; -} & Record>; diff --git a/packages/zquery/tsconfig.json b/packages/zquery/tsconfig.json deleted file mode 100644 index 2a9d5af4..00000000 --- a/packages/zquery/tsconfig.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "extends": "tsconfig/react-library.json", - "include": [".", "./tests-setup.ts"], - "exclude": ["dist", "build", "node_modules"] -} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index dc9e5530..ace3b323 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,20 +9,20 @@ importers: .: dependencies: '@buf/cosmos_ibc.bufbuild_es': - specifier: 1.9.0-20240530142100-ad4444393387.1 - version: 1.9.0-20240530142100-ad4444393387.1(@bufbuild/protobuf@1.10.0) + specifier: 1.10.0-20240606104028-442292b00c16.1 + version: 1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0) '@buf/cosmos_ibc.connectrpc_es': - specifier: 1.4.0-20240530142100-ad4444393387.2 - version: 1.4.0-20240530142100-ad4444393387.2(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) + specifier: 1.4.0-20240606104028-442292b00c16.3 + version: 1.4.0-20240606104028-442292b00c16.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) '@buf/penumbra-zone_penumbra.bufbuild_es': - specifier: 1.9.0-20240528180215-8fe1c79485f8.1 - version: 1.9.0-20240528180215-8fe1c79485f8.1(@bufbuild/protobuf@1.10.0) + specifier: 1.10.0-20240616005217-ca45ca80333e.1 + version: 1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0) '@buf/penumbra-zone_penumbra.connectrpc_es': - specifier: 1.4.0-20240528180215-8fe1c79485f8.2 - version: 1.4.0-20240528180215-8fe1c79485f8.2(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) + specifier: 1.4.0-20240616005217-ca45ca80333e.3 + version: 1.4.0-20240616005217-ca45ca80333e.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) '@buf/tendermint_tendermint.bufbuild_es': - specifier: 1.9.0-20231117195010-33ed361a9051.1 - version: 1.9.0-20231117195010-33ed361a9051.1(@bufbuild/protobuf@1.10.0) + specifier: 1.10.0-20231117195010-33ed361a9051.1 + version: 1.10.0-20231117195010-33ed361a9051.1(@bufbuild/protobuf@1.10.0) '@bufbuild/protobuf': specifier: ^1.10.0 version: 1.10.0 @@ -32,103 +32,85 @@ importers: '@connectrpc/connect-web': specifier: ^1.4.0 version: 1.4.0(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) - '@penumbra-zone/keys': - specifier: workspace:* - version: link:packages/keys devDependencies: '@buf/connectrpc_eliza.bufbuild_es': - specifier: 1.9.0-20230913231627-233fca715f49.1 - version: 1.9.0-20230913231627-233fca715f49.1(@bufbuild/protobuf@1.10.0) + specifier: 1.10.0-20230913231627-233fca715f49.1 + version: 1.10.0-20230913231627-233fca715f49.1(@bufbuild/protobuf@1.10.0) '@buf/connectrpc_eliza.connectrpc_es': - specifier: 1.4.0-20230913231627-233fca715f49.2 - version: 1.4.0-20230913231627-233fca715f49.2(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) + specifier: 1.4.0-20230913231627-233fca715f49.3 + version: 1.4.0-20230913231627-233fca715f49.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) '@changesets/cli': - specifier: ^2.27.3 + specifier: ^2.27.5 version: 2.27.5 - '@penumbra-zone/eslint-config': + '@repo/eslint-config': specifier: workspace:* version: link:packages/eslint-config - '@penumbra-zone/tailwind-config': + '@repo/tailwind-config': specifier: workspace:* version: link:packages/tailwind-config - '@penumbra-zone/wasm': + '@repo/tsconfig': specifier: workspace:* - version: link:packages/wasm + version: link:packages/tsconfig '@storybook/react-vite': specifier: 8.1.1 - version: 8.1.1(encoding@0.1.13)(prettier@3.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.18.0)(typescript@5.4.5)(vite@5.2.13(@types/node@20.14.2)(terser@5.31.1)) + version: 8.1.1(encoding@0.1.13)(prettier@3.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.18.0)(typescript@5.4.5)(vite@5.3.1(@types/node@20.14.5)(terser@5.31.1)) '@turbo/gen': - specifier: ^1.13.3 - version: 1.13.4(@swc/core@1.5.28(@swc/helpers@0.5.11))(@types/node@20.14.2)(typescript@5.4.5) + specifier: ^1.13.4 + version: 1.13.4(@swc/core@1.6.3)(@types/node@20.14.5)(typescript@5.4.5) '@types/chrome': specifier: 0.0.268 version: 0.0.268 '@types/node': - specifier: ^20.12.12 - version: 20.14.2 - '@vitejs/plugin-basic-ssl': - specifier: ^1.1.0 - version: 1.1.0(vite@5.2.13(@types/node@20.14.2)(terser@5.31.1)) - '@vitejs/plugin-react': - specifier: ^4.2.1 - version: 4.3.1(vite@5.2.13(@types/node@20.14.2)(terser@5.31.1)) + specifier: ^20.14.5 + version: 20.14.5 '@vitejs/plugin-react-swc': - specifier: ^3.6.0 - version: 3.7.0(@swc/helpers@0.5.11)(vite@5.2.13(@types/node@20.14.2)(terser@5.31.1)) + specifier: ^3.7.0 + version: 3.7.0(vite@5.3.1(@types/node@20.14.5)(terser@5.31.1)) '@vitest/browser': specifier: ^1.6.0 version: 1.6.0(playwright@1.44.1)(vitest@1.6.0) jsdom: - specifier: ^24.0.0 - version: 24.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.4) + specifier: ^24.1.0 + version: 24.1.0 playwright: - specifier: ^1.44.0 + specifier: ^1.44.1 version: 1.44.1 prettier: - specifier: ^3.2.5 + specifier: ^3.3.2 version: 3.3.2 - react: - specifier: ^18.3.1 - version: 18.3.1 syncpack: specifier: ^12.3.2 version: 12.3.2(typescript@5.4.5) tailwindcss: - specifier: ^3.4.3 - version: 3.4.4(ts-node@10.9.2(@swc/core@1.5.28(@swc/helpers@0.5.11))(@types/node@20.14.2)(typescript@5.4.5)) - tsconfig: - specifier: workspace:* - version: link:packages/tsconfig + specifier: ^3.4.4 + version: 3.4.4(ts-node@10.9.2(@swc/core@1.6.3)(@types/node@20.14.5)(typescript@5.4.5)) turbo: - specifier: ^1.13.3 + specifier: ^1.13.4 version: 1.13.4 typescript: specifier: ^5.4.5 version: 5.4.5 vite: - specifier: ^5.2.11 - version: 5.2.13(@types/node@20.14.2)(terser@5.31.1) - vite-plugin-dts: - specifier: ^3.9.1 - version: 3.9.1(@types/node@20.14.2)(rollup@4.18.0)(typescript@5.4.5)(vite@5.2.13(@types/node@20.14.2)(terser@5.31.1)) - vite-plugin-externalize-deps: - specifier: ^0.8.0 - version: 0.8.0(vite@5.2.13(@types/node@20.14.2)(terser@5.31.1)) + specifier: ^5.3.1 + version: 5.3.1(@types/node@20.14.5)(terser@5.31.1) vite-plugin-top-level-await: specifier: ^1.4.1 - version: 1.4.1(@swc/helpers@0.5.11)(rollup@4.18.0)(vite@5.2.13(@types/node@20.14.2)(terser@5.31.1)) + version: 1.4.1(rollup@4.18.0)(vite@5.3.1(@types/node@20.14.5)(terser@5.31.1)) vite-plugin-wasm: specifier: ^3.3.0 - version: 3.3.0(vite@5.2.13(@types/node@20.14.2)(terser@5.31.1)) + version: 3.3.0(vite@5.3.1(@types/node@20.14.5)(terser@5.31.1)) vitest: specifier: ^1.6.0 - version: 1.6.0(@types/node@20.14.2)(@vitest/browser@1.6.0(playwright@1.44.1)(vitest@1.6.0))(jsdom@24.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(terser@5.31.1) + version: 1.6.0(@types/node@20.14.5)(@vitest/browser@1.6.0(playwright@1.44.1)(vitest@1.6.0))(jsdom@24.1.0)(terser@5.31.1) apps/extension: dependencies: + '@buf/cosmos_ibc.bufbuild_es': + specifier: 1.10.0-20240606104028-442292b00c16.1 + version: 1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0) '@buf/penumbra-zone_penumbra.bufbuild_es': - specifier: 1.9.0-20240528180215-8fe1c79485f8.1 - version: 1.9.0-20240528180215-8fe1c79485f8.1(@bufbuild/protobuf@1.10.0) + specifier: 1.10.0-20240616005217-ca45ca80333e.1 + version: 1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0) '@bufbuild/protobuf': specifier: ^1.10.0 version: 1.10.0 @@ -142,50 +124,53 @@ importers: specifier: 8.0.1 version: 8.0.1 '@penumbra-zone/bech32m': - specifier: workspace:* - version: link:../../packages/bech32m + specifier: ^6.1.0 + version: 6.1.0 '@penumbra-zone/client': - specifier: workspace:* - version: link:../../packages/client + specifier: ^8.0.0 + version: 8.0.0(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))(@penumbra-zone/transport-dom@7.1.0) '@penumbra-zone/crypto-web': - specifier: workspace:* - version: link:../../packages/crypto + specifier: ^5.0.0 + version: 5.0.0(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))))) '@penumbra-zone/getters': - specifier: workspace:* - version: link:../../packages/getters + specifier: ^8.0.0 + version: 8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))) + '@penumbra-zone/keys': + specifier: ^4.1.0 + version: 4.1.0 '@penumbra-zone/perspective': - specifier: workspace:* - version: link:../../packages/perspective + specifier: ^6.0.0 + version: 6.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))))(@penumbra-zone/wasm@9.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))))) '@penumbra-zone/protobuf': - specifier: workspace:* - version: link:../../packages/protobuf + specifier: ^5.1.0 + version: 5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))) '@penumbra-zone/query': - specifier: workspace:* - version: link:../../packages/query + specifier: ^6.0.0 + version: 6.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/crypto-web@5.0.0(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))))))(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))))(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))))(@penumbra-zone/wasm@9.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))))) '@penumbra-zone/services': - specifier: workspace:* - version: link:../../packages/services - '@penumbra-zone/services-context': - specifier: workspace:* - version: link:../../packages/services-context + specifier: ^6.0.0 + version: 6.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/crypto-web@5.0.0(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))))))(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))))(@penumbra-zone/perspective@6.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))))(@penumbra-zone/wasm@9.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))))))(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))(@penumbra-zone/query@6.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/crypto-web@5.0.0(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))))))(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))))(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))))(@penumbra-zone/wasm@9.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))))))(@penumbra-zone/storage@6.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))))(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))))(@penumbra-zone/wasm@9.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))))))(@penumbra-zone/transport-dom@7.1.0)(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))))(@penumbra-zone/wasm@9.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))))) '@penumbra-zone/storage': - specifier: workspace:* - version: link:../../packages/storage + specifier: ^6.0.0 + version: 6.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))))(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))))(@penumbra-zone/wasm@9.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))))) '@penumbra-zone/transport-chrome': - specifier: workspace:* - version: link:../../packages/transport-chrome + specifier: ^4.0.0 + version: 4.0.0(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))(@penumbra-zone/transport-dom@7.1.0) '@penumbra-zone/transport-dom': - specifier: workspace:* - version: link:../../packages/transport-dom + specifier: ^7.1.0 + version: 7.1.0 '@penumbra-zone/types': + specifier: ^9.0.0 + version: 9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))) + '@penumbra-zone/wasm': + specifier: ^9.0.0 + version: 9.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))))) + '@repo/context': specifier: workspace:* - version: link:../../packages/types - '@penumbra-zone/ui': + version: link:../../packages/context + '@repo/ui': specifier: workspace:* version: link:../../packages/ui - '@penumbra-zone/wasm': - specifier: workspace:* - version: link:../../packages/wasm '@tanstack/react-query': specifier: 4.36.1 version: 4.36.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -232,15 +217,15 @@ importers: specifier: ^4.5.2 version: 4.5.2(@types/react@18.3.3)(immer@10.1.1)(react@18.3.1) devDependencies: - '@penumbra-zone/keys': - specifier: workspace:* - version: link:../../packages/keys '@radix-ui/react-icons': specifier: ^1.3.0 version: 1.3.0(react@18.3.1) + '@types/chrome': + specifier: 0.0.268 + version: 0.0.268 '@types/firefox-webext-browser': specifier: ^120.0.3 - version: 120.0.3 + version: 120.0.4 '@types/lodash': specifier: ^4.17.4 version: 4.17.5 @@ -252,52 +237,46 @@ importers: version: 18.3.0 '@types/webpack': specifier: ^5.28.5 - version: 5.28.5(@swc/core@1.5.28(@swc/helpers@0.5.11))(webpack-cli@5.1.4(webpack@5.92.0)) + version: 5.28.5(@swc/core@1.6.3)(esbuild@0.20.2)(webpack-cli@5.1.4(webpack@5.92.0)) autoprefixer: specifier: ^10.4.19 version: 10.4.19(postcss@8.4.38) copy-webpack-plugin: specifier: ^12.0.2 - version: 12.0.2(webpack@5.92.0(@swc/core@1.5.28(@swc/helpers@0.5.11))(webpack-cli@5.1.4)) + version: 12.0.2(webpack@5.92.0(@swc/core@1.6.3)(esbuild@0.20.2)(webpack-cli@5.1.4(webpack@5.92.0))) css-loader: specifier: ^7.1.1 - version: 7.1.2(webpack@5.92.0(@swc/core@1.5.28(@swc/helpers@0.5.11))(webpack-cli@5.1.4)) + version: 7.1.2(webpack@5.92.0(@swc/core@1.6.3)(esbuild@0.20.2)(webpack-cli@5.1.4(webpack@5.92.0))) dotenv: specifier: ^16.4.5 version: 16.4.5 html-webpack-plugin: specifier: ^5.6.0 - version: 5.6.0(webpack@5.92.0(@swc/core@1.5.28(@swc/helpers@0.5.11))(webpack-cli@5.1.4)) + version: 5.6.0(webpack@5.92.0(@swc/core@1.6.3)(esbuild@0.20.2)(webpack-cli@5.1.4(webpack@5.92.0))) postcss: specifier: ^8.4.38 version: 8.4.38 postcss-loader: specifier: ^8.1.1 - version: 8.1.1(postcss@8.4.38)(typescript@5.4.5)(webpack@5.92.0(@swc/core@1.5.28(@swc/helpers@0.5.11))(webpack-cli@5.1.4)) + version: 8.1.1(postcss@8.4.38)(typescript@5.4.5)(webpack@5.92.0(@swc/core@1.6.3)(esbuild@0.20.2)(webpack-cli@5.1.4(webpack@5.92.0))) promise.withresolvers: specifier: ^1.0.3 version: 1.0.3 style-loader: specifier: ^4.0.0 - version: 4.0.0(webpack@5.92.0(@swc/core@1.5.28(@swc/helpers@0.5.11))(webpack-cli@5.1.4)) + version: 4.0.0(webpack@5.92.0(@swc/core@1.6.3)(esbuild@0.20.2)(webpack-cli@5.1.4(webpack@5.92.0))) tailwindcss: - specifier: ^3.4.3 - version: 3.4.4(ts-node@10.9.2(@swc/core@1.5.28(@swc/helpers@0.5.11))(@types/node@20.14.2)(typescript@5.4.5)) + specifier: ^3.4.4 + version: 3.4.4(ts-node@10.9.2(@swc/core@1.6.3)(@types/node@20.14.5)(typescript@5.4.5)) ts-loader: specifier: ^9.5.1 - version: 9.5.1(typescript@5.4.5)(webpack@5.92.0(@swc/core@1.5.28(@swc/helpers@0.5.11))(webpack-cli@5.1.4)) + version: 9.5.1(typescript@5.4.5)(webpack@5.92.0(@swc/core@1.6.3)(esbuild@0.20.2)(webpack-cli@5.1.4(webpack@5.92.0))) ts-node: specifier: ^10.9.2 - version: 10.9.2(@swc/core@1.5.28(@swc/helpers@0.5.11))(@types/node@20.14.2)(typescript@5.4.5) - vite-plugin-top-level-await: - specifier: ^1.4.1 - version: 1.4.1(@swc/helpers@0.5.11)(rollup@4.18.0)(vite@5.2.13(@types/node@20.14.2)(terser@5.31.1)) - vite-plugin-wasm: - specifier: ^3.3.0 - version: 3.3.0(vite@5.2.13(@types/node@20.14.2)(terser@5.31.1)) + version: 10.9.2(@swc/core@1.6.3)(@types/node@20.14.5)(typescript@5.4.5) webpack: specifier: ^5.91.0 - version: 5.92.0(@swc/core@1.5.28(@swc/helpers@0.5.11))(webpack-cli@5.1.4) + version: 5.92.0(@swc/core@1.6.3)(esbuild@0.20.2)(webpack-cli@5.1.4(webpack@5.92.0)) webpack-cli: specifier: ^5.1.4 version: 5.1.4(webpack@5.92.0) @@ -307,9 +286,6 @@ importers: apps/prax-marketing-site: dependencies: - '@vitejs/plugin-react-swc': - specifier: ^3.6.0 - version: 3.7.0(@swc/helpers@0.5.11)(vite@5.2.13(@types/node@20.14.2)(terser@5.31.1)) react: specifier: ^18.3.1 version: 18.3.1 @@ -320,15 +296,9 @@ importers: specifier: ^6.23.1 version: 6.23.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) tailwindcss: - specifier: ^3.4.3 - version: 3.4.4(ts-node@10.9.2(@swc/core@1.5.28(@swc/helpers@0.5.11))(@types/node@20.14.2)(typescript@5.4.5)) + specifier: ^3.4.4 + version: 3.4.4(ts-node@10.9.2(@swc/core@1.6.3)(@types/node@20.14.5)(typescript@5.4.5)) devDependencies: - '@penumbra-zone/eslint-config': - specifier: workspace:* - version: link:../../packages/eslint-config - '@penumbra-zone/tailwind-config': - specifier: workspace:* - version: link:../../packages/tailwind-config '@types/react': specifier: ^18.3.2 version: 18.3.3 @@ -340,378 +310,106 @@ importers: version: 10.4.19(postcss@8.4.38) firebase-tools: specifier: ^13.8.0 - version: 13.11.2(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.4) + version: 13.11.2(encoding@0.1.13) postcss: specifier: ^8.4.38 version: 8.4.38 - packages/bech32m: + packages/context: dependencies: - bech32: - specifier: ^2.0.0 - version: 2.0.0 - devDependencies: + '@buf/cosmos_ibc.bufbuild_es': + specifier: 1.10.0-20240606104028-442292b00c16.1 + version: 1.10.0-20240618145807-4698edb0fdb0.1(@bufbuild/protobuf@1.10.0) '@buf/penumbra-zone_penumbra.bufbuild_es': - specifier: 1.9.0-20240528180215-8fe1c79485f8.1 - version: 1.9.0-20240528180215-8fe1c79485f8.1(@bufbuild/protobuf@1.10.0) - - packages/client: - dependencies: + specifier: 1.10.0-20240616005217-ca45ca80333e.1 + version: 1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0) '@bufbuild/protobuf': specifier: ^1.10.0 version: 1.10.0 + '@penumbra-labs/registry': + specifier: 8.0.1 + version: 8.0.1 + '@penumbra-zone/bech32m': + specifier: ^6.1.0 + version: 6.1.0 + '@penumbra-zone/crypto-web': + specifier: ^5.0.0 + version: 5.0.0(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))))) '@penumbra-zone/protobuf': - specifier: workspace:* - version: link:../protobuf - '@penumbra-zone/transport-dom': - specifier: workspace:* - version: link:../transport-dom - devDependencies: - '@connectrpc/connect': - specifier: ^1.4.0 - version: 1.4.0(@bufbuild/protobuf@1.10.0) - - packages/crypto: - dependencies: + specifier: ^5.1.0 + version: 5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240618145807-4698edb0fdb0.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))) + '@penumbra-zone/query': + specifier: ^6.0.0 + version: 6.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/crypto-web@5.0.0(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))))))(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))))(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))))(@penumbra-zone/wasm@9.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))))) + '@penumbra-zone/storage': + specifier: ^6.0.0 + version: 6.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))))(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))))(@penumbra-zone/wasm@9.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))))) '@penumbra-zone/types': - specifier: workspace:* - version: link:../types - bip39: - specifier: ^3.1.0 - version: 3.1.0 - crypto-js: - specifier: ^4.2.0 - version: 4.2.0 - devDependencies: - '@types/crypto-js': - specifier: ^4.2.2 - version: 4.2.2 + specifier: ^9.0.0 + version: 9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))) + '@penumbra-zone/wasm': + specifier: ^9.0.0 + version: 9.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))))) + exponential-backoff: + specifier: ^3.1.1 + version: 3.1.1 packages/eslint-config: devDependencies: '@eslint/compat': specifier: ^1.0.1 - version: 1.0.3 + version: 1.1.0 '@eslint/js': specifier: ^9.3.0 - version: 9.4.0 + version: 9.5.0 eslint: specifier: ^9.3.0 - version: 9.4.0 + version: 9.5.0 eslint-config-prettier: specifier: ^9.1.0 - version: 9.1.0(eslint@9.4.0) + version: 9.1.0(eslint@9.5.0) eslint-import-resolver-typescript: specifier: ^3.6.1 - version: 3.6.1(@typescript-eslint/parser@7.13.0(eslint@9.4.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@9.4.0) + version: 3.6.1(@typescript-eslint/parser@7.13.1(eslint@9.5.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@9.5.0) eslint-plugin-import: specifier: ^2.29.1 - version: 2.29.1(@typescript-eslint/parser@7.13.0(eslint@9.4.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@9.4.0) + version: 2.29.1(@typescript-eslint/parser@7.13.1(eslint@9.5.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@9.5.0) eslint-plugin-prettier: specifier: ^5.1.3 - version: 5.1.3(@types/eslint@8.56.10)(eslint-config-prettier@9.1.0(eslint@9.4.0))(eslint@9.4.0)(prettier@3.3.2) + version: 5.1.3(@types/eslint@8.56.10)(eslint-config-prettier@9.1.0(eslint@9.5.0))(eslint@9.5.0)(prettier@3.3.2) eslint-plugin-react: specifier: 7.34.1 - version: 7.34.1(eslint@9.4.0) + version: 7.34.1(eslint@9.5.0) eslint-plugin-react-hooks: specifier: ^4.6.2 - version: 4.6.2(eslint@9.4.0) + version: 4.6.2(eslint@9.5.0) eslint-plugin-storybook: specifier: ^0.8.0 - version: 0.8.0(eslint@9.4.0)(typescript@5.4.5) + version: 0.8.0(eslint@9.5.0)(typescript@5.4.5) eslint-plugin-tailwindcss: specifier: ^3.15.2 - version: 3.17.3(tailwindcss@3.4.4(ts-node@10.9.2(@swc/core@1.5.28(@swc/helpers@0.5.11))(@types/node@20.14.2)(typescript@5.4.5))) + version: 3.17.3(tailwindcss@3.4.4(ts-node@10.9.2(@swc/core@1.6.3)(@types/node@20.14.5)(typescript@5.4.5))) eslint-plugin-turbo: specifier: ^1.13.3 - version: 1.13.4(eslint@9.4.0) + version: 1.13.4(eslint@9.5.0) eslint-plugin-vitest: specifier: ^0.5.4 - version: 0.5.4(eslint@9.4.0)(typescript@5.4.5)(vitest@1.6.0(@types/node@20.14.2)(@vitest/browser@1.6.0(playwright@1.44.1)(vitest@1.6.0))(jsdom@24.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(terser@5.31.1)) + version: 0.5.4(eslint@9.5.0)(typescript@5.4.5)(vitest@1.6.0(@types/node@20.14.5)(@vitest/browser@1.6.0(playwright@1.44.1)(vitest@1.6.0))(jsdom@24.1.0)(terser@5.31.1)) typescript-eslint: specifier: ^7.10.0 - version: 7.13.0(eslint@9.4.0)(typescript@5.4.5) - - packages/getters: - dependencies: - '@penumbra-zone/bech32m': - specifier: workspace:* - version: link:../bech32m - devDependencies: - '@buf/penumbra-zone_penumbra.bufbuild_es': - specifier: 1.9.0-20240528180215-8fe1c79485f8.1 - version: 1.9.0-20240528180215-8fe1c79485f8.1(@bufbuild/protobuf@1.10.0) - '@bufbuild/protobuf': - specifier: ^1.10.0 - version: 1.10.0 - - packages/keys: {} - - packages/perspective: - dependencies: - '@penumbra-zone/bech32m': - specifier: workspace:* - version: link:../bech32m - '@penumbra-zone/getters': - specifier: workspace:* - version: link:../getters - '@penumbra-zone/types': - specifier: workspace:* - version: link:../types - '@penumbra-zone/wasm': - specifier: workspace:* - version: link:../wasm - devDependencies: - '@buf/penumbra-zone_penumbra.bufbuild_es': - specifier: 1.9.0-20240528180215-8fe1c79485f8.1 - version: 1.9.0-20240528180215-8fe1c79485f8.1(@bufbuild/protobuf@1.10.0) - - packages/polyfills: - dependencies: - array-from-async: - specifier: ^3.0.0 - version: 3.0.0 - - packages/protobuf: - dependencies: - '@buf/cosmos_ibc.bufbuild_es': - specifier: 1.9.0-20240530142100-ad4444393387.1 - version: 1.9.0-20240530142100-ad4444393387.1(@bufbuild/protobuf@1.10.0) - '@buf/cosmos_ibc.connectrpc_es': - specifier: 1.4.0-20240530142100-ad4444393387.2 - version: 1.4.0-20240530142100-ad4444393387.2(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) - '@buf/penumbra-zone_penumbra.connectrpc_es': - specifier: 1.4.0-20240528180215-8fe1c79485f8.2 - version: 1.4.0-20240528180215-8fe1c79485f8.2(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) - devDependencies: - '@bufbuild/protobuf': - specifier: ^1.10.0 - version: 1.10.0 - '@connectrpc/connect': - specifier: ^1.4.0 - version: 1.4.0(@bufbuild/protobuf@1.10.0) - - packages/query: - dependencies: - '@penumbra-zone/bech32m': - specifier: workspace:* - version: link:../bech32m - '@penumbra-zone/crypto-web': - specifier: workspace:* - version: link:../crypto - '@penumbra-zone/getters': - specifier: workspace:* - version: link:../getters - '@penumbra-zone/protobuf': - specifier: workspace:* - version: link:../protobuf - '@penumbra-zone/types': - specifier: workspace:* - version: link:../types - '@penumbra-zone/wasm': - specifier: workspace:* - version: link:../wasm - exponential-backoff: - specifier: ^3.1.1 - version: 3.1.1 - devDependencies: - '@buf/cosmos_ibc.bufbuild_es': - specifier: 1.9.0-20240530142100-ad4444393387.1 - version: 1.9.0-20240530142100-ad4444393387.1(@bufbuild/protobuf@1.10.0) - '@buf/penumbra-zone_penumbra.bufbuild_es': - specifier: 1.9.0-20240528180215-8fe1c79485f8.1 - version: 1.9.0-20240528180215-8fe1c79485f8.1(@bufbuild/protobuf@1.10.0) - '@bufbuild/protobuf': - specifier: ^1.10.0 - version: 1.10.0 - '@connectrpc/connect': - specifier: ^1.4.0 - version: 1.4.0(@bufbuild/protobuf@1.10.0) - '@connectrpc/connect-web': - specifier: ^1.4.0 - version: 1.4.0(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) - - packages/services: - dependencies: - '@penumbra-zone/bech32m': - specifier: workspace:* - version: link:../bech32m - '@penumbra-zone/crypto-web': - specifier: workspace:* - version: link:../crypto - '@penumbra-zone/getters': - specifier: workspace:* - version: link:../getters - '@penumbra-zone/perspective': - specifier: workspace:* - version: link:../perspective - '@penumbra-zone/polyfills': - specifier: workspace:* - version: link:../polyfills - '@penumbra-zone/protobuf': - specifier: workspace:* - version: link:../protobuf - '@penumbra-zone/query': - specifier: workspace:* - version: link:../query - '@penumbra-zone/services-context': - specifier: workspace:* - version: link:../services-context - '@penumbra-zone/storage': - specifier: workspace:* - version: link:../storage - '@penumbra-zone/transport-dom': - specifier: workspace:* - version: link:../transport-dom - '@penumbra-zone/types': - specifier: workspace:* - version: link:../types - '@penumbra-zone/wasm': - specifier: workspace:* - version: link:../wasm - devDependencies: - '@buf/penumbra-zone_penumbra.bufbuild_es': - specifier: 1.9.0-20240528180215-8fe1c79485f8.1 - version: 1.9.0-20240528180215-8fe1c79485f8.1(@bufbuild/protobuf@1.10.0) - '@bufbuild/protobuf': - specifier: ^1.10.0 - version: 1.10.0 - '@connectrpc/connect': - specifier: ^1.4.0 - version: 1.4.0(@bufbuild/protobuf@1.10.0) - - packages/services-context: - dependencies: - '@penumbra-labs/registry': - specifier: 8.0.1 - version: 8.0.1 - '@penumbra-zone/query': - specifier: workspace:* - version: link:../query - '@penumbra-zone/storage': - specifier: workspace:* - version: link:../storage - '@penumbra-zone/types': - specifier: workspace:* - version: link:../types - '@penumbra-zone/wasm': - specifier: workspace:* - version: link:../wasm - exponential-backoff: - specifier: ^3.1.1 - version: 3.1.1 - devDependencies: - '@buf/penumbra-zone_penumbra.bufbuild_es': - specifier: 1.9.0-20240528180215-8fe1c79485f8.1 - version: 1.9.0-20240528180215-8fe1c79485f8.1(@bufbuild/protobuf@1.10.0) - '@bufbuild/protobuf': - specifier: ^1.10.0 - version: 1.10.0 - - packages/storage: - dependencies: - '@penumbra-labs/registry': - specifier: 8.0.1 - version: 8.0.1 - '@penumbra-zone/bech32m': - specifier: workspace:* - version: link:../bech32m - '@penumbra-zone/crypto-web': - specifier: workspace:* - version: link:../crypto - '@penumbra-zone/getters': - specifier: workspace:* - version: link:../getters - idb: - specifier: ^8.0.0 - version: 8.0.0 - devDependencies: - '@buf/penumbra-zone_penumbra.bufbuild_es': - specifier: 1.9.0-20240528180215-8fe1c79485f8.1 - version: 1.9.0-20240528180215-8fe1c79485f8.1(@bufbuild/protobuf@1.10.0) - '@bufbuild/protobuf': - specifier: ^1.10.0 - version: 1.10.0 - '@penumbra-zone/polyfills': - specifier: workspace:* - version: link:../polyfills - '@penumbra-zone/types': - specifier: workspace:* - version: link:../types - '@penumbra-zone/wasm': - specifier: workspace:* - version: link:../wasm + version: 7.13.1(eslint@9.5.0)(typescript@5.4.5) packages/tailwind-config: dependencies: tailwindcss: - specifier: ^3.4.3 - version: 3.4.4(ts-node@10.9.2(@swc/core@1.5.28(@swc/helpers@0.5.11))(@types/node@20.14.2)(typescript@5.4.5)) + specifier: ^3.4.4 + version: 3.4.4(ts-node@10.9.2(@swc/core@1.6.3)(@types/node@20.14.5)(typescript@5.4.5)) tailwindcss-animate: specifier: ^1.0.7 - version: 1.0.7(tailwindcss@3.4.4(ts-node@10.9.2(@swc/core@1.5.28(@swc/helpers@0.5.11))(@types/node@20.14.2)(typescript@5.4.5))) - - packages/transport-chrome: - dependencies: - '@penumbra-zone/transport-dom': - specifier: workspace:* - version: link:../transport-dom - devDependencies: - '@bufbuild/protobuf': - specifier: ^1.10.0 - version: 1.10.0 - '@connectrpc/connect': - specifier: ^1.4.0 - version: 1.4.0(@bufbuild/protobuf@1.10.0) - - packages/transport-dom: - devDependencies: - '@buf/connectrpc_eliza.bufbuild_es': - specifier: 1.9.0-20230913231627-233fca715f49.1 - version: 1.9.0-20230913231627-233fca715f49.1(@bufbuild/protobuf@1.10.0) - '@buf/connectrpc_eliza.connectrpc_es': - specifier: 1.4.0-20230913231627-233fca715f49.2 - version: 1.4.0-20230913231627-233fca715f49.2(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) - '@bufbuild/protobuf': - specifier: ^1.10.0 - version: 1.10.0 - '@connectrpc/connect': - specifier: ^1.4.0 - version: 1.4.0(@bufbuild/protobuf@1.10.0) - '@penumbra-zone/polyfills': - specifier: workspace:* - version: link:../polyfills + version: 1.0.7(tailwindcss@3.4.4(ts-node@10.9.2(@swc/core@1.6.3)(@types/node@20.14.5)(typescript@5.4.5))) packages/tsconfig: {} - packages/types: - dependencies: - '@penumbra-zone/bech32m': - specifier: workspace:* - version: link:../bech32m - '@penumbra-zone/getters': - specifier: workspace:* - version: link:../getters - bignumber.js: - specifier: ^9.1.2 - version: 9.1.2 - idb: - specifier: ^8.0.0 - version: 8.0.0 - zod: - specifier: ^3.23.8 - version: 3.23.8 - devDependencies: - '@buf/cosmos_ibc.bufbuild_es': - specifier: 1.9.0-20240530142100-ad4444393387.1 - version: 1.9.0-20240530142100-ad4444393387.1(@bufbuild/protobuf@1.10.0) - '@buf/penumbra-zone_penumbra.bufbuild_es': - specifier: 1.9.0-20240528180215-8fe1c79485f8.1 - version: 1.9.0-20240528180215-8fe1c79485f8.1(@bufbuild/protobuf@1.10.0) - '@bufbuild/protobuf': - specifier: ^1.10.0 - version: 1.10.0 - packages/ui: dependencies: '@emotion/react': @@ -722,19 +420,22 @@ importers: version: 11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1) '@mui/material': specifier: ^5.15.18 - version: 5.15.19(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 5.15.20(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@penumbra-zone/bech32m': - specifier: workspace:* - version: link:../bech32m + specifier: ^6.1.0 + version: 6.1.0 '@penumbra-zone/getters': - specifier: workspace:* - version: link:../getters + specifier: ^8.0.0 + version: 8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240618145807-4698edb0fdb0.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))) '@penumbra-zone/perspective': - specifier: workspace:* - version: link:../perspective + specifier: ^6.0.0 + version: 6.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240618145807-4698edb0fdb0.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))))(@penumbra-zone/wasm@9.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240618145807-4698edb0fdb0.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240618145807-4698edb0fdb0.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240618145807-4698edb0fdb0.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))))) '@penumbra-zone/types': - specifier: workspace:* - version: link:../types + specifier: ^9.0.0 + version: 9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240618145807-4698edb0fdb0.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240618145807-4698edb0fdb0.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))) + '@penumbra-zone/wasm': + specifier: ^9.0.0 + version: 9.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240618145807-4698edb0fdb0.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240618145807-4698edb0fdb0.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240618145807-4698edb0fdb0.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))))) '@radix-ui/react-avatar': specifier: ^1.0.4 version: 1.0.4(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -782,10 +483,10 @@ importers: version: 1.0.7(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@testing-library/jest-dom': specifier: ^6.4.5 - version: 6.4.6(vitest@1.6.0(@types/node@20.14.2)(@vitest/browser@1.6.0(playwright@1.44.1)(vitest@1.6.0))(jsdom@24.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(terser@5.31.1)) + version: 6.4.6(vitest@1.6.0(@types/node@20.14.5)(@vitest/browser@1.6.0(playwright@1.44.1)(vitest@1.6.0))(jsdom@24.1.0)(terser@5.31.1)) '@textea/json-viewer': specifier: ^3.4.1 - version: 3.4.1(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@mui/material@5.15.19(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@types/react@18.3.3)(immer@10.1.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 3.4.1(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@mui/material@5.15.20(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@types/react@18.3.3)(immer@10.1.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@visx/axis': specifier: ^3.10.1 version: 3.10.1(react@18.3.1) @@ -816,6 +517,9 @@ importers: '@visx/tooltip': specifier: ^3.3.0 version: 3.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + bignumber.js: + specifier: ^9.1.2 + version: 9.1.2 class-variance-authority: specifier: ^0.7.0 version: 0.7.0 @@ -857,35 +561,35 @@ importers: version: 1.6.0 devDependencies: '@buf/penumbra-zone_penumbra.bufbuild_es': - specifier: 1.9.0-20240528180215-8fe1c79485f8.1 - version: 1.9.0-20240528180215-8fe1c79485f8.1(@bufbuild/protobuf@1.10.0) + specifier: 1.10.0-20240616005217-ca45ca80333e.1 + version: 1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0) '@bufbuild/protobuf': specifier: ^1.10.0 version: 1.10.0 '@storybook/addon-essentials': specifier: ^8.1.1 - version: 8.1.6(@types/react-dom@18.3.0)(@types/react@18.3.3)(encoding@0.1.13)(prettier@3.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 8.1.10(@types/react-dom@18.3.0)(@types/react@18.3.3)(encoding@0.1.13)(prettier@3.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@storybook/addon-interactions': specifier: ^8.1.1 - version: 8.1.6(vitest@1.6.0(@types/node@20.14.2)(@vitest/browser@1.6.0(playwright@1.44.1)(vitest@1.6.0))(jsdom@24.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(terser@5.31.1)) + version: 8.1.10(vitest@1.6.0(@types/node@20.14.5)(@vitest/browser@1.6.0(playwright@1.44.1)(vitest@1.6.0))(jsdom@24.1.0)(terser@5.31.1)) '@storybook/addon-links': specifier: ^8.1.1 - version: 8.1.6(react@18.3.1) + version: 8.1.10(react@18.3.1) '@storybook/addon-postcss': specifier: ^2.0.0 - version: 2.0.0(webpack@5.92.0(@swc/core@1.5.28(@swc/helpers@0.5.11))(esbuild@0.20.2)) + version: 2.0.0(webpack@5.92.0(@swc/core@1.6.3)(esbuild@0.20.2)) '@storybook/blocks': specifier: ^8.1.1 - version: 8.1.6(@types/react-dom@18.3.0)(@types/react@18.3.3)(encoding@0.1.13)(prettier@3.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 8.1.10(@types/react-dom@18.3.0)(@types/react@18.3.3)(encoding@0.1.13)(prettier@3.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@storybook/preview-api': specifier: ^8.1.1 - version: 8.1.6 + version: 8.1.10 '@storybook/react': specifier: ^8.1.1 - version: 8.1.6(encoding@0.1.13)(prettier@3.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5) + version: 8.1.10(encoding@0.1.13)(prettier@3.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5) '@storybook/react-vite': specifier: 8.1.1 - version: 8.1.1(encoding@0.1.13)(prettier@3.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.18.0)(typescript@5.4.5)(vite@5.2.13(@types/node@20.14.2)(terser@5.31.1)) + version: 8.1.1(encoding@0.1.13)(prettier@3.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.18.0)(typescript@5.4.5)(vite@5.3.1(@types/node@20.14.5)(terser@5.31.1)) '@testing-library/react': specifier: ^15.0.7 version: 15.0.7(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -906,7 +610,7 @@ importers: version: 10.4.19(postcss@8.4.38) eslint-plugin-storybook: specifier: ^0.8.0 - version: 0.8.0(eslint@9.4.0)(typescript@5.4.5) + version: 0.8.0(eslint@9.5.0)(typescript@5.4.5) postcss: specifier: ^8.4.38 version: 8.4.38 @@ -918,55 +622,10 @@ importers: version: 18.3.1 storybook: specifier: ^8.1.1 - version: 8.1.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(utf-8-validate@6.0.4) + version: 8.1.10(@babel/preset-env@7.24.7(@babel/core@7.24.7))(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) tailwindcss: - specifier: ^3.4.3 - version: 3.4.4(ts-node@10.9.2(@swc/core@1.5.28(@swc/helpers@0.5.11))(@types/node@20.14.2)(typescript@5.4.5)) - - packages/wasm: - dependencies: - '@penumbra-zone/protobuf': - specifier: workspace:* - version: link:../protobuf - '@penumbra-zone/types': - specifier: workspace:* - version: link:../types - zod: - specifier: ^3.23.8 - version: 3.23.8 - optionalDependencies: - '@penumbra-zone/keys': - specifier: workspace:* - version: link:../keys - devDependencies: - '@buf/penumbra-zone_penumbra.bufbuild_es': - specifier: 1.9.0-20240528180215-8fe1c79485f8.1 - version: 1.9.0-20240528180215-8fe1c79485f8.1(@bufbuild/protobuf@1.10.0) - '@bufbuild/protobuf': - specifier: ^1.10.0 - version: 1.10.0 - '@penumbra-zone/bech32m': - specifier: workspace:* - version: link:../bech32m - fake-indexeddb: - specifier: ^6.0.0 - version: 6.0.0 - - packages/zquery: - dependencies: - react: - specifier: ^18.3.1 - version: 18.3.1 - zustand: - specifier: ^4.5.2 - version: 4.5.2(@types/react@18.3.3)(immer@10.1.1)(react@18.3.1) - devDependencies: - '@types/react': - specifier: ^18.3.2 - version: 18.3.3 - vitest: - specifier: ^1.6.0 - version: 1.6.0(@types/node@20.14.2)(@vitest/browser@1.6.0(playwright@1.44.1)(vitest@1.6.0))(jsdom@24.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(terser@5.31.1) + specifier: ^3.4.4 + version: 3.4.4(ts-node@10.9.2(@swc/core@1.6.3)(@types/node@20.14.5)(typescript@5.4.5)) packages: @@ -1492,18 +1151,6 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-react-jsx-self@7.24.7': - resolution: {integrity: sha512-fOPQYbGSgH0HUp4UJO4sMBFjY6DuWq+2i8rixyUMb3CdGixs/gccURvYOAhajBdKDoGajFr3mUq5rH3phtkGzw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-react-jsx-source@7.24.7': - resolution: {integrity: sha512-J2z+MWzZHVOemyLweMqngXrgGC42jQ//R0KdxqkIz/OrbVIIlhFI3WigZ5fO+nwFvBlncr4MGapd8vTyc7RPNQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-regenerator@7.24.7': resolution: {integrity: sha512-lq3fvXPdimDrlg6LWBoqj+r/DEWgONuwjuOuQCSYgRroXDH/IdM1C0IZf59fL5cHLpjEH/O6opIRBbqv7ELnuA==} engines: {node: '>=6.9.0'} @@ -1631,205 +1278,230 @@ packages: '@base2/pretty-print-object@1.0.1': resolution: {integrity: sha512-4iri8i1AqYHJE2DstZYkyEprg6Pq6sKx3xn5FpySk9sNhH7qN2LLlHJCfDTZRILNwQNPD7mATWM0TBui7uC1pA==} - '@buf/connectrpc_eliza.bufbuild_es@1.7.2-20230913231627-233fca715f49.1': - resolution: {tarball: https://buf.build/gen/npm/v1/@buf/connectrpc_eliza.bufbuild_es/-/connectrpc_eliza.bufbuild_es-1.7.2-20230913231627-233fca715f49.1.tgz} + '@buf/connectrpc_eliza.bufbuild_es@1.10.0-20230913231627-233fca715f49.1': + resolution: {tarball: https://buf.build/gen/npm/v1/@buf/connectrpc_eliza.bufbuild_es/-/connectrpc_eliza.bufbuild_es-1.10.0-20230913231627-233fca715f49.1.tgz} peerDependencies: - '@bufbuild/protobuf': ^1.7.2 + '@bufbuild/protobuf': ^1.10.0 - '@buf/connectrpc_eliza.bufbuild_es@1.9.0-20230913231627-233fca715f49.1': - resolution: {tarball: https://buf.build/gen/npm/v1/@buf/connectrpc_eliza.bufbuild_es/-/connectrpc_eliza.bufbuild_es-1.9.0-20230913231627-233fca715f49.1.tgz} + '@buf/connectrpc_eliza.bufbuild_es@1.7.2-20230913231627-233fca715f49.2': + resolution: {tarball: https://buf.build/gen/npm/v1/@buf/connectrpc_eliza.bufbuild_es/-/connectrpc_eliza.bufbuild_es-1.7.2-20230913231627-233fca715f49.2.tgz} peerDependencies: - '@bufbuild/protobuf': ^1.9.0 + '@bufbuild/protobuf': ^1.7.2 - '@buf/connectrpc_eliza.connectrpc_es@1.4.0-20230913231627-233fca715f49.2': - resolution: {tarball: https://buf.build/gen/npm/v1/@buf/connectrpc_eliza.connectrpc_es/-/connectrpc_eliza.connectrpc_es-1.4.0-20230913231627-233fca715f49.2.tgz} + '@buf/connectrpc_eliza.connectrpc_es@1.4.0-20230913231627-233fca715f49.3': + resolution: {tarball: https://buf.build/gen/npm/v1/@buf/connectrpc_eliza.connectrpc_es/-/connectrpc_eliza.connectrpc_es-1.4.0-20230913231627-233fca715f49.3.tgz} peerDependencies: '@connectrpc/connect': ^1.4.0 - '@buf/cosmos_cosmos-proto.bufbuild_es@1.7.2-20211202220400-1935555c206d.1': - resolution: {tarball: https://buf.build/gen/npm/v1/@buf/cosmos_cosmos-proto.bufbuild_es/-/cosmos_cosmos-proto.bufbuild_es-1.7.2-20211202220400-1935555c206d.1.tgz} + '@buf/cosmos_cosmos-proto.bufbuild_es@1.10.0-20211202220400-1935555c206d.1': + resolution: {tarball: https://buf.build/gen/npm/v1/@buf/cosmos_cosmos-proto.bufbuild_es/-/cosmos_cosmos-proto.bufbuild_es-1.10.0-20211202220400-1935555c206d.1.tgz} peerDependencies: - '@bufbuild/protobuf': ^1.7.2 + '@bufbuild/protobuf': ^1.10.0 - '@buf/cosmos_cosmos-proto.bufbuild_es@1.9.0-20211202220400-1935555c206d.1': - resolution: {tarball: https://buf.build/gen/npm/v1/@buf/cosmos_cosmos-proto.bufbuild_es/-/cosmos_cosmos-proto.bufbuild_es-1.9.0-20211202220400-1935555c206d.1.tgz} + '@buf/cosmos_cosmos-proto.bufbuild_es@1.7.2-20211202220400-1935555c206d.2': + resolution: {tarball: https://buf.build/gen/npm/v1/@buf/cosmos_cosmos-proto.bufbuild_es/-/cosmos_cosmos-proto.bufbuild_es-1.7.2-20211202220400-1935555c206d.2.tgz} peerDependencies: - '@bufbuild/protobuf': ^1.9.0 + '@bufbuild/protobuf': ^1.7.2 - '@buf/cosmos_cosmos-proto.connectrpc_es@1.4.0-20211202220400-1935555c206d.2': - resolution: {tarball: https://buf.build/gen/npm/v1/@buf/cosmos_cosmos-proto.connectrpc_es/-/cosmos_cosmos-proto.connectrpc_es-1.4.0-20211202220400-1935555c206d.2.tgz} + '@buf/cosmos_cosmos-proto.connectrpc_es@1.4.0-20211202220400-1935555c206d.3': + resolution: {tarball: https://buf.build/gen/npm/v1/@buf/cosmos_cosmos-proto.connectrpc_es/-/cosmos_cosmos-proto.connectrpc_es-1.4.0-20211202220400-1935555c206d.3.tgz} peerDependencies: '@connectrpc/connect': ^1.4.0 - '@buf/cosmos_cosmos-sdk.bufbuild_es@1.7.2-20230522115704-e7a85cef453e.1': - resolution: {tarball: https://buf.build/gen/npm/v1/@buf/cosmos_cosmos-sdk.bufbuild_es/-/cosmos_cosmos-sdk.bufbuild_es-1.7.2-20230522115704-e7a85cef453e.1.tgz} + '@buf/cosmos_cosmos-sdk.bufbuild_es@1.10.0-20230522115704-e7a85cef453e.1': + resolution: {tarball: https://buf.build/gen/npm/v1/@buf/cosmos_cosmos-sdk.bufbuild_es/-/cosmos_cosmos-sdk.bufbuild_es-1.10.0-20230522115704-e7a85cef453e.1.tgz} peerDependencies: - '@bufbuild/protobuf': ^1.7.2 + '@bufbuild/protobuf': ^1.10.0 - '@buf/cosmos_cosmos-sdk.bufbuild_es@1.7.2-20230719110346-aa25660f4ff7.1': - resolution: {tarball: https://buf.build/gen/npm/v1/@buf/cosmos_cosmos-sdk.bufbuild_es/-/cosmos_cosmos-sdk.bufbuild_es-1.7.2-20230719110346-aa25660f4ff7.1.tgz} + '@buf/cosmos_cosmos-sdk.bufbuild_es@1.10.0-20230719110346-aa25660f4ff7.1': + resolution: {tarball: https://buf.build/gen/npm/v1/@buf/cosmos_cosmos-sdk.bufbuild_es/-/cosmos_cosmos-sdk.bufbuild_es-1.10.0-20230719110346-aa25660f4ff7.1.tgz} peerDependencies: - '@bufbuild/protobuf': ^1.7.2 + '@bufbuild/protobuf': ^1.10.0 - '@buf/cosmos_cosmos-sdk.bufbuild_es@1.9.0-20230522115704-e7a85cef453e.1': - resolution: {tarball: https://buf.build/gen/npm/v1/@buf/cosmos_cosmos-sdk.bufbuild_es/-/cosmos_cosmos-sdk.bufbuild_es-1.9.0-20230522115704-e7a85cef453e.1.tgz} + '@buf/cosmos_cosmos-sdk.bufbuild_es@1.7.2-20230522115704-e7a85cef453e.2': + resolution: {tarball: https://buf.build/gen/npm/v1/@buf/cosmos_cosmos-sdk.bufbuild_es/-/cosmos_cosmos-sdk.bufbuild_es-1.7.2-20230522115704-e7a85cef453e.2.tgz} peerDependencies: - '@bufbuild/protobuf': ^1.9.0 + '@bufbuild/protobuf': ^1.7.2 - '@buf/cosmos_cosmos-sdk.bufbuild_es@1.9.0-20230719110346-aa25660f4ff7.1': - resolution: {tarball: https://buf.build/gen/npm/v1/@buf/cosmos_cosmos-sdk.bufbuild_es/-/cosmos_cosmos-sdk.bufbuild_es-1.9.0-20230719110346-aa25660f4ff7.1.tgz} + '@buf/cosmos_cosmos-sdk.bufbuild_es@1.7.2-20230719110346-aa25660f4ff7.2': + resolution: {tarball: https://buf.build/gen/npm/v1/@buf/cosmos_cosmos-sdk.bufbuild_es/-/cosmos_cosmos-sdk.bufbuild_es-1.7.2-20230719110346-aa25660f4ff7.2.tgz} peerDependencies: - '@bufbuild/protobuf': ^1.9.0 + '@bufbuild/protobuf': ^1.7.2 - '@buf/cosmos_cosmos-sdk.connectrpc_es@1.4.0-20230522115704-e7a85cef453e.2': - resolution: {tarball: https://buf.build/gen/npm/v1/@buf/cosmos_cosmos-sdk.connectrpc_es/-/cosmos_cosmos-sdk.connectrpc_es-1.4.0-20230522115704-e7a85cef453e.2.tgz} + '@buf/cosmos_cosmos-sdk.connectrpc_es@1.4.0-20230522115704-e7a85cef453e.3': + resolution: {tarball: https://buf.build/gen/npm/v1/@buf/cosmos_cosmos-sdk.connectrpc_es/-/cosmos_cosmos-sdk.connectrpc_es-1.4.0-20230522115704-e7a85cef453e.3.tgz} peerDependencies: '@connectrpc/connect': ^1.4.0 - '@buf/cosmos_cosmos-sdk.connectrpc_es@1.4.0-20230719110346-aa25660f4ff7.2': - resolution: {tarball: https://buf.build/gen/npm/v1/@buf/cosmos_cosmos-sdk.connectrpc_es/-/cosmos_cosmos-sdk.connectrpc_es-1.4.0-20230719110346-aa25660f4ff7.2.tgz} + '@buf/cosmos_cosmos-sdk.connectrpc_es@1.4.0-20230719110346-aa25660f4ff7.3': + resolution: {tarball: https://buf.build/gen/npm/v1/@buf/cosmos_cosmos-sdk.connectrpc_es/-/cosmos_cosmos-sdk.connectrpc_es-1.4.0-20230719110346-aa25660f4ff7.3.tgz} peerDependencies: '@connectrpc/connect': ^1.4.0 - '@buf/cosmos_gogo-proto.bufbuild_es@1.7.2-20221020125208-34d970b699f8.1': - resolution: {tarball: https://buf.build/gen/npm/v1/@buf/cosmos_gogo-proto.bufbuild_es/-/cosmos_gogo-proto.bufbuild_es-1.7.2-20221020125208-34d970b699f8.1.tgz} + '@buf/cosmos_gogo-proto.bufbuild_es@1.10.0-20221020125208-34d970b699f8.1': + resolution: {tarball: https://buf.build/gen/npm/v1/@buf/cosmos_gogo-proto.bufbuild_es/-/cosmos_gogo-proto.bufbuild_es-1.10.0-20221020125208-34d970b699f8.1.tgz} peerDependencies: - '@bufbuild/protobuf': ^1.7.2 + '@bufbuild/protobuf': ^1.10.0 - '@buf/cosmos_gogo-proto.bufbuild_es@1.7.2-20230509103710-5e5b9fdd0180.1': - resolution: {tarball: https://buf.build/gen/npm/v1/@buf/cosmos_gogo-proto.bufbuild_es/-/cosmos_gogo-proto.bufbuild_es-1.7.2-20230509103710-5e5b9fdd0180.1.tgz} + '@buf/cosmos_gogo-proto.bufbuild_es@1.10.0-20230509103710-5e5b9fdd0180.1': + resolution: {tarball: https://buf.build/gen/npm/v1/@buf/cosmos_gogo-proto.bufbuild_es/-/cosmos_gogo-proto.bufbuild_es-1.10.0-20230509103710-5e5b9fdd0180.1.tgz} peerDependencies: - '@bufbuild/protobuf': ^1.7.2 + '@bufbuild/protobuf': ^1.10.0 - '@buf/cosmos_gogo-proto.bufbuild_es@1.9.0-20221020125208-34d970b699f8.1': - resolution: {tarball: https://buf.build/gen/npm/v1/@buf/cosmos_gogo-proto.bufbuild_es/-/cosmos_gogo-proto.bufbuild_es-1.9.0-20221020125208-34d970b699f8.1.tgz} + '@buf/cosmos_gogo-proto.bufbuild_es@1.7.2-20221020125208-34d970b699f8.2': + resolution: {tarball: https://buf.build/gen/npm/v1/@buf/cosmos_gogo-proto.bufbuild_es/-/cosmos_gogo-proto.bufbuild_es-1.7.2-20221020125208-34d970b699f8.2.tgz} peerDependencies: - '@bufbuild/protobuf': ^1.9.0 + '@bufbuild/protobuf': ^1.7.2 - '@buf/cosmos_gogo-proto.bufbuild_es@1.9.0-20230509103710-5e5b9fdd0180.1': - resolution: {tarball: https://buf.build/gen/npm/v1/@buf/cosmos_gogo-proto.bufbuild_es/-/cosmos_gogo-proto.bufbuild_es-1.9.0-20230509103710-5e5b9fdd0180.1.tgz} + '@buf/cosmos_gogo-proto.bufbuild_es@1.7.2-20230509103710-5e5b9fdd0180.2': + resolution: {tarball: https://buf.build/gen/npm/v1/@buf/cosmos_gogo-proto.bufbuild_es/-/cosmos_gogo-proto.bufbuild_es-1.7.2-20230509103710-5e5b9fdd0180.2.tgz} peerDependencies: - '@bufbuild/protobuf': ^1.9.0 + '@bufbuild/protobuf': ^1.7.2 - '@buf/cosmos_gogo-proto.connectrpc_es@1.4.0-20221020125208-34d970b699f8.2': - resolution: {tarball: https://buf.build/gen/npm/v1/@buf/cosmos_gogo-proto.connectrpc_es/-/cosmos_gogo-proto.connectrpc_es-1.4.0-20221020125208-34d970b699f8.2.tgz} + '@buf/cosmos_gogo-proto.connectrpc_es@1.4.0-20221020125208-34d970b699f8.3': + resolution: {tarball: https://buf.build/gen/npm/v1/@buf/cosmos_gogo-proto.connectrpc_es/-/cosmos_gogo-proto.connectrpc_es-1.4.0-20221020125208-34d970b699f8.3.tgz} peerDependencies: '@connectrpc/connect': ^1.4.0 - '@buf/cosmos_gogo-proto.connectrpc_es@1.4.0-20230509103710-5e5b9fdd0180.2': - resolution: {tarball: https://buf.build/gen/npm/v1/@buf/cosmos_gogo-proto.connectrpc_es/-/cosmos_gogo-proto.connectrpc_es-1.4.0-20230509103710-5e5b9fdd0180.2.tgz} + '@buf/cosmos_gogo-proto.connectrpc_es@1.4.0-20230509103710-5e5b9fdd0180.3': + resolution: {tarball: https://buf.build/gen/npm/v1/@buf/cosmos_gogo-proto.connectrpc_es/-/cosmos_gogo-proto.connectrpc_es-1.4.0-20230509103710-5e5b9fdd0180.3.tgz} peerDependencies: '@connectrpc/connect': ^1.4.0 - '@buf/cosmos_ibc.bufbuild_es@1.7.2-20230913112312-7ab44ae956a0.1': - resolution: {tarball: https://buf.build/gen/npm/v1/@buf/cosmos_ibc.bufbuild_es/-/cosmos_ibc.bufbuild_es-1.7.2-20230913112312-7ab44ae956a0.1.tgz} + '@buf/cosmos_ibc.bufbuild_es@1.10.0-20230913112312-7ab44ae956a0.1': + resolution: {tarball: https://buf.build/gen/npm/v1/@buf/cosmos_ibc.bufbuild_es/-/cosmos_ibc.bufbuild_es-1.10.0-20230913112312-7ab44ae956a0.1.tgz} + peerDependencies: + '@bufbuild/protobuf': ^1.10.0 + + '@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1': + resolution: {tarball: https://buf.build/gen/npm/v1/@buf/cosmos_ibc.bufbuild_es/-/cosmos_ibc.bufbuild_es-1.10.0-20240606104028-442292b00c16.1.tgz} + peerDependencies: + '@bufbuild/protobuf': ^1.10.0 + + '@buf/cosmos_ibc.bufbuild_es@1.10.0-20240618145807-4698edb0fdb0.1': + resolution: {tarball: https://buf.build/gen/npm/v1/@buf/cosmos_ibc.bufbuild_es/-/cosmos_ibc.bufbuild_es-1.10.0-20240618145807-4698edb0fdb0.1.tgz} + peerDependencies: + '@bufbuild/protobuf': ^1.10.0 + + '@buf/cosmos_ibc.bufbuild_es@1.7.2-20230913112312-7ab44ae956a0.2': + resolution: {tarball: https://buf.build/gen/npm/v1/@buf/cosmos_ibc.bufbuild_es/-/cosmos_ibc.bufbuild_es-1.7.2-20230913112312-7ab44ae956a0.2.tgz} peerDependencies: '@bufbuild/protobuf': ^1.7.2 - '@buf/cosmos_ibc.bufbuild_es@1.7.2-20240530142100-ad4444393387.1': - resolution: {tarball: https://buf.build/gen/npm/v1/@buf/cosmos_ibc.bufbuild_es/-/cosmos_ibc.bufbuild_es-1.7.2-20240530142100-ad4444393387.1.tgz} + '@buf/cosmos_ibc.bufbuild_es@1.7.2-20240606104028-442292b00c16.2': + resolution: {tarball: https://buf.build/gen/npm/v1/@buf/cosmos_ibc.bufbuild_es/-/cosmos_ibc.bufbuild_es-1.7.2-20240606104028-442292b00c16.2.tgz} peerDependencies: '@bufbuild/protobuf': ^1.7.2 - '@buf/cosmos_ibc.bufbuild_es@1.9.0-20230913112312-7ab44ae956a0.1': - resolution: {tarball: https://buf.build/gen/npm/v1/@buf/cosmos_ibc.bufbuild_es/-/cosmos_ibc.bufbuild_es-1.9.0-20230913112312-7ab44ae956a0.1.tgz} + '@buf/cosmos_ibc.bufbuild_es@1.7.2-20240618145807-4698edb0fdb0.2': + resolution: {tarball: https://buf.build/gen/npm/v1/@buf/cosmos_ibc.bufbuild_es/-/cosmos_ibc.bufbuild_es-1.7.2-20240618145807-4698edb0fdb0.2.tgz} peerDependencies: - '@bufbuild/protobuf': ^1.9.0 + '@bufbuild/protobuf': ^1.7.2 - '@buf/cosmos_ibc.bufbuild_es@1.9.0-20240530142100-ad4444393387.1': - resolution: {tarball: https://buf.build/gen/npm/v1/@buf/cosmos_ibc.bufbuild_es/-/cosmos_ibc.bufbuild_es-1.9.0-20240530142100-ad4444393387.1.tgz} + '@buf/cosmos_ibc.connectrpc_es@1.4.0-20230913112312-7ab44ae956a0.3': + resolution: {tarball: https://buf.build/gen/npm/v1/@buf/cosmos_ibc.connectrpc_es/-/cosmos_ibc.connectrpc_es-1.4.0-20230913112312-7ab44ae956a0.3.tgz} peerDependencies: - '@bufbuild/protobuf': ^1.9.0 + '@connectrpc/connect': ^1.4.0 - '@buf/cosmos_ibc.connectrpc_es@1.4.0-20230913112312-7ab44ae956a0.2': - resolution: {tarball: https://buf.build/gen/npm/v1/@buf/cosmos_ibc.connectrpc_es/-/cosmos_ibc.connectrpc_es-1.4.0-20230913112312-7ab44ae956a0.2.tgz} + '@buf/cosmos_ibc.connectrpc_es@1.4.0-20240606104028-442292b00c16.3': + resolution: {tarball: https://buf.build/gen/npm/v1/@buf/cosmos_ibc.connectrpc_es/-/cosmos_ibc.connectrpc_es-1.4.0-20240606104028-442292b00c16.3.tgz} peerDependencies: '@connectrpc/connect': ^1.4.0 - '@buf/cosmos_ibc.connectrpc_es@1.4.0-20240530142100-ad4444393387.2': - resolution: {tarball: https://buf.build/gen/npm/v1/@buf/cosmos_ibc.connectrpc_es/-/cosmos_ibc.connectrpc_es-1.4.0-20240530142100-ad4444393387.2.tgz} + '@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3': + resolution: {tarball: https://buf.build/gen/npm/v1/@buf/cosmos_ibc.connectrpc_es/-/cosmos_ibc.connectrpc_es-1.4.0-20240618145807-4698edb0fdb0.3.tgz} peerDependencies: '@connectrpc/connect': ^1.4.0 - '@buf/cosmos_ics23.bufbuild_es@1.7.2-20221207100654-55085f7c710a.1': - resolution: {tarball: https://buf.build/gen/npm/v1/@buf/cosmos_ics23.bufbuild_es/-/cosmos_ics23.bufbuild_es-1.7.2-20221207100654-55085f7c710a.1.tgz} + '@buf/cosmos_ics23.bufbuild_es@1.10.0-20221207100654-55085f7c710a.1': + resolution: {tarball: https://buf.build/gen/npm/v1/@buf/cosmos_ics23.bufbuild_es/-/cosmos_ics23.bufbuild_es-1.10.0-20221207100654-55085f7c710a.1.tgz} peerDependencies: - '@bufbuild/protobuf': ^1.7.2 + '@bufbuild/protobuf': ^1.10.0 - '@buf/cosmos_ics23.bufbuild_es@1.9.0-20221207100654-55085f7c710a.1': - resolution: {tarball: https://buf.build/gen/npm/v1/@buf/cosmos_ics23.bufbuild_es/-/cosmos_ics23.bufbuild_es-1.9.0-20221207100654-55085f7c710a.1.tgz} + '@buf/cosmos_ics23.bufbuild_es@1.7.2-20221207100654-55085f7c710a.2': + resolution: {tarball: https://buf.build/gen/npm/v1/@buf/cosmos_ics23.bufbuild_es/-/cosmos_ics23.bufbuild_es-1.7.2-20221207100654-55085f7c710a.2.tgz} peerDependencies: - '@bufbuild/protobuf': ^1.9.0 + '@bufbuild/protobuf': ^1.7.2 - '@buf/cosmos_ics23.connectrpc_es@1.4.0-20221207100654-55085f7c710a.2': - resolution: {tarball: https://buf.build/gen/npm/v1/@buf/cosmos_ics23.connectrpc_es/-/cosmos_ics23.connectrpc_es-1.4.0-20221207100654-55085f7c710a.2.tgz} + '@buf/cosmos_ics23.connectrpc_es@1.4.0-20221207100654-55085f7c710a.3': + resolution: {tarball: https://buf.build/gen/npm/v1/@buf/cosmos_ics23.connectrpc_es/-/cosmos_ics23.connectrpc_es-1.4.0-20221207100654-55085f7c710a.3.tgz} peerDependencies: '@connectrpc/connect': ^1.4.0 - '@buf/googleapis_googleapis.bufbuild_es@1.7.2-20220908150232-8d7204855ec1.1': - resolution: {tarball: https://buf.build/gen/npm/v1/@buf/googleapis_googleapis.bufbuild_es/-/googleapis_googleapis.bufbuild_es-1.7.2-20220908150232-8d7204855ec1.1.tgz} + '@buf/googleapis_googleapis.bufbuild_es@1.10.0-20220908150232-8d7204855ec1.1': + resolution: {tarball: https://buf.build/gen/npm/v1/@buf/googleapis_googleapis.bufbuild_es/-/googleapis_googleapis.bufbuild_es-1.10.0-20220908150232-8d7204855ec1.1.tgz} peerDependencies: - '@bufbuild/protobuf': ^1.7.2 + '@bufbuild/protobuf': ^1.10.0 - '@buf/googleapis_googleapis.bufbuild_es@1.7.2-20221214150216-75b4300737fb.1': - resolution: {tarball: https://buf.build/gen/npm/v1/@buf/googleapis_googleapis.bufbuild_es/-/googleapis_googleapis.bufbuild_es-1.7.2-20221214150216-75b4300737fb.1.tgz} + '@buf/googleapis_googleapis.bufbuild_es@1.10.0-20221214150216-75b4300737fb.1': + resolution: {tarball: https://buf.build/gen/npm/v1/@buf/googleapis_googleapis.bufbuild_es/-/googleapis_googleapis.bufbuild_es-1.10.0-20221214150216-75b4300737fb.1.tgz} peerDependencies: - '@bufbuild/protobuf': ^1.7.2 + '@bufbuild/protobuf': ^1.10.0 - '@buf/googleapis_googleapis.bufbuild_es@1.7.2-20230502210827-cc916c318597.1': - resolution: {tarball: https://buf.build/gen/npm/v1/@buf/googleapis_googleapis.bufbuild_es/-/googleapis_googleapis.bufbuild_es-1.7.2-20230502210827-cc916c318597.1.tgz} + '@buf/googleapis_googleapis.bufbuild_es@1.10.0-20230502210827-cc916c318597.1': + resolution: {tarball: https://buf.build/gen/npm/v1/@buf/googleapis_googleapis.bufbuild_es/-/googleapis_googleapis.bufbuild_es-1.10.0-20230502210827-cc916c318597.1.tgz} peerDependencies: - '@bufbuild/protobuf': ^1.7.2 + '@bufbuild/protobuf': ^1.10.0 - '@buf/googleapis_googleapis.bufbuild_es@1.9.0-20220908150232-8d7204855ec1.1': - resolution: {tarball: https://buf.build/gen/npm/v1/@buf/googleapis_googleapis.bufbuild_es/-/googleapis_googleapis.bufbuild_es-1.9.0-20220908150232-8d7204855ec1.1.tgz} + '@buf/googleapis_googleapis.bufbuild_es@1.7.2-20220908150232-8d7204855ec1.2': + resolution: {tarball: https://buf.build/gen/npm/v1/@buf/googleapis_googleapis.bufbuild_es/-/googleapis_googleapis.bufbuild_es-1.7.2-20220908150232-8d7204855ec1.2.tgz} peerDependencies: - '@bufbuild/protobuf': ^1.9.0 + '@bufbuild/protobuf': ^1.7.2 - '@buf/googleapis_googleapis.bufbuild_es@1.9.0-20221214150216-75b4300737fb.1': - resolution: {tarball: https://buf.build/gen/npm/v1/@buf/googleapis_googleapis.bufbuild_es/-/googleapis_googleapis.bufbuild_es-1.9.0-20221214150216-75b4300737fb.1.tgz} + '@buf/googleapis_googleapis.bufbuild_es@1.7.2-20221214150216-75b4300737fb.2': + resolution: {tarball: https://buf.build/gen/npm/v1/@buf/googleapis_googleapis.bufbuild_es/-/googleapis_googleapis.bufbuild_es-1.7.2-20221214150216-75b4300737fb.2.tgz} peerDependencies: - '@bufbuild/protobuf': ^1.9.0 + '@bufbuild/protobuf': ^1.7.2 - '@buf/googleapis_googleapis.bufbuild_es@1.9.0-20230502210827-cc916c318597.1': - resolution: {tarball: https://buf.build/gen/npm/v1/@buf/googleapis_googleapis.bufbuild_es/-/googleapis_googleapis.bufbuild_es-1.9.0-20230502210827-cc916c318597.1.tgz} + '@buf/googleapis_googleapis.bufbuild_es@1.7.2-20230502210827-cc916c318597.2': + resolution: {tarball: https://buf.build/gen/npm/v1/@buf/googleapis_googleapis.bufbuild_es/-/googleapis_googleapis.bufbuild_es-1.7.2-20230502210827-cc916c318597.2.tgz} peerDependencies: - '@bufbuild/protobuf': ^1.9.0 + '@bufbuild/protobuf': ^1.7.2 - '@buf/googleapis_googleapis.connectrpc_es@1.4.0-20220908150232-8d7204855ec1.2': - resolution: {tarball: https://buf.build/gen/npm/v1/@buf/googleapis_googleapis.connectrpc_es/-/googleapis_googleapis.connectrpc_es-1.4.0-20220908150232-8d7204855ec1.2.tgz} + '@buf/googleapis_googleapis.connectrpc_es@1.4.0-20220908150232-8d7204855ec1.3': + resolution: {tarball: https://buf.build/gen/npm/v1/@buf/googleapis_googleapis.connectrpc_es/-/googleapis_googleapis.connectrpc_es-1.4.0-20220908150232-8d7204855ec1.3.tgz} peerDependencies: '@connectrpc/connect': ^1.4.0 - '@buf/googleapis_googleapis.connectrpc_es@1.4.0-20221214150216-75b4300737fb.2': - resolution: {tarball: https://buf.build/gen/npm/v1/@buf/googleapis_googleapis.connectrpc_es/-/googleapis_googleapis.connectrpc_es-1.4.0-20221214150216-75b4300737fb.2.tgz} + '@buf/googleapis_googleapis.connectrpc_es@1.4.0-20221214150216-75b4300737fb.3': + resolution: {tarball: https://buf.build/gen/npm/v1/@buf/googleapis_googleapis.connectrpc_es/-/googleapis_googleapis.connectrpc_es-1.4.0-20221214150216-75b4300737fb.3.tgz} peerDependencies: '@connectrpc/connect': ^1.4.0 - '@buf/googleapis_googleapis.connectrpc_es@1.4.0-20230502210827-cc916c318597.2': - resolution: {tarball: https://buf.build/gen/npm/v1/@buf/googleapis_googleapis.connectrpc_es/-/googleapis_googleapis.connectrpc_es-1.4.0-20230502210827-cc916c318597.2.tgz} + '@buf/googleapis_googleapis.connectrpc_es@1.4.0-20230502210827-cc916c318597.3': + resolution: {tarball: https://buf.build/gen/npm/v1/@buf/googleapis_googleapis.connectrpc_es/-/googleapis_googleapis.connectrpc_es-1.4.0-20230502210827-cc916c318597.3.tgz} peerDependencies: '@connectrpc/connect': ^1.4.0 - '@buf/penumbra-zone_penumbra.bufbuild_es@1.7.2-20240528180215-8fe1c79485f8.1': - resolution: {tarball: https://buf.build/gen/npm/v1/@buf/penumbra-zone_penumbra.bufbuild_es/-/penumbra-zone_penumbra.bufbuild_es-1.7.2-20240528180215-8fe1c79485f8.1.tgz} + '@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1': + resolution: {tarball: https://buf.build/gen/npm/v1/@buf/penumbra-zone_penumbra.bufbuild_es/-/penumbra-zone_penumbra.bufbuild_es-1.10.0-20240616005217-ca45ca80333e.1.tgz} + peerDependencies: + '@bufbuild/protobuf': ^1.10.0 + + '@buf/penumbra-zone_penumbra.bufbuild_es@1.7.2-20240616005217-ca45ca80333e.2': + resolution: {tarball: https://buf.build/gen/npm/v1/@buf/penumbra-zone_penumbra.bufbuild_es/-/penumbra-zone_penumbra.bufbuild_es-1.7.2-20240616005217-ca45ca80333e.2.tgz} + peerDependencies: + '@bufbuild/protobuf': ^1.7.2 + + '@buf/penumbra-zone_penumbra.bufbuild_es@1.7.2-20240618173046-185f930afaf0.2': + resolution: {tarball: https://buf.build/gen/npm/v1/@buf/penumbra-zone_penumbra.bufbuild_es/-/penumbra-zone_penumbra.bufbuild_es-1.7.2-20240618173046-185f930afaf0.2.tgz} peerDependencies: '@bufbuild/protobuf': ^1.7.2 - '@buf/penumbra-zone_penumbra.bufbuild_es@1.9.0-20240528180215-8fe1c79485f8.1': - resolution: {tarball: https://buf.build/gen/npm/v1/@buf/penumbra-zone_penumbra.bufbuild_es/-/penumbra-zone_penumbra.bufbuild_es-1.9.0-20240528180215-8fe1c79485f8.1.tgz} + '@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240616005217-ca45ca80333e.3': + resolution: {tarball: https://buf.build/gen/npm/v1/@buf/penumbra-zone_penumbra.connectrpc_es/-/penumbra-zone_penumbra.connectrpc_es-1.4.0-20240616005217-ca45ca80333e.3.tgz} peerDependencies: - '@bufbuild/protobuf': ^1.9.0 + '@connectrpc/connect': ^1.4.0 - '@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240528180215-8fe1c79485f8.2': - resolution: {tarball: https://buf.build/gen/npm/v1/@buf/penumbra-zone_penumbra.connectrpc_es/-/penumbra-zone_penumbra.connectrpc_es-1.4.0-20240528180215-8fe1c79485f8.2.tgz} + '@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3': + resolution: {tarball: https://buf.build/gen/npm/v1/@buf/penumbra-zone_penumbra.connectrpc_es/-/penumbra-zone_penumbra.connectrpc_es-1.4.0-20240618173046-185f930afaf0.3.tgz} peerDependencies: '@connectrpc/connect': ^1.4.0 - '@buf/tendermint_tendermint.bufbuild_es@1.9.0-20231117195010-33ed361a9051.1': - resolution: {tarball: https://buf.build/gen/npm/v1/@buf/tendermint_tendermint.bufbuild_es/-/tendermint_tendermint.bufbuild_es-1.9.0-20231117195010-33ed361a9051.1.tgz} + '@buf/tendermint_tendermint.bufbuild_es@1.10.0-20231117195010-33ed361a9051.1': + resolution: {tarball: https://buf.build/gen/npm/v1/@buf/tendermint_tendermint.bufbuild_es/-/tendermint_tendermint.bufbuild_es-1.10.0-20231117195010-33ed361a9051.1.tgz} peerDependencies: - '@bufbuild/protobuf': ^1.9.0 + '@bufbuild/protobuf': ^1.10.0 '@bufbuild/protobuf@1.10.0': resolution: {integrity: sha512-QDdVFLoN93Zjg36NoQPZfsVH9tZew7wKDKyV5qRdj8ntT4wQCOradQjRaTdwMhWUYsgKsvCINKKm87FdEk96Ag==} @@ -1985,138 +1657,276 @@ packages: cpu: [ppc64] os: [aix] + '@esbuild/aix-ppc64@0.21.5': + resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [aix] + '@esbuild/android-arm64@0.20.2': resolution: {integrity: sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==} engines: {node: '>=12'} cpu: [arm64] os: [android] + '@esbuild/android-arm64@0.21.5': + resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + '@esbuild/android-arm@0.20.2': resolution: {integrity: sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==} engines: {node: '>=12'} cpu: [arm] os: [android] + '@esbuild/android-arm@0.21.5': + resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + '@esbuild/android-x64@0.20.2': resolution: {integrity: sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==} engines: {node: '>=12'} cpu: [x64] os: [android] + '@esbuild/android-x64@0.21.5': + resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + '@esbuild/darwin-arm64@0.20.2': resolution: {integrity: sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==} engines: {node: '>=12'} cpu: [arm64] os: [darwin] + '@esbuild/darwin-arm64@0.21.5': + resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + '@esbuild/darwin-x64@0.20.2': resolution: {integrity: sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==} engines: {node: '>=12'} cpu: [x64] os: [darwin] + '@esbuild/darwin-x64@0.21.5': + resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + '@esbuild/freebsd-arm64@0.20.2': resolution: {integrity: sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==} engines: {node: '>=12'} cpu: [arm64] os: [freebsd] + '@esbuild/freebsd-arm64@0.21.5': + resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + '@esbuild/freebsd-x64@0.20.2': resolution: {integrity: sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==} engines: {node: '>=12'} cpu: [x64] os: [freebsd] + '@esbuild/freebsd-x64@0.21.5': + resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + '@esbuild/linux-arm64@0.20.2': resolution: {integrity: sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==} engines: {node: '>=12'} cpu: [arm64] os: [linux] + '@esbuild/linux-arm64@0.21.5': + resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + '@esbuild/linux-arm@0.20.2': resolution: {integrity: sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==} engines: {node: '>=12'} cpu: [arm] os: [linux] + '@esbuild/linux-arm@0.21.5': + resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + '@esbuild/linux-ia32@0.20.2': resolution: {integrity: sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==} engines: {node: '>=12'} cpu: [ia32] os: [linux] + '@esbuild/linux-ia32@0.21.5': + resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + '@esbuild/linux-loong64@0.20.2': resolution: {integrity: sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==} engines: {node: '>=12'} cpu: [loong64] os: [linux] + '@esbuild/linux-loong64@0.21.5': + resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + '@esbuild/linux-mips64el@0.20.2': resolution: {integrity: sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==} engines: {node: '>=12'} cpu: [mips64el] os: [linux] + '@esbuild/linux-mips64el@0.21.5': + resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + '@esbuild/linux-ppc64@0.20.2': resolution: {integrity: sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==} engines: {node: '>=12'} cpu: [ppc64] os: [linux] + '@esbuild/linux-ppc64@0.21.5': + resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + '@esbuild/linux-riscv64@0.20.2': resolution: {integrity: sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==} engines: {node: '>=12'} cpu: [riscv64] os: [linux] + '@esbuild/linux-riscv64@0.21.5': + resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + '@esbuild/linux-s390x@0.20.2': resolution: {integrity: sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==} engines: {node: '>=12'} cpu: [s390x] os: [linux] + '@esbuild/linux-s390x@0.21.5': + resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + '@esbuild/linux-x64@0.20.2': resolution: {integrity: sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==} engines: {node: '>=12'} cpu: [x64] os: [linux] + '@esbuild/linux-x64@0.21.5': + resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + '@esbuild/netbsd-x64@0.20.2': resolution: {integrity: sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==} engines: {node: '>=12'} cpu: [x64] os: [netbsd] + '@esbuild/netbsd-x64@0.21.5': + resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + '@esbuild/openbsd-x64@0.20.2': resolution: {integrity: sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==} engines: {node: '>=12'} cpu: [x64] os: [openbsd] + '@esbuild/openbsd-x64@0.21.5': + resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + '@esbuild/sunos-x64@0.20.2': resolution: {integrity: sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==} engines: {node: '>=12'} cpu: [x64] os: [sunos] + '@esbuild/sunos-x64@0.21.5': + resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + '@esbuild/win32-arm64@0.20.2': resolution: {integrity: sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==} engines: {node: '>=12'} cpu: [arm64] os: [win32] + '@esbuild/win32-arm64@0.21.5': + resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + '@esbuild/win32-ia32@0.20.2': resolution: {integrity: sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==} engines: {node: '>=12'} cpu: [ia32] os: [win32] + '@esbuild/win32-ia32@0.21.5': + resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + '@esbuild/win32-x64@0.20.2': resolution: {integrity: sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==} engines: {node: '>=12'} cpu: [x64] os: [win32] + '@esbuild/win32-x64@0.21.5': + resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + '@eslint-community/eslint-utils@4.4.0': resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -2127,24 +1937,24 @@ packages: resolution: {integrity: sha512-Zm2NGpWELsQAD1xsJzGQpYfvICSsFkEpU0jxBjfdC6uNEWXcHnfs9hScFWtXVDVl+rBQJGrl4g1vcKIejpH9dA==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint/compat@1.0.3': - resolution: {integrity: sha512-9RaroPQaU2+SDcWav1YfuipwqnHccoiXZdUsicRQsQ/vH2wkEmRVcj344GapG/FnCeZRtqj0n6PshI+s9xkkAQ==} + '@eslint/compat@1.1.0': + resolution: {integrity: sha512-s9Wi/p25+KbzxKlDm3VshQdImhWk+cbdblhwGNnyCU5lpSwtWa4v7VQCxSki0FAUrGA3s8nCWgYzAH41mwQVKQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/config-array@0.15.1': - resolution: {integrity: sha512-K4gzNq+yymn/EVsXYmf+SBcBro8MTf+aXJZUphM96CdzUEr+ClGDvAbpmaEK+cGVigVXIgs9gNmvHAlrzzY5JQ==} + '@eslint/config-array@0.16.0': + resolution: {integrity: sha512-/jmuSd74i4Czf1XXn7wGRWZCuyaUZ330NH1Bek0Pplatt4Sy1S5haN21SCLLdbeKslQ+S0wEJ+++v5YibSi+Lg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/eslintrc@3.1.0': resolution: {integrity: sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/js@9.4.0': - resolution: {integrity: sha512-fdI7VJjP3Rvc70lC4xkFXHB0fiPeojiL1PxVG6t1ZvXQrarj893PweuBTujxDUFk0Fxj4R7PIIAZ/aiiyZPZcg==} + '@eslint/js@9.5.0': + resolution: {integrity: sha512-A7+AOT2ICkodvtsWnxZP4Xxk3NbZ3VMHd8oihydLRGrJgqqdEz1qSeEgXYyT/Cu8h1TWWsQRejIx48mtjZ5y1w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/object-schema@2.1.3': - resolution: {integrity: sha512-HAbhAYKfsAC2EkTqve00ibWIZlaU74Z1EHwAjYr4PXF0YU2VEA1zSIKSSpKszRLRWwHzzRZXvK632u+uXzvsvw==} + '@eslint/object-schema@2.1.4': + resolution: {integrity: sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@fal-works/esbuild-plugin-global-externals@2.1.2': @@ -2269,19 +2079,6 @@ packages: '@types/react': '>=16' react: '>=16' - '@microsoft/api-extractor-model@7.28.13': - resolution: {integrity: sha512-39v/JyldX4MS9uzHcdfmjjfS6cYGAoXV+io8B5a338pkHiSt+gy2eXQ0Q7cGFJ7quSa1VqqlMdlPrB6sLR/cAw==} - - '@microsoft/api-extractor@7.43.0': - resolution: {integrity: sha512-GFhTcJpB+MI6FhvXEI9b2K0snulNLWHqC/BbcJtyNYcKUiw7l3Lgis5ApsYncJ0leALX7/of4XfmXk+maT111w==} - hasBin: true - - '@microsoft/tsdoc-config@0.16.2': - resolution: {integrity: sha512-OGiIzzoBLgWWR0UdRJX98oYO+XKGf7tiK4Zk6tQ/E4IJqGCe7dvkTvgDZV5cFJUzLGDOjeAXrnZoA6QkVySuxw==} - - '@microsoft/tsdoc@0.14.2': - resolution: {integrity: sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug==} - '@mui/base@5.0.0-beta.40': resolution: {integrity: sha512-I/lGHztkCzvwlXpjD2+SNmvNQvB4227xBXhISPjEaJUXGImOQ9f3D2Yj/T3KasSI/h0MLWy74X0J6clhPmsRbQ==} engines: {node: '>=12.0.0'} @@ -2293,11 +2090,11 @@ packages: '@types/react': optional: true - '@mui/core-downloads-tracker@5.15.19': - resolution: {integrity: sha512-tCHSi/Tomez9ERynFhZRvFO6n9ATyrPs+2N80DMDzp6xDVirbBjEwhPcE+x7Lj+nwYw0SqFkOxyvMP0irnm55w==} + '@mui/core-downloads-tracker@5.15.20': + resolution: {integrity: sha512-DoL2ppgldL16utL8nNyj/P12f8mCNdx/Hb/AJnX9rLY4b52hCMIx1kH83pbXQ6uMy6n54M3StmEbvSGoj2OFuA==} - '@mui/material@5.15.19': - resolution: {integrity: sha512-lp5xQBbcRuxNtjpWU0BWZgIrv2XLUz4RJ0RqFXBdESIsKoGCQZ6P3wwU5ZPuj5TjssNiKv9AlM+vHopRxZhvVQ==} + '@mui/material@5.15.20': + resolution: {integrity: sha512-tVq3l4qoXx/NxUgIx/x3lZiPn/5xDbdTE8VrLczNpfblLYZzlrbxA7kb9mI8NoBF6+w9WE9IrxWnKK5KlPI2bg==} engines: {node: '>=12.0.0'} peerDependencies: '@emotion/react': ^11.5.0 @@ -2313,8 +2110,8 @@ packages: '@types/react': optional: true - '@mui/private-theming@5.15.14': - resolution: {integrity: sha512-UH0EiZckOWcxiXLX3Jbb0K7rC8mxTr9L9l6QhOZxYc4r8FHUkefltV9VDGLrzCaWh30SQiJvAEd7djX3XXY6Xw==} + '@mui/private-theming@5.15.20': + resolution: {integrity: sha512-BK8F94AIqSrnaPYXf2KAOjGZJgWfvqAVQ2gVR3EryvQFtuBnG6RwodxrCvd3B48VuMy6Wsk897+lQMUxJyk+6g==} engines: {node: '>=12.0.0'} peerDependencies: '@types/react': ^17.0.0 || ^18.0.0 @@ -2336,8 +2133,8 @@ packages: '@emotion/styled': optional: true - '@mui/system@5.15.15': - resolution: {integrity: sha512-aulox6N1dnu5PABsfxVGOZffDVmlxPOVgj56HrUnJE8MCSh8lOvvkd47cebIVQQYAjpwieXQXiDPj5pwM40jTQ==} + '@mui/system@5.15.20': + resolution: {integrity: sha512-LoMq4IlAAhxzL2VNUDBTQxAb4chnBe8JvRINVNDiMtHE2PiPOoHlhOPutSxEbaL5mkECPVWSv6p8JEV+uykwIA==} engines: {node: '>=12.0.0'} peerDependencies: '@emotion/react': ^11.5.0 @@ -2360,8 +2157,8 @@ packages: '@types/react': optional: true - '@mui/utils@5.15.14': - resolution: {integrity: sha512-0lF/7Hh/ezDv5X7Pry6enMsbYyGKjADzvHyo3Qrc/SSlTsQ1VkbDMbH0m2t3OR5iIVLwMoxwM7yGd+6FCMtTFA==} + '@mui/utils@5.15.20': + resolution: {integrity: sha512-mAbYx0sovrnpAu1zHc3MDIhPqL8RPVC5W5xcO1b7PiSCJPtckIZmBkp8hefamAvUiAV8gpfMOM6Zb+eSisbI2A==} engines: {node: '>=12.0.0'} peerDependencies: '@types/react': ^17.0.0 || ^18.0.0 @@ -2408,6 +2205,115 @@ packages: '@penumbra-labs/registry@8.0.1': resolution: {integrity: sha512-wbnIhOL7zWUKRF0TGxSUwJpdnoT0jE/xuK8ce/OnUFxgcn8sgdL+Z+TgAx4JNicLuJftUmOm9ACtF86Lpv3zMw==} + '@penumbra-zone/bech32m@6.1.0': + resolution: {integrity: sha512-XOMTRDbk+xioIY/p2nCQgBwlzut1Y+mKRO+u8SSNpW92BDX4fk8TXh6STzlTP1REN7UA+NdV/nUglLVBZutCow==} + + '@penumbra-zone/client@8.0.0': + resolution: {integrity: sha512-57OuCbKSMfMfGDhpT9QR7ddLOfAEVk1XSneXyzN2P0i5eQvphS9iTOOwG7BG5ci0NYJLaD6uUwQqsOPqbXKxjg==} + peerDependencies: + '@penumbra-zone/protobuf': 5.1.0 + '@penumbra-zone/transport-dom': 7.1.0 + + '@penumbra-zone/crypto-web@5.0.0': + resolution: {integrity: sha512-S8rdAlQrx5dM1IWO8+jBb2+wfptRw1yPc/inwMCXJx0OyTFmOMp2PXpHuE4PXHR/mxODkwzMTe88gFWDvbJZIg==} + peerDependencies: + '@penumbra-zone/types': 9.0.0 + + '@penumbra-zone/getters@8.0.0': + resolution: {integrity: sha512-Y4rt7hNyKLbk70QBNMVJww71LXUKsV8/ZTRdDtQ67BTY5MRTy+7681U83yNKVqBEy487vc6UQfgGgyLvhVPvqg==} + peerDependencies: + '@buf/penumbra-zone_penumbra.bufbuild_es': 1.10.0-20240616005217-ca45ca80333e.1 + '@bufbuild/protobuf': ^1.10.0 + '@penumbra-zone/bech32m': 6.1.0 + '@penumbra-zone/protobuf': 5.1.0 + + '@penumbra-zone/keys@4.1.0': + resolution: {integrity: sha512-VOxPuJj6wdwzhPyr4nJ/x6WU0NkQDcPfPZagxaMmG7r0331iYD9yVp1aw5F/iscx7a4yKH5MT47FlIGkXgN9fw==} + hasBin: true + + '@penumbra-zone/perspective@6.0.0': + resolution: {integrity: sha512-r4mO0V/ugGTkkIldlVdZcLSJH3SzbXLa4delSgpCWhQrezCE1Mqj8JzlJw9sjRwIv2FA52mMyzHCGX8vReCuEQ==} + peerDependencies: + '@buf/penumbra-zone_penumbra.bufbuild_es': 1.10.0-20240616005217-ca45ca80333e.1 + '@penumbra-zone/bech32m': 6.1.0 + '@penumbra-zone/getters': 8.0.0 + '@penumbra-zone/wasm': 9.0.0 + + '@penumbra-zone/protobuf@5.1.0': + resolution: {integrity: sha512-AkpZt3FtSvDFVu20mlCtn4UR3+c58cotPWc+zN9JpX/vfRhJy21wet4KwLbqyUJqaoGbQR/6zgUGZk1zqzJXUA==} + peerDependencies: + '@buf/cosmos_ibc.bufbuild_es': 1.10.0-20240606104028-442292b00c16.1 + '@buf/cosmos_ibc.connectrpc_es': 1.4.0-20240606104028-442292b00c16.3 + '@buf/penumbra-zone_penumbra.bufbuild_es': 1.10.0-20240616005217-ca45ca80333e.1 + '@buf/penumbra-zone_penumbra.connectrpc_es': 1.4.0-20240616005217-ca45ca80333e.3 + + '@penumbra-zone/query@6.0.0': + resolution: {integrity: sha512-vJQ4pHVHuNHcwr13+cZ6/4Q5c839ngQqYXPod5jfQ68BaVY4kIz0WQdopQcbVZCWkP6qTRhuS4jSPh12t2Nqdg==} + peerDependencies: + '@buf/cosmos_ibc.bufbuild_es': 1.10.0-20240606104028-442292b00c16.1 + '@buf/penumbra-zone_penumbra.bufbuild_es': 1.10.0-20240616005217-ca45ca80333e.1 + '@penumbra-zone/bech32m': 6.1.0 + '@penumbra-zone/crypto-web': 5.0.0 + '@penumbra-zone/getters': 8.0.0 + '@penumbra-zone/protobuf': 5.1.0 + '@penumbra-zone/types': 9.0.0 + '@penumbra-zone/wasm': 9.0.0 + + '@penumbra-zone/services@6.0.0': + resolution: {integrity: sha512-9taHfdvfNyFL9qtNwKp74WuLgf54qTet8cs//rM1mYORwEwSFeqh9DpOaYUo0G3viSSvQ17WDUQZvoA3EmG2dw==} + peerDependencies: + '@buf/penumbra-zone_penumbra.bufbuild_es': 1.10.0-20240616005217-ca45ca80333e.1 + '@bufbuild/protobuf': ^1.10.0 + '@connectrpc/connect': ^1.4.0 + '@penumbra-zone/bech32m': 6.1.0 + '@penumbra-zone/crypto-web': 5.0.0 + '@penumbra-zone/getters': 8.0.0 + '@penumbra-zone/perspective': 6.0.0 + '@penumbra-zone/protobuf': 5.1.0 + '@penumbra-zone/query': 6.0.0 + '@penumbra-zone/storage': 6.0.0 + '@penumbra-zone/transport-dom': 7.1.0 + '@penumbra-zone/types': 9.0.0 + '@penumbra-zone/wasm': 9.0.0 + + '@penumbra-zone/storage@6.0.0': + resolution: {integrity: sha512-IYMILpD7yrhYmlJpo2MQCFiw8StnUQhetODGYebNJeK3rfygfxmv3RdpP4UHAm2AkEqPaFtVvZovLZkWN2JYkA==} + peerDependencies: + '@buf/penumbra-zone_penumbra.bufbuild_es': 1.10.0-20240616005217-ca45ca80333e.1 + '@bufbuild/protobuf': ^1.10.0 + '@penumbra-zone/bech32m': 6.1.0 + '@penumbra-zone/getters': 8.0.0 + '@penumbra-zone/types': 9.0.0 + '@penumbra-zone/wasm': 9.0.0 + + '@penumbra-zone/transport-chrome@4.0.0': + resolution: {integrity: sha512-aym9RbFWej4MsXeTOx72qIUzjp141T7EhnKpdOFfJmYmo8AytCsJoFLNw9eWj7G2NS/X6x0vlGJJl1K/+TEtPA==} + peerDependencies: + '@bufbuild/protobuf': ^1.10.0 + '@connectrpc/connect': ^1.4.0 + '@penumbra-zone/transport-dom': 7.1.0 + + '@penumbra-zone/transport-dom@7.1.0': + resolution: {integrity: sha512-eCknu+VlQtLSPuYMbIV3x7T9rh0ZT2OVRHyxqlsXVkCUiIvT2AJioRxoFDIbd2ILFFVPEKfoxFL6qBcMghZ2wg==} + + '@penumbra-zone/types@9.0.0': + resolution: {integrity: sha512-gIJbMKiKcNctsX6R6ZJd9yvol3kgNTKwsR2riT5kLO8sqKqjgfc5WcaM1fKkwj4bZfzLbpToH94vVoT5UK+Jxg==} + peerDependencies: + '@buf/cosmos_ibc.bufbuild_es': 1.10.0-20240606104028-442292b00c16.1 + '@buf/penumbra-zone_penumbra.bufbuild_es': 1.10.0-20240616005217-ca45ca80333e.1 + '@bufbuild/protobuf': ^1.10.0 + '@penumbra-zone/bech32m': 6.1.0 + '@penumbra-zone/getters': 8.0.0 + + '@penumbra-zone/wasm@9.0.0': + resolution: {integrity: sha512-PWQj93qHJ5h3I+hEIXSWGQgckQ0hzO4Fs370Ss/MHUbKg/pjE2VftYoMQILiGZBwg9peoeuczyNI6mbEY/7I6Q==} + peerDependencies: + '@buf/penumbra-zone_penumbra.bufbuild_es': 1.10.0-20240616005217-ca45ca80333e.1 + '@bufbuild/protobuf': ^1.10.0 + '@penumbra-zone/bech32m': 6.1.0 + '@penumbra-zone/protobuf': 5.1.0 + '@penumbra-zone/types': 9.0.0 + '@pkgjs/parseargs@0.11.0': resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} @@ -3080,28 +2986,6 @@ packages: cpu: [x64] os: [win32] - '@rushstack/node-core-library@4.0.2': - resolution: {integrity: sha512-hyES82QVpkfQMeBMteQUnrhASL/KHPhd7iJ8euduwNJG4mu2GSOKybf0rOEjOm1Wz7CwJEUm9y0yD7jg2C1bfg==} - peerDependencies: - '@types/node': '*' - peerDependenciesMeta: - '@types/node': - optional: true - - '@rushstack/rig-package@0.5.2': - resolution: {integrity: sha512-mUDecIJeH3yYGZs2a48k+pbhM6JYwWlgjs2Ca5f2n1G2/kgdgP9D/07oglEGf6mRyXEnazhEENeYTSNDRCwdqA==} - - '@rushstack/terminal@0.10.0': - resolution: {integrity: sha512-UbELbXnUdc7EKwfH2sb8ChqNgapUOdqcCIdQP4NGxBpTZV2sQyeekuK3zmfQSa/MN+/7b4kBogl2wq0vpkpYGw==} - peerDependencies: - '@types/node': '*' - peerDependenciesMeta: - '@types/node': - optional: true - - '@rushstack/ts-command-line@4.19.1': - resolution: {integrity: sha512-J7H768dgcpG60d7skZ5uSSwyCZs/S2HrWP1Ds8d1qYAyaaeJmpmmLr9BVw97RjFzmQPOYnoXcKA4GkqDCkduQg==} - '@sinclair/typebox@0.27.8': resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} @@ -3109,53 +2993,53 @@ packages: resolution: {integrity: sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==} engines: {node: '>=18'} - '@storybook/addon-actions@8.1.6': - resolution: {integrity: sha512-EbiAdbtXN/UM4by3+qisbrQmElaIfahgNqffbst6GiCTmUCVE5if6geL1mzKd/u/rZOzx5g0EG76x8N9yDjOtg==} + '@storybook/addon-actions@8.1.10': + resolution: {integrity: sha512-1MjncuynvkT3rJtrkWPHLo92Pfno+LUWtaHiNDt9nXYowclTN2cT4a4gNDh6eKkB9dITHxkD7/4mxjHpFUvyrA==} - '@storybook/addon-backgrounds@8.1.6': - resolution: {integrity: sha512-mrBG5mkcMg6vpRUtNxyYaseD4ucrG+mZiqZnXcx8LWzwDMOd4mOODvap286z+Si0Fl1etbGDDhPU9+hV+o1arw==} + '@storybook/addon-backgrounds@8.1.10': + resolution: {integrity: sha512-nX9Hmcq5U/13S2ETcjGaLqfDcaSKTNPD3RBzWUoNQuZB/bB1q4qLLncQnQfaa6uruP9k6GIFZvtXeJAs9r0POw==} - '@storybook/addon-controls@8.1.6': - resolution: {integrity: sha512-hDMsu4yRP/ySb/G7hbd7nSFhVNz+F9hnizJGJX4XGuiSx7rAEYjvfKQKkawxTP+VeAw6iZPj1fukvOrMCQ0xxQ==} + '@storybook/addon-controls@8.1.10': + resolution: {integrity: sha512-98uLezKv6W/1byJL+Zri5kA1Cfi+DUBsbdjz7fFJl8xMtAGwuv9cnOueQl0ouDhqqwnZ4LWHYQsSsPPMz1Lmkg==} - '@storybook/addon-docs@8.1.6': - resolution: {integrity: sha512-ejTbjDhaHn6IeTma/pwn8OutDzIqbMJKNhZx24W4FE/qvYInZIK/9gYPU9/oLKZ7FImqP3s1e4+RxDBgsq21lA==} + '@storybook/addon-docs@8.1.10': + resolution: {integrity: sha512-jzmIeCoykiHg/KLPrYEDtXO/+dcQaEOqyJHS77eTzAO2iSXJlE+yva5Uwc8apG7UxDVa4Ycc1lPwMzB5GaHsGQ==} - '@storybook/addon-essentials@8.1.6': - resolution: {integrity: sha512-8ve9eM9dL6JsC5hV98unXtADvwyhIZoa3iWSeTicxWab49tvAfIM9ExwcWmUyPaB4m5q45jBSBXg66bzW2+TFw==} + '@storybook/addon-essentials@8.1.10': + resolution: {integrity: sha512-xgAXdl/MaKWmwqJJpw4z1YaD1V/r74VHHLqY3Z4YaU9DmlApkCa+FmZSS9QVAf7g6JNUcD1Dbtw5j62uNn+YyA==} - '@storybook/addon-highlight@8.1.6': - resolution: {integrity: sha512-QT95TS4OT0SJJVz/1m038COUdS2yWukQOwyq2rCgSM6nU3OHOPf/CldDK4Sdch7Z4jV9kRdRS0Pu4FB5SV+uOw==} + '@storybook/addon-highlight@8.1.10': + resolution: {integrity: sha512-s9QKGtU6WGB/+CggNWg940NIi+u0tcxpPxqg/ltg3EOHr8J0NAZur6mibs3Z4Q5CXkAuNdWrvopLu+/27i1rQQ==} - '@storybook/addon-interactions@8.1.6': - resolution: {integrity: sha512-/5i3wXuNnduTN807BNSX7nJ0a3eQPjN49yUAfLtYtIoNCEsLAza2F5yt8aadKOj1rR6xqROc7y8NMhhC5Cp50A==} + '@storybook/addon-interactions@8.1.10': + resolution: {integrity: sha512-GGU66TxYv6Bis10mmlgMhLOyai1am1amKVvX7ML8XYfsi6lA9zCnfQSVXulYLfjfzyIR6Ld8Kxe5awvjucPxSw==} - '@storybook/addon-links@8.1.6': - resolution: {integrity: sha512-EuSXoK+tpApjW08ZiC4yE9ePdJkIu36AFPJHA6FVierVU31klW+cbFqps88JpmALZkrlf+pzKf3uBIGLrkBSAw==} + '@storybook/addon-links@8.1.10': + resolution: {integrity: sha512-SxCuK7k7A0/qIPzV68u25qfye3Fb0PkC1izlRbt7u64wIUIxGzgfjM3dFRWK2VaJzCsEQWSmIdv7YHi7Wv5y3w==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta peerDependenciesMeta: react: optional: true - '@storybook/addon-measure@8.1.6': - resolution: {integrity: sha512-afG6XzClrkBQ9ZUZQs0rI9z/RYB+qhebG5k1NTCGYJnj7K4c+jso9nQ9vmypOBqlYKwTT2ZG+9xSK1/IhudEvg==} + '@storybook/addon-measure@8.1.10': + resolution: {integrity: sha512-akhdg3WBOBvDsolzSSvW4TIdZLMVlL9DS6rpZvhydXeX8pG0sjb+sON6VUL4h8Gs7qa8QumauXCr+Y4q1FhZhw==} - '@storybook/addon-outline@8.1.6': - resolution: {integrity: sha512-YjH3L4kxln0fLF77oDGJ2KF1I0RNrBQ9FRtqZkGMUbplxwYU0BBrguSgVeGxTLN1q/69LmL6wjFP4nLzqZARhA==} + '@storybook/addon-outline@8.1.10': + resolution: {integrity: sha512-Edn5TWpV1DcumOjx0qG9bBKja6vz210ip7O47JbRDu7IDR8lguaM2X9xbmhXhBQq4fmqvobZmfRnrSeCtSYeyQ==} '@storybook/addon-postcss@2.0.0': resolution: {integrity: sha512-Nt82A7e9zJH4+A+VzLKKswUfru+T6FJTakj4dccP0i8DSn7a0CkzRPrLuZBq8tg4voV6gD74bcDf3gViCVBGtA==} engines: {node: '>=10', yarn: ^1.17.0} - '@storybook/addon-toolbars@8.1.6': - resolution: {integrity: sha512-d1GciLzD2ZRqh7+b8+JGuCdx8x/MAobhTy+jKeK79d+QKNtPhqZ1OvyUbwObgD6XLF8B/3DvyP3r52lmYMwlnQ==} + '@storybook/addon-toolbars@8.1.10': + resolution: {integrity: sha512-5bRcCWrhaTX5Y91EWmHilPZ7kZaneaY414Gn5a6gsaNgaVPkSx9KD9j8M9DyXJ4yQNs265TiPWQqWrPB3Q2VgA==} - '@storybook/addon-viewport@8.1.6': - resolution: {integrity: sha512-4EpEkJW1fPqlHIqG7OQtnAaHh9DPj7k+guXpzWjVwHfF6AE0fXIg7Yx6iVDGPyKkRaagPw6nL8DOr2U8YwK4rQ==} + '@storybook/addon-viewport@8.1.10': + resolution: {integrity: sha512-rJpyAwTVQa+6yqjdMDeqNKoW5aPoSzBAtMywtNMP5lHwF6NpJUvm67c/ox0//d5dPPPjlJDz2QC2COWqjviQyw==} - '@storybook/blocks@8.1.6': - resolution: {integrity: sha512-HBp80G9puOejqlBA0iNlV3gUxc7TkBlNIVG2rmhjcvPZUueldxTUGIGvEfTLdEM6nqzNVZT+duXwqeHHnDcynA==} + '@storybook/blocks@8.1.10': + resolution: {integrity: sha512-8ZGgLIUBdSafcyaKR5Zs0CFisFCPoxZBVt3GMUCZtN+G17YhEg4+OnZs5aMZknfnh28BUnZS2STjWTGStAE5Rw==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta @@ -3165,8 +3049,8 @@ packages: react-dom: optional: true - '@storybook/builder-manager@8.1.6': - resolution: {integrity: sha512-Y5d+dikKnUuCYyh4VLEF6A+AbWughEgtipVkDKOddSTzn04trClIOKqfhQqEUObydCpgvvfdjGXJa/zDRV/UQA==} + '@storybook/builder-manager@8.1.10': + resolution: {integrity: sha512-dhg54zpaglR9XKNAiwMqm5/IONMCEG/hO/iTfNHJI1rAGeWhvM71cmhF+VlKUcjpTlIfHe7J19+TL+sWQJNgtg==} '@storybook/builder-vite@8.1.1': resolution: {integrity: sha512-+BSmXuZ9j95oKCvHcKztzjZNzBVeXYMoRO2TuflLnknMUA0v9ySp1PhiQxHM4DgAW6t9db1akzc9HoTA5sjTWg==} @@ -3186,24 +3070,24 @@ packages: '@storybook/channels@8.1.1': resolution: {integrity: sha512-vG7y97QB++TRkuxYLNKaWJmgr9QBUHyjQgNCWvHIeSYW5zxum9sm6VSR2j1r2G3XUGFSxDwenYBTQuwZJLhWNQ==} - '@storybook/channels@8.1.6': - resolution: {integrity: sha512-CzDnP6qfI8OC8pGUk+wPUzLPYcKhX8XbriF2gBtwl6qVM8YfkHP2mLTiDYDwBIi0rLuUbSm/SpILXQ/ouOHOGw==} + '@storybook/channels@8.1.10': + resolution: {integrity: sha512-CxZE4XrQoe+F+S2mo8Z9HTvFZKfKHIIiwYfoXKCryVp2U/z7ZKrely2PbfxWsrQvF3H0+oegfYYhYRHRiM21Zw==} - '@storybook/cli@8.1.6': - resolution: {integrity: sha512-xsFdBoAbo+2h/UCWuVXiH4Tu49iQ6d+3R1J8F2n4N6rAKxMqAb6fzYnH1GeRYeZk0HGqb2iNc4kBkxj0jW0rKw==} + '@storybook/cli@8.1.10': + resolution: {integrity: sha512-7Fm2Qgk33sHayZ0QABqwe1Jto4yyVRVW6kTrSeP5IuLh+mn244RgxBvWtGCyL1EcWDFI7PYUFa0HxgTCq7C+OA==} hasBin: true '@storybook/client-logger@8.1.1': resolution: {integrity: sha512-9AWPgIN3K0eLusChJUqB5Ft+9P2pW5/s4vOMoj3TCvu8lrdq8AH8ctvxk7x2Kw2wEwQ/g9DyE6C/rDQUARbxew==} - '@storybook/client-logger@8.1.6': - resolution: {integrity: sha512-QfSoUxS1rmrBzO7o99og9g+Gkm7sTmU5ZOpTkjszjlRqfV6/77eUnUOzUikej4LqPLmlJV5fqGuvoP0aNVksDw==} + '@storybook/client-logger@8.1.10': + resolution: {integrity: sha512-sVXCOo7jnlCgRPOcMlQGODAEt6ipPj+8xGkRUws0kie77qiDld1drLSB6R380dWc9lUrbv9E1GpxCd/Y4ZzSJQ==} - '@storybook/codemod@8.1.6': - resolution: {integrity: sha512-N5JeimfscAOcME7FIrTCmxcsXxow11vtmPTjYWoeLYokBodaH5RyWcyyQ5KS1ACtt+dHYoX8lepSZA5SBEzYog==} + '@storybook/codemod@8.1.10': + resolution: {integrity: sha512-HZ/vrseP/sHfbO2RZpImP5eeqOakJ0X31BIiD4uxDBIKGltMXhlPKHTI93O2YGR+vbB33otoTVRjE+ZpPmC6SA==} - '@storybook/components@8.1.6': - resolution: {integrity: sha512-RDcSj2gBVhK/klfcXQgINtvWe5hpJ1CYUv8hrAon3fWtZmX1+IrTJTorsdISvdHQ99o0WHZ+Ouz42O0yJnHzRg==} + '@storybook/components@8.1.10': + resolution: {integrity: sha512-fL2odC3Ct3NiFJEiGLmMNB3Tw3CdUDA/+va3Ka/JEhjaRhbsND2JgriHYmED8SnX9CCqwXoxl5QA8qwl+Oyolw==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta @@ -3216,8 +3100,8 @@ packages: prettier: optional: true - '@storybook/core-common@8.1.6': - resolution: {integrity: sha512-OTlfJFaTOB588ibXrrFm0TAXam6E5xV1VXSjNXL+fIifx8Kjln2HNSy1JKjvcblQneYiV4J1xPCVnAIe0EGHDg==} + '@storybook/core-common@8.1.10': + resolution: {integrity: sha512-+0GhgDRQwUlXu1lY77NdLnVBVycCEW0DG7eu7rvLYYkTyNRxbdl2RWsQpjr/j4sxqT6u82l9/b+RWpmsl4MgMQ==} peerDependencies: prettier: ^2 || ^3 peerDependenciesMeta: @@ -3227,23 +3111,23 @@ packages: '@storybook/core-events@8.1.1': resolution: {integrity: sha512-WpeiBV6RWTZ6t8SI1YdQh8NlbvQtZs9WRr4CPfpzHAly+oxFy6PtPz0h5TMKsU5/kt/L9yL7tE9ZzPYzvFWH/A==} - '@storybook/core-events@8.1.6': - resolution: {integrity: sha512-DaIVe4TUp/7uQdSJYGmJv9S/S364tSgZ3S3dZ1vsf1rgoUbCp5kTBtcd/fcqgukMPREgCgO9oDhmemI3SLAqzw==} + '@storybook/core-events@8.1.10': + resolution: {integrity: sha512-aS4zsBVyJds74+rAW0IfTEjULDCQwXecVpQfv11B8/89/07s3bOPssGGoTtCTaN4pHbduywE6MxbmFvTmXOFCA==} - '@storybook/core-server@8.1.6': - resolution: {integrity: sha512-rgkeTG8V4emzhPqjlhchsjLay0WtgK7SrXNf1X40oTJIwmbgbReLJ5EmOXBe9rhWSXJ13aKL3l6JuTLAoptSkg==} + '@storybook/core-server@8.1.10': + resolution: {integrity: sha512-jNL5/daNyo7Rcu+y/bOmSB1P65pmcaLwvpr31EUEIISaAqvgruaneS3GKHg2TR0wcxEoHaM4abqhW6iwkI/XYQ==} '@storybook/csf-plugin@8.1.1': resolution: {integrity: sha512-aZ2F3PY601MuW8xWf7/f928/anhZyaXYnysa8ViHooBEnJS1FBJfCsDDSM54FTDRyyOQF6AZtHeY53snd+e9ng==} - '@storybook/csf-plugin@8.1.6': - resolution: {integrity: sha512-y2OW84leoWsqfBXb7EoRy2QUmtsI3gpqYqpyD/d5K+vQ+E9CBel2WB8RPrwcYm2L88WPDaufQQDzqyB7aMx4fQ==} + '@storybook/csf-plugin@8.1.10': + resolution: {integrity: sha512-EwW9Olw85nKamUH/2YrkD+bxDvDP4TJ2MqS1qR3UU+lBP/HMQA2zFAgiW1TUmmdHmhAeiDOXbDhijxMa30sppQ==} '@storybook/csf-tools@8.1.1': resolution: {integrity: sha512-BaS1bFx8Rj9Nj7gxsJrifu9lFoli7CD4DxBGEeagVOvCcBX95RI0I9JLhr81LdMl5DwPP1xBGZjCVNsC7eIR4w==} - '@storybook/csf-tools@8.1.6': - resolution: {integrity: sha512-jrKfHFNhiLBhWWW4/fm2wgKEVg55e6QuYUHY16KGd7PdPuzm+2Pt7jIl5V9yIj6a59YbjeMpT6jWPKbFx2TuCw==} + '@storybook/csf-tools@8.1.10': + resolution: {integrity: sha512-bm/J1jAJf1YaKhcXgOlsNN02sf8XvILXuVAvr9cFC3aFkxVoGbC2AKCss4cgXAd8EQxUNtyETkOcheB5mJ5IlA==} '@storybook/csf@0.0.1': resolution: {integrity: sha512-USTLkZze5gkel8MYCujSRBVIrUQ3YPBrLOx7GNk/0wttvVtlzWXAq9eLbQ4p/NicGxP+3T7KPEMVV//g+yubpw==} @@ -3257,8 +3141,8 @@ packages: '@storybook/docs-tools@8.1.1': resolution: {integrity: sha512-BPq9e6bl4uRru0GSLHS56eg0SV5LEMJSzrMIzeSrTf9xoZdBeLM05oblo2oebEGZUE97uduhKoaUeUJtsuMIxw==} - '@storybook/docs-tools@8.1.6': - resolution: {integrity: sha512-IhqQHSJ5nEBEJ162P/6/6c45toLinWpAkB7pwbAoP00djZSzfHNdQ4HfpZSGfD4GUJIvzsqMzUlyqCKLAoRPPA==} + '@storybook/docs-tools@8.1.10': + resolution: {integrity: sha512-FsO/+L9CrUfAIbm9cdH9UpjTusT7L5RZxN4WCXkiF5SpAVyBoY8kar3RzTZVoh4aQxt1yGWYC+SZGjgf++xa4g==} '@storybook/global@5.0.0': resolution: {integrity: sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ==} @@ -3270,14 +3154,14 @@ packages: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - '@storybook/instrumenter@8.1.6': - resolution: {integrity: sha512-BoNu0QaD5hhcbEVUsvmYDqUOu4HItNBMPUkj6aDCfpLxae5vstH3zsCRVqRcElbfqVhmRzD23w8+9In9M0Fajg==} + '@storybook/instrumenter@8.1.10': + resolution: {integrity: sha512-/TZ3JpTCorbhThCfaR5k4Vs0Svp6xz6t+FVaim/v7N9VErEfmtn+d76CqYLfvmo68DzkEzvArOFBdh2MXtscsw==} - '@storybook/manager-api@8.1.6': - resolution: {integrity: sha512-L/s1FdFh/P+eFmQwLtFtJHwFJrGD9H7nauaQlKJOrU3GeXfjBjtlAZQF0Q6B4ZTGxwZjQrzShpt/0yKc6gymtw==} + '@storybook/manager-api@8.1.10': + resolution: {integrity: sha512-9aZ+zoNrTo1BJskVmCKE/yqlBXmWaKVZh1W/+/xu3WL9wdm/tBlozRvQwegIZlRVvUOxtjOg28Vd2hySYL58zg==} - '@storybook/manager@8.1.6': - resolution: {integrity: sha512-B7xc09FYHqC1sknJoWkGHBBCMQlfg7hF+4x42cGhAyYed4TeYAf7b1PDniq8L/PLbUgzTw+A62UC1fMurCcVDQ==} + '@storybook/manager@8.1.10': + resolution: {integrity: sha512-dQmRBfT4CABIPhv0kL25qKcQk2SiU5mIZ1DuVzckIbZW+iYEOAusyJ/0HExM9leCrymaW3BgZGlHbIXL7EvZtw==} '@storybook/node-logger@6.5.16': resolution: {integrity: sha512-YjhBKrclQtjhqFNSO+BZK+RXOx6EQypAELJKoLFaawg331e8VUfvUuRCNB3fcEWp8G9oH13PQQte0OTjLyyOYg==} @@ -3285,14 +3169,14 @@ packages: '@storybook/node-logger@8.1.1': resolution: {integrity: sha512-l+B8eu3yBZfrHvCR/FVqGyObgA0KSLp+06NkWDMn0p7qu0tCTROquopKdn2gXKitZp8wGwhgJV56OvW5C12XQA==} - '@storybook/node-logger@8.1.6': - resolution: {integrity: sha512-IZEiTLFHu8Oom/vdEGpisSw5CfU+cw6/fTaX1P3EVClFOWVuy8/3X5MPu4wJH3jPym6E2DBduIUFeRsiuq61gA==} + '@storybook/node-logger@8.1.10': + resolution: {integrity: sha512-djgbAROgGAvz/gr49egBxCHn1+rui57e76qa9aOMPzEBcxsGrnnKKp0uNdiNt4M7Xv6S2QHbJ2SfOlHhWmMeaA==} '@storybook/preview-api@8.1.1': resolution: {integrity: sha512-5EcByqtJgj7a7ZWICMLif8mK3cRmdIMbdSPEDf4X6aTQ8LZOg6updLrkb/Eh6qfeYv46TK/MP8BXa89wfOxWGQ==} - '@storybook/preview-api@8.1.6': - resolution: {integrity: sha512-g9EvVg/DYqmjMh1uivJBJnSIvURyuK4LLabYicQNmYdQJscAeXX2bpMcA4aeci9BBm9B2RP7JbSnq7DbXZaJYA==} + '@storybook/preview-api@8.1.10': + resolution: {integrity: sha512-0Gl8WHDtp/srrA5uBYXl7YbC8kFQA7IxVmwWN7dIS7HAXu63JZ6JfxaFcfy+kCBfZSBD7spFG4J0f5JXRDYbpg==} '@storybook/preview@8.1.1': resolution: {integrity: sha512-P8iBi9v/62AhTztbCYjVxH6idNO0h9uO583GHwi3uq2Io7F1gUSgwG/HYZ7PnclOsMnmG0FJvAwrvdRc6sWSNw==} @@ -3303,8 +3187,8 @@ packages: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - '@storybook/react-dom-shim@8.1.6': - resolution: {integrity: sha512-qP5nkAmpGFy/gshO+bVjRo1rgo/6UVDElgOd2dlUtYnfdPONiOfWko2XGYKKfxa6Cp7KU35JlZz/kHGqWG31zQ==} + '@storybook/react-dom-shim@8.1.10': + resolution: {integrity: sha512-+HS75Pq8jb3xkVq0hK33D84aGfbJCURRB+GN2vfTMmmjguQt7z2+MnGqRgrUCt6h2rxU3VdPg9OBnYi/UC0Zrg==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta @@ -3328,8 +3212,8 @@ packages: typescript: optional: true - '@storybook/react@8.1.6': - resolution: {integrity: sha512-2CSc3MLeaY7QaYAQLwaXRboKkgQnWrSZAo/WTJcSHUr2YFxH5+iECB0Kci12GqaJklhhgmfTfVZ4Jo9ZJ6LQfg==} + '@storybook/react@8.1.10': + resolution: {integrity: sha512-y0ycq19tTLLk+4rB+nfCPCtoFBWC0QvmMaJY32dbAjWPk+UNFGhWdqjg0oP1NwXYL18WnhRzlyz1Rojw0aXk1w==} engines: {node: '>=18.0.0'} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta @@ -3339,17 +3223,17 @@ packages: typescript: optional: true - '@storybook/router@8.1.6': - resolution: {integrity: sha512-tvuhB2uXHEKK640Epm1SqVzPhQ9lXYfF7FX6FleJgVYEvZpJpNTD4RojedQoLI6SUUSXNy1Vs2QV26VM0XIPHQ==} + '@storybook/router@8.1.10': + resolution: {integrity: sha512-JDEgZ0vVDx0GLz+dKD+R1xqWwjqsCdA2F+s3/si7upHqkFRWU5ocextZ63oKsRnCoaeUh6OavAU4EdkrKiQtQw==} - '@storybook/telemetry@8.1.6': - resolution: {integrity: sha512-qNWjQPF6ufRvLCAavulhNYoqldDIeBvioFuCjLlwbw3BZw3ck7pwh1vZg4AJ0SAfzbnpnXPGrHe31gnxV0D6tw==} + '@storybook/telemetry@8.1.10': + resolution: {integrity: sha512-pwiMWrq85D0AnaAgYNfB2w2BDgqnetQ+tXwsUAw4fUEFwA4oPU6r0uqekRbNNE6wmSSYjiiFP3JgknBFqjd2hg==} - '@storybook/test@8.1.6': - resolution: {integrity: sha512-tyexfYPtOHP83pMHggoGdHadfqh/veLdS+APHxt12zmCNUobxOxnuWmImXThQiyLlXTWecreLvlMvgAIjziBsA==} + '@storybook/test@8.1.10': + resolution: {integrity: sha512-uskw/xb/GkGLRTEKPao/5xUKxjP1X3DnDpE52xDF46ZmTvM+gPQbkex97qdG6Mfv37/0lhVhufAsV3g5+CrYKQ==} - '@storybook/theming@8.1.6': - resolution: {integrity: sha512-0Cl/7/0z2WSfXhZ9XSw6rgEjb0fXac7jfktieX0vYo1YckrNpWFRQP9NCpVPAcYZaFLlRSOqYark6CLoutEsIg==} + '@storybook/theming@8.1.10': + resolution: {integrity: sha512-W7mth4hwdTqWLneqYCyUnIEiDg4vSokoad8HEodPz6JC9XUPUX3Yi2W4W3xFvqrW4Z5RXfuJ53iG2HN+0AgaQw==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta @@ -3362,71 +3246,71 @@ packages: '@storybook/types@8.1.1': resolution: {integrity: sha512-QSQ63aKr2IXrGjX2/Fg1oiGWk+2Nuf+TplaHRC2NKBMgvyn+M0BHUgMTDHQVrFaH4bpl2PkE0r0tzOKP4JI43A==} - '@storybook/types@8.1.6': - resolution: {integrity: sha512-cWpS9+x1pxCO39spR8QmumMK2ub2p5cvMtrRvWaIjBFPbCwm2CvjBXFWIra2veBCZTxUKJ9VWxvi7pzRHjN/nw==} + '@storybook/types@8.1.10': + resolution: {integrity: sha512-UJ97iqI+0Mk13I6ayd3TaBfSFBkWnEauwTnFMQe1dN/L3wTh8laOBaLa0Vr3utRSnt2b5hpcw/nq7azB/Gx4Yw==} - '@swc/core-darwin-arm64@1.5.28': - resolution: {integrity: sha512-sP6g63ybzIdOWNDbn51tyHN8EMt7Mb4RMeHQEsXB7wQfDvzhpWB+AbfK6Gs3Q8fwP/pmWIrWW9csKOc1K2Mmkg==} + '@swc/core-darwin-arm64@1.6.3': + resolution: {integrity: sha512-3r7cJf1BcE30iyF1rnOSKrEzIR+cqnyYSZvivrm62TZdXVsIjfXe1xulsKGxZgNeLY5erIu7ukvMvBvPhnQvqA==} engines: {node: '>=10'} cpu: [arm64] os: [darwin] - '@swc/core-darwin-x64@1.5.28': - resolution: {integrity: sha512-Bd/agp/g7QocQG5AuorOzSC78t8OzeN+pCN/QvJj1CvPhvppjJw6e1vAbOR8vO2vvGi2pvtf3polrYQStJtSiA==} + '@swc/core-darwin-x64@1.6.3': + resolution: {integrity: sha512-8GLZ23IgVpF5xh2SbS5ZW/12/EEBuRU1hFOLB5rKERJU0y1RJ6YhDMf/FuOWhfHQcFM7TeedBwHIzaF+tdKKlw==} engines: {node: '>=10'} cpu: [x64] os: [darwin] - '@swc/core-linux-arm-gnueabihf@1.5.28': - resolution: {integrity: sha512-Wr3TwPGIveS9/OBWm0r9VAL8wkCR0zQn46J8K01uYCmVhUNK3Muxjs0vQBZaOrGu94mqbj9OXY+gB3W7aDvGdA==} + '@swc/core-linux-arm-gnueabihf@1.6.3': + resolution: {integrity: sha512-VQ/bduX7WhLOlGbJLMG7UH0LBehjjx43R4yuk55rjjJLqpvX5fQzMsWhQdIZ5vsc+4ORzdgtEAlpumTv6bsD1A==} engines: {node: '>=10'} cpu: [arm] os: [linux] - '@swc/core-linux-arm64-gnu@1.5.28': - resolution: {integrity: sha512-8G1ZwVTuLgTAVTMPD+M97eU6WeiRIlGHwKZ5fiJHPBcz1xqIC7jQcEh7XBkobkYoU5OILotls3gzjRt8CMNyDQ==} + '@swc/core-linux-arm64-gnu@1.6.3': + resolution: {integrity: sha512-jHIQ/PCwtdDBIF/BiC5DochswuCAIW/T5skJ+eDMbta7+QtEnZCXTZWpT5ORoEY/gtsE2fjpOA4TS6fBBvXqUw==} engines: {node: '>=10'} cpu: [arm64] os: [linux] - '@swc/core-linux-arm64-musl@1.5.28': - resolution: {integrity: sha512-0Ajdzb5Fzvz+XUbN5ESeHAz9aHHSYiQcm+vmsDi0TtPHmsalfnqEPZmnK0zPALPJPLQP2dDo4hELeDg3/c3xgA==} + '@swc/core-linux-arm64-musl@1.6.3': + resolution: {integrity: sha512-gA6velEUD27Dwu0BlR9hCcFzkWq2YL2pDAU5qbgeuGhaMiUCBssfqTQB+2ctEnV+AZx+hSMJOHvtA+uFZjfRrw==} engines: {node: '>=10'} cpu: [arm64] os: [linux] - '@swc/core-linux-x64-gnu@1.5.28': - resolution: {integrity: sha512-ueQ9VejnQUM2Pt+vT0IAKoF4vYBWUP6n1KHGdILpoGe3LuafQrqu7RoyQ15C7/AYii7hAeNhTFdf6gLbg8cjFg==} + '@swc/core-linux-x64-gnu@1.6.3': + resolution: {integrity: sha512-fy4qoBDr5I8r+ZNCZxs/oZcmu4j/8mtSud6Ka102DaSxEjNg0vfIdo9ITsVIPsofhUTmDKjQsPB2O7YUlJAioQ==} engines: {node: '>=10'} cpu: [x64] os: [linux] - '@swc/core-linux-x64-musl@1.5.28': - resolution: {integrity: sha512-G5th8Mg0az8CbY4GQt9/m5hg2Y0kGIwvQBeVACuLQB6q2Y4txzdiTpjmFqUUhEvvl7Klyx1IHvNhfXs3zpt7PA==} + '@swc/core-linux-x64-musl@1.6.3': + resolution: {integrity: sha512-c/twcMbq/Gpq47G+b3kWgoaCujpXO11aRgJx6am+CprvP4uNeBHEpQkxD+DQmdWFHisZd0i9GB8NG3e7L9Rz9Q==} engines: {node: '>=10'} cpu: [x64] os: [linux] - '@swc/core-win32-arm64-msvc@1.5.28': - resolution: {integrity: sha512-JezwCGavZ7CkNXx4yInI4kpb71L0zxzxA9BFlmnsGKEEjVQcKc3hFpmIzfFVs+eotlBUwDNb0+Yo9m6Cb7lllA==} + '@swc/core-win32-arm64-msvc@1.6.3': + resolution: {integrity: sha512-y6RxMtX45acReQmzkxcEfJscfBXce6QjuNgWQHHs9exA592BZzmolDUwgmAyjyvopz1lWX+KdymdZFKvuDSx4w==} engines: {node: '>=10'} cpu: [arm64] os: [win32] - '@swc/core-win32-ia32-msvc@1.5.28': - resolution: {integrity: sha512-q8tW5J4RkOkl7vYShnWS//VAb2Ngolfm9WOMaF2GRJUr2Y/Xeb/+cNjdsNOqea2BzW049D5vdP7XPmir3/zUZw==} + '@swc/core-win32-ia32-msvc@1.6.3': + resolution: {integrity: sha512-41h7z3xgukl1HDDwhquaeOPSP1OWeHl+mWKnJVmmwd3ui/oowUDCO856qa6JagBgPSnAGfyXwv6vthuXwyCcWA==} engines: {node: '>=10'} cpu: [ia32] os: [win32] - '@swc/core-win32-x64-msvc@1.5.28': - resolution: {integrity: sha512-jap6EiB3wG1YE1hyhNr9KLPpH4PGm+5tVMfN0l7fgKtV0ikgpcEN/YF94tru+z5m2HovqYW009+Evq9dcVGmpg==} + '@swc/core-win32-x64-msvc@1.6.3': + resolution: {integrity: sha512-//bnwo9b8Vp1ED06eXCHyGZ5xIpdkQgg2fuFDdtd1FITl7r5bdQh2ryRzPiKiGwgXZwZQitUshI4JeEX9IuW+Q==} engines: {node: '>=10'} cpu: [x64] os: [win32] - '@swc/core@1.5.28': - resolution: {integrity: sha512-muCdNIqOTURUgYeyyOLYE3ShL8SZO6dw6bhRm6dCvxWzCZOncPc5fB0kjcPXTML+9KJoHL7ks5xg+vsQK+v6ig==} + '@swc/core@1.6.3': + resolution: {integrity: sha512-mZpei+LqE+AL+nwgERMQey9EJA9/yhHTN6nwbobH5GnSij/lhfTdGfAb1iumOrroqEcXbHUaK//7wOw7DjBGdA==} engines: {node: '>=10'} peerDependencies: '@swc/helpers': '*' @@ -3437,9 +3321,6 @@ packages: '@swc/counter@0.1.3': resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} - '@swc/helpers@0.5.11': - resolution: {integrity: sha512-YNlnKRWF2sVojTpIyzwou9XoTNbzbzONwRhOoniEioF1AtaitTvVZblaQRrAzChWQ1bLYyYSWzM18y4WwgzJ+A==} - '@swc/types@0.1.8': resolution: {integrity: sha512-RNFA3+7OJFNYY78x0FYwi1Ow+iF1eF5WvmfY1nXPOEH4R2p/D4Cr1vzje7dNAI2aLFqpv8Wyz4oKSWqIZArpQA==} @@ -3540,9 +3421,6 @@ packages: resolution: {integrity: sha512-3uYg2b5TWCiupetbDFMbBFMHl33xQTvp5DNg0fZSYal73Z9AlFH9yWabHWMYw6ywmwM1evkYRpTVA2n7GgqT5A==} hasBin: true - '@types/argparse@1.0.38': - resolution: {integrity: sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==} - '@types/aria-query@5.0.4': resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} @@ -3573,9 +3451,6 @@ packages: '@types/cross-spawn@6.0.6': resolution: {integrity: sha512-fXRhhUkG4H3TQk5dBhQ7m/JDdSNHKwR2BBia62lhwEIq9xGiQKLxd6LymNhn47SjXhsUEPmxi+PKw2OkW4LLjA==} - '@types/crypto-js@4.2.2': - resolution: {integrity: sha512-sDOLlVbHhXpAUAL0YHDUUwDZf3iN4Bwi4W6a0W0b+QcAezUbRtH4FVb+9J4h+XFPW7l/gQ9F8qC7P+Ec4k8QVQ==} - '@types/d3-array@3.0.3': resolution: {integrity: sha512-Reoy+pKnvsksN0lQUlcH6dOGjRZ/3WRwXR//m+/8lt1BXeI4xyaUZoqULNjyXXRuh0Mj4LNpkCvhUpQlY3X5xQ==} @@ -3657,8 +3532,8 @@ packages: '@types/find-cache-dir@3.2.1': resolution: {integrity: sha512-frsJrz2t/CeGifcu/6uRo4b+SzAwT4NYCVPu1GN8IB9XTzrpPkGuV0tmh9mN+/L0PklAlsC3u5Fxt0ju00LXIw==} - '@types/firefox-webext-browser@120.0.3': - resolution: {integrity: sha512-APbBSxOvFMbKwXy/4YrEVa5Di6N0C9yl4w0WA0xzdkOrChAfPQ/KlcC8QLyhemHCHpF1CB/zHy52+oUQurViOg==} + '@types/firefox-webext-browser@120.0.4': + resolution: {integrity: sha512-lBrpf08xhiZBigrtdQfUaqX1UauwZ+skbFiL8u2Tdra/rklkKadYmIzTwkNZSWtuZ7OKpFqbE2HHfDoFqvZf6w==} '@types/geojson@7946.0.14': resolution: {integrity: sha512-WCfD5Ht3ZesJUsONdhvm84dmzWOiOzOAqOncN0++w0lBw1o8OuDNJF2McvvCef/yBqb/HYRahp1BYtODFQ8bRg==} @@ -3711,11 +3586,11 @@ packages: '@types/node@12.20.55': resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} - '@types/node@18.19.34': - resolution: {integrity: sha512-eXF4pfBNV5DAMKGbI02NnDtWrQ40hAN558/2vvS4gMpMIxaf6JmD7YjnZbq0Q9TDSSkKBamime8ewRoomHdt4g==} + '@types/node@18.19.36': + resolution: {integrity: sha512-tX1BNmYSWEvViftB26VLNxT6mEr37M7+ldUtq7rlKnv4/2fKYsJIOmqJAjT6h1DNuwQjIKgw3VJ/Dtw3yiTIQw==} - '@types/node@20.14.2': - resolution: {integrity: sha512-xyu6WAMVwv6AKFLB+e/7ySZVr/0zLCzOa7rSpq6jNwpqOrUbcACDWC+53d4n2QHOnDou0fbIsg8wZu/sxrnI4Q==} + '@types/node@20.14.5': + resolution: {integrity: sha512-aoRR+fJkZT2l0aGOJhuA8frnCSoNX6W7U2mpNq63+BxBIj5BQFt8rHy627kijCmm63ijdSdwvGgpUsU6MBsZZA==} '@types/normalize-package-data@2.4.4': resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} @@ -3786,8 +3661,8 @@ packages: '@types/webpack@5.28.5': resolution: {integrity: sha512-wR87cgvxj3p6D0Crt1r5avwqffqPXUkNlnQ1mjU93G7gCuFjufZR4I6j8cz5g1F1tTYpfOOFvly+cmIQwL9wvw==} - '@typescript-eslint/eslint-plugin@7.13.0': - resolution: {integrity: sha512-FX1X6AF0w8MdVFLSdqwqN/me2hyhuQg4ykN6ZpVhh1ij/80pTvDKclX1sZB9iqex8SjQfVhwMKs3JtnnMLzG9w==} + '@typescript-eslint/eslint-plugin@7.13.1': + resolution: {integrity: sha512-kZqi+WZQaZfPKnsflLJQCz6Ze9FFSMfXrrIOcyargekQxG37ES7DJNpJUE9Q/X5n3yTIP/WPutVNzgknQ7biLg==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: '@typescript-eslint/parser': ^7.0.0 @@ -3797,8 +3672,8 @@ packages: typescript: optional: true - '@typescript-eslint/parser@7.13.0': - resolution: {integrity: sha512-EjMfl69KOS9awXXe83iRN7oIEXy9yYdqWfqdrFAYAAr6syP8eLEFI7ZE4939antx2mNgPRW/o1ybm2SFYkbTVA==} + '@typescript-eslint/parser@7.13.1': + resolution: {integrity: sha512-1ELDPlnLvDQ5ybTSrMhRTFDfOQEOXNM+eP+3HT/Yq7ruWpciQw+Avi73pdEbA4SooCawEWo3dtYbF68gN7Ed1A==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: eslint: ^8.56.0 @@ -3811,12 +3686,12 @@ packages: resolution: {integrity: sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@typescript-eslint/scope-manager@7.13.0': - resolution: {integrity: sha512-ZrMCe1R6a01T94ilV13egvcnvVJ1pxShkE0+NDjDzH4nvG1wXpwsVI5bZCvE7AEDH1mXEx5tJSVR68bLgG7Dng==} + '@typescript-eslint/scope-manager@7.13.1': + resolution: {integrity: sha512-adbXNVEs6GmbzaCpymHQ0MB6E4TqoiVbC0iqG3uijR8ZYfpAXMGttouQzF4Oat3P2GxDVIrg7bMI/P65LiQZdg==} engines: {node: ^18.18.0 || >=20.0.0} - '@typescript-eslint/type-utils@7.13.0': - resolution: {integrity: sha512-xMEtMzxq9eRkZy48XuxlBFzpVMDurUAfDu5Rz16GouAtXm0TaAoTFzqWUFPPuQYXI/CDaH/Bgx/fk/84t/Bc9A==} + '@typescript-eslint/type-utils@7.13.1': + resolution: {integrity: sha512-aWDbLu1s9bmgPGXSzNCxELu+0+HQOapV/y+60gPXafR8e2g1Bifxzevaa+4L2ytCWm+CHqpELq4CSoN9ELiwCg==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: eslint: ^8.56.0 @@ -3829,8 +3704,8 @@ packages: resolution: {integrity: sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@typescript-eslint/types@7.13.0': - resolution: {integrity: sha512-QWuwm9wcGMAuTsxP+qz6LBBd3Uq8I5Nv8xb0mk54jmNoCyDspnMvVsOxI6IsMmway5d1S9Su2+sCKv1st2l6eA==} + '@typescript-eslint/types@7.13.1': + resolution: {integrity: sha512-7K7HMcSQIAND6RBL4kDl24sG/xKM13cA85dc7JnmQXw2cBDngg7c19B++JzvJHRG3zG36n9j1i451GBzRuHchw==} engines: {node: ^18.18.0 || >=20.0.0} '@typescript-eslint/typescript-estree@5.62.0': @@ -3842,8 +3717,8 @@ packages: typescript: optional: true - '@typescript-eslint/typescript-estree@7.13.0': - resolution: {integrity: sha512-cAvBvUoobaoIcoqox1YatXOnSl3gx92rCZoMRPzMNisDiM12siGilSM4+dJAekuuHTibI2hVC2fYK79iSFvWjw==} + '@typescript-eslint/typescript-estree@7.13.1': + resolution: {integrity: sha512-uxNr51CMV7npU1BxZzYjoVz9iyjckBduFBP0S5sLlh1tXYzHzgZ3BR9SVsNed+LmwKrmnqN3Kdl5t7eZ5TS1Yw==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: typescript: '*' @@ -3857,8 +3732,8 @@ packages: peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - '@typescript-eslint/utils@7.13.0': - resolution: {integrity: sha512-jceD8RgdKORVnB4Y6BqasfIkFhl4pajB1wVxrF4akxD2QPM8GNYjgGwEzYS+437ewlqqrg7Dw+6dhdpjMpeBFQ==} + '@typescript-eslint/utils@7.13.1': + resolution: {integrity: sha512-h5MzFBD5a/Gh/fvNdp9pTfqJAbuQC4sCN2WzuXme71lqFJsZtLbjxfSk4r3p02WIArOF9N94pdsLiGutpDbrXQ==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: eslint: ^8.56.0 @@ -3867,8 +3742,8 @@ packages: resolution: {integrity: sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@typescript-eslint/visitor-keys@7.13.0': - resolution: {integrity: sha512-nxn+dozQx+MK61nn/JP+M4eCkHDSxSLDpgE3WcQo0+fkjEolnaB5jswvIKC4K56By8MMgIho7f1PVxERHEo8rw==} + '@typescript-eslint/visitor-keys@7.13.1': + resolution: {integrity: sha512-k/Bfne7lrP7hcb7m9zSsgcBmo+8eicqqfNAJ7uUY+jkTFpKeH2FSkWpFRtimBxgkyvqfu9jTPRbYOvud6isdXA==} engines: {node: ^18.18.0 || >=20.0.0} '@ungap/structured-clone@1.2.0': @@ -3943,23 +3818,11 @@ packages: '@visx/vendor@3.5.0': resolution: {integrity: sha512-yt3SEZRVmt36+APsCISSO9eSOtzQkBjt+QRxNRzcTWuzwMAaF3PHCCSe31++kkpgY9yFoF+Gfes1TBe5NlETiQ==} - '@vitejs/plugin-basic-ssl@1.1.0': - resolution: {integrity: sha512-wO4Dk/rm8u7RNhOf95ZzcEmC9rYOncYgvq4z3duaJrCgjN8BxAnDVyndanfcJZ0O6XZzHz6Q0hTimxTg8Y9g/A==} - engines: {node: '>=14.6.0'} - peerDependencies: - vite: ^3.0.0 || ^4.0.0 || ^5.0.0 - '@vitejs/plugin-react-swc@3.7.0': resolution: {integrity: sha512-yrknSb3Dci6svCd/qhHqhFPDSw0QtjumcqdKMoNNzmOl5lMXTTiqzjWtG4Qask2HdvvzaNgSunbQGet8/GrKdA==} peerDependencies: vite: ^4 || ^5 - '@vitejs/plugin-react@4.3.1': - resolution: {integrity: sha512-m/V2syj5CuVnaxcUJOQRel/Wr31FFXRFlnOoq1TVtkCxsY5veGMTEmpWHndrhB2U8ScHtCQB1e+4hWYExQc6Lg==} - engines: {node: ^14.18.0 || >=16.0.0} - peerDependencies: - vite: ^4.2.0 || ^5.0.0 - '@vitest/browser@1.6.0': resolution: {integrity: sha512-3Wpp9h1hf++rRVPvoXevkdHybLhJVn7MwIMKMIh08tVaoDMmT6fnNhbP222Z48V9PptpYeA5zvH9Ct/ZcaAzmQ==} peerDependencies: @@ -3999,32 +3862,6 @@ packages: '@vitest/utils@1.6.0': resolution: {integrity: sha512-21cPiuGMoMZwiOHa2i4LXkMkMkCGzA+MVFV70jRwHo95dL4x/ts5GZhML1QWuy7yfp3WzK3lRvZi3JnXTYqrBw==} - '@volar/language-core@1.11.1': - resolution: {integrity: sha512-dOcNn3i9GgZAcJt43wuaEykSluAuOkQgzni1cuxLxTV0nJKanQztp7FxyswdRILaKH+P2XZMPRp2S4MV/pElCw==} - - '@volar/source-map@1.11.1': - resolution: {integrity: sha512-hJnOnwZ4+WT5iupLRnuzbULZ42L7BWWPMmruzwtLhJfpDVoZLjNBxHDi2sY2bgZXCKlpU5XcsMFoYrsQmPhfZg==} - - '@volar/typescript@1.11.1': - resolution: {integrity: sha512-iU+t2mas/4lYierSnoFOeRFQUhAEMgsFuQxoxvwn5EdQopw43j+J27a4lt9LMInx1gLJBC6qL14WYGlgymaSMQ==} - - '@vue/compiler-core@3.4.27': - resolution: {integrity: sha512-E+RyqY24KnyDXsCuQrI+mlcdW3ALND6U7Gqa/+bVwbcpcR3BRRIckFoz7Qyd4TTlnugtwuI7YgjbvsLmxb+yvg==} - - '@vue/compiler-dom@3.4.27': - resolution: {integrity: sha512-kUTvochG/oVgE1w5ViSr3KUBh9X7CWirebA3bezTbB5ZKBQZwR2Mwj9uoSKRMFcz4gSMzzLXBPD6KpCLb9nvWw==} - - '@vue/language-core@1.8.27': - resolution: {integrity: sha512-L8Kc27VdQserNaCUNiSFdDl9LWT24ly8Hpwf1ECy3aFb9m6bDhBGQYOujDm21N7EW3moKIOKEanQwe1q5BK+mA==} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - - '@vue/shared@3.4.27': - resolution: {integrity: sha512-DL3NmY2OFlqmYYrzp39yi3LDkKxa5vZVwxWdQ3rG0ekuWscHraeIbnI8t+aZK7qhYqEqWKTUdijadunb9pnrgA==} - '@webassemblyjs/ast@1.12.1': resolution: {integrity: sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==} @@ -4141,8 +3978,8 @@ packages: resolution: {integrity: sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==} engines: {node: '>=0.4.0'} - acorn-walk@8.3.2: - resolution: {integrity: sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==} + acorn-walk@8.3.3: + resolution: {integrity: sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==} engines: {node: '>=0.4.0'} acorn@7.4.1: @@ -4150,8 +3987,8 @@ packages: engines: {node: '>=0.4.0'} hasBin: true - acorn@8.11.3: - resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} + acorn@8.12.0: + resolution: {integrity: sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==} engines: {node: '>=0.4.0'} hasBin: true @@ -4299,9 +4136,6 @@ packages: array-flatten@3.0.0: resolution: {integrity: sha512-zPMVc3ZYlGLNk4mpK1NzP2wg0ml9t7fUgDsayR5Y5rSzxQilzR9FGu/EH2jQOcKSAeAfWeylyW8juy3OkWRvNA==} - array-from-async@3.0.0: - resolution: {integrity: sha512-gV8/L4y2QB5JTXL9DMdtspGyed2M3V6nMnSN+nNg8ejyUlAAbKAjRS6pfWWINjU/MuFJFMGWPazHPor7hThXQw==} - array-includes@3.1.8: resolution: {integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==} engines: {node: '>= 0.4'} @@ -4514,10 +4348,6 @@ packages: buffer@6.0.3: resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} - bufferutil@4.0.8: - resolution: {integrity: sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==} - engines: {node: '>=6.14.2'} - bytes@3.0.0: resolution: {integrity: sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==} engines: {node: '>= 0.8'} @@ -4570,8 +4400,8 @@ packages: camelize@1.0.1: resolution: {integrity: sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==} - caniuse-lite@1.0.30001632: - resolution: {integrity: sha512-udx3o7yHJfUxMLkGohMlVHCvFvWmirKh9JAH/d7WOLPetlH+LTL5cocMZ0t7oZx/mdlOWXti97xLZWc8uURRHg==} + caniuse-lite@1.0.30001636: + resolution: {integrity: sha512-bMg2vmr8XBsbL6Lr0UHXy/21m84FTxDLWn2FSqMd5PrlbMxwJlQnC2YWYxVgp66PZE+BBNF2jYQUBKCo1FDeZg==} cardinal@2.1.1: resolution: {integrity: sha512-JSr5eOgoEymtYHBjNWyjrMqet9Am2miJhlfKNdqLp6zoeAh0KN5dRAcxlecj5mAJrmQomgiOBj35xHLrFjqBpw==} @@ -4773,10 +4603,6 @@ packages: resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} engines: {node: '>= 12'} - commander@9.5.0: - resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} - engines: {node: ^12.20.0 || >=14} - commondir@1.0.1: resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} @@ -4792,9 +4618,6 @@ packages: resolution: {integrity: sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==} engines: {node: '>= 0.8.0'} - computeds@0.0.1: - resolution: {integrity: sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q==} - concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} @@ -5049,9 +4872,6 @@ packages: resolution: {integrity: sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==} engines: {node: '>= 0.4'} - de-indent@1.0.2: - resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==} - debounce@1.2.1: resolution: {integrity: sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==} @@ -5300,8 +5120,8 @@ packages: engines: {node: '>=0.10.0'} hasBin: true - electron-to-chromium@1.4.799: - resolution: {integrity: sha512-3D3DwWkRTzrdEpntY0hMLYwj7SeBk1138CkPE8sBDSj3WzrzOiG2rHm3luw8jucpf+WiyLBCZyU9lMHyQI9M9Q==} + electron-to-chromium@1.4.806: + resolution: {integrity: sha512-nkoEX2QIB8kwCOtvtgwhXWy2IHVcOLQZu9Qo36uaGB835mdX/h8uLRlosL6QIhLVUnAiicXRW00PwaPZC74Nrg==} emoji-regex@10.3.0: resolution: {integrity: sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==} @@ -5409,6 +5229,11 @@ packages: engines: {node: '>=12'} hasBin: true + esbuild@0.21.5: + resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} + engines: {node: '>=12'} + hasBin: true + escalade@3.1.2: resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} engines: {node: '>=6'} @@ -5552,13 +5377,13 @@ packages: resolution: {integrity: sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - eslint@9.4.0: - resolution: {integrity: sha512-sjc7Y8cUD1IlwYcTS9qPSvGjAC8Ne9LctpxKKu3x/1IC9bnOg98Zy6GxEJUfr1NojMgVPlyANXYns8oE2c1TAA==} + eslint@9.5.0: + resolution: {integrity: sha512-+NAOZFrW/jFTS3dASCGBxX1pkFD0/fsO+hfAkJ4TyYKwgsXZbqzrw+seCYFCcPCYXvnD67tAnglU7GQTz6kcVw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} hasBin: true - espree@10.0.1: - resolution: {integrity: sha512-MWkrWZbJsL2UwnjxTX3gG8FneachS/Mwg7tdGXce011sJd5b0JG54vat5KHnfSBODZ3Wvzd2WnjxyzsRoVv+ww==} + espree@10.1.0: + resolution: {integrity: sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} esprima@4.0.1: @@ -5640,10 +5465,6 @@ packages: resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==} engines: {node: '>=4'} - fake-indexeddb@6.0.0: - resolution: {integrity: sha512-YEboHE5VfopUclOck7LncgIqskAqnv4q0EWbYCaxKKjAvO93c+TJIaBuGy8CBFdbg9nKdpN3AuPRwVBJ4k7NrQ==} - engines: {node: '>=18'} - fast-check@3.17.2: resolution: {integrity: sha512-+3DPTxtxABLgmmVpYxrash3DHoq0cMa1jjLYNp3qqokKKhqVEaS4lbnaDKqWU5Dd6C2pEudPPBAEEQ9nUou9OQ==} engines: {node: '>=8.0.0'} @@ -5756,8 +5577,8 @@ packages: flatted@3.3.1: resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} - flow-parser@0.237.2: - resolution: {integrity: sha512-mvI/kdfr3l1waaPbThPA8dJa77nHXrfZIun+SWvFwSwDjmeByU7mGJGRmv1+7guU6ccyLV8e1lqZA1lD4iMGnQ==} + flow-parser@0.238.0: + resolution: {integrity: sha512-VE7XSv1epljsIN2YeBnxCmGJihpNIAnLLu/pPOdA+Gkso7qDltJwUi6vfHjgxdBbjSdAuPGnhuOHJUQG+yYwIg==} engines: {node: '>=0.4.0'} fn.name@1.1.0: @@ -5766,8 +5587,8 @@ packages: for-each@0.3.3: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} - foreground-child@3.2.0: - resolution: {integrity: sha512-CrWQNaEl1/6WeZoarcM9LHupTo3RpZO2Pdk1vktwzPiQTsJnAKJmm3TACKeG5UZbWDfaH2AbvYxzP96y0MT7fA==} + foreground-child@3.2.1: + resolution: {integrity: sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==} engines: {node: '>=14'} form-data@2.5.1: @@ -5958,8 +5779,8 @@ packages: glob-to-regexp@0.4.1: resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} - glob@10.4.1: - resolution: {integrity: sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==} + glob@10.4.2: + resolution: {integrity: sha512-GwMlUF6PkPo3Gk21UxkCohOv0PLcIXVtKyLlpEI28R/cO/4eNOdmLk3CMW1wROV/WR/EsZOWAfBbBOqYvs88/w==} engines: {node: '>=16 || 14 >=14.18'} hasBin: true @@ -6214,10 +6035,6 @@ packages: resolution: {integrity: sha512-m7ZEHgtw69qOGw+jwxXkHlrlIPdTGkyh66zXZ1ajZbxkDBNjSY/LGbmjc7h0s2ELsUDTAhFr55TrPSSqJGPG0A==} engines: {node: '>=4'} - import-lazy@4.0.0: - resolution: {integrity: sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==} - engines: {node: '>=8'} - import-local@3.1.0: resolution: {integrity: sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==} engines: {node: '>=8'} @@ -6707,9 +6524,6 @@ packages: resolution: {integrity: sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==} engines: {node: '>= 8'} - kolorist@1.8.0: - resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==} - kuler@2.0.0: resolution: {integrity: sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==} @@ -6805,9 +6619,6 @@ packages: lodash.isboolean@3.0.3: resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==} - lodash.isequal@4.5.0: - resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==} - lodash.isinteger@4.0.4: resolution: {integrity: sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==} @@ -7018,9 +6829,6 @@ packages: resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} engines: {node: '>=4'} - minimatch@3.0.8: - resolution: {integrity: sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==} - minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -7118,9 +6926,6 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - muggle-string@0.3.1: - resolution: {integrity: sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg==} - mute-stream@0.0.8: resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==} @@ -7189,10 +6994,6 @@ packages: resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - node-gyp-build@4.8.1: - resolution: {integrity: sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==} - hasBin: true - node-gyp@10.1.0: resolution: {integrity: sha512-B4J5M1cABxPc5PwfjhbV5hoy2DP9p8lFXASnEN6hugXOa61416tnTZ29x9sSwAd0o99XNIcpvDDy1swAExsVKA==} engines: {node: ^16.14.0 || >=18.0.0} @@ -7414,6 +7215,9 @@ packages: resolution: {integrity: sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==} engines: {node: '>= 14'} + package-json-from-dist@1.0.0: + resolution: {integrity: sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==} + pako@0.2.9: resolution: {integrity: sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==} @@ -7444,9 +7248,6 @@ packages: pascal-case@3.1.2: resolution: {integrity: sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==} - path-browserify@1.0.1: - resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} - path-case@2.1.1: resolution: {integrity: sha512-Ou0N05MioItesaLr9q8TtHVWmJ6fxWdqKB2RohFmNWVyJ+2zeKIeDNWAN6B/Pe7wpzWChhZX6nONYmOnMeJQ/Q==} @@ -7885,8 +7686,8 @@ packages: resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} hasBin: true - re2@1.21.2: - resolution: {integrity: sha512-f8jqI0vCbwDhzY66Fgx1V2RoNDdmAupKkqRqR/AEF+2/MZNRbtEOjax6oHSht95MU40vx6+2ITsJr/9esukckg==} + re2@1.21.3: + resolution: {integrity: sha512-GI+KoGkHT4kxTaX+9p0FgNB1XUnCndO9slG5qqeEoZ7kbf6Dk6ohQVpmwKVeSp7LPLn+g6Q3BaCopz4oHuBDuQ==} react-colorful@5.6.1: resolution: {integrity: sha512-1exovf0uGTGyq5mXQT0zgQ80uvj2PCwvF8zY1RN9/vbJVSjSo3fsB/4L3ObbF7u70NduSiK4xu4Y6q1MHoUGEw==} @@ -7933,10 +7734,6 @@ packages: react: ^16.0.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 - react-refresh@0.14.2: - resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==} - engines: {node: '>=0.10.0'} - react-remove-scroll-bar@2.3.6: resolution: {integrity: sha512-DtSYaao4mBmX+HDo5YWYdBWQwYIQQshUV/dVxFxK+KM26Wjwp1gZ6rv6OC3oujI6Bfu6Xyg3TwK533AQutsn/g==} engines: {node: '>=10'} @@ -8150,9 +7947,6 @@ packages: resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - resolve@1.19.0: - resolution: {integrity: sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==} - resolve@1.22.8: resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} hasBin: true @@ -8283,11 +8077,6 @@ packages: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true - semver@7.5.4: - resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} - engines: {node: '>=10'} - hasBin: true - semver@7.6.0: resolution: {integrity: sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==} engines: {node: '>=10'} @@ -8493,8 +8282,8 @@ packages: store2@2.14.3: resolution: {integrity: sha512-4QcZ+yx7nzEFiV4BMLnr/pRa5HYzNITX2ri0Zh6sT9EyQHbBHacC6YigllUPU9X3D0f/22QCgfokpKs52YRrUg==} - storybook@8.1.6: - resolution: {integrity: sha512-qouQEB+sSb9ktE6fGVoBy6CLEUq4NOqDUpt/EhnITaWqzUeAZSQXTcoHg9DXhTMiynnbfqsUcZuK9PZOjgt7/w==} + storybook@8.1.10: + resolution: {integrity: sha512-HHlZibyc/QkcQj8aEnYnYwEl+ItNZ/uRbCdkvJzu/vIWYon5jUg30mHFIGZprgLSt27CxOs30Et8yT9z4VhwjA==} hasBin: true stream-chain@2.2.5: @@ -8512,10 +8301,6 @@ packages: stream-transform@2.1.3: resolution: {integrity: sha512-9GHUiM5hMiCi6Y03jD2ARC1ettBXkQBoQAe7nJsPknnI0ow10aXjTnew8QtYQmLjzn974BnmWEAJgCY6ZP1DeQ==} - string-argv@0.3.2: - resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} - engines: {node: '>=0.6.19'} - string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} @@ -9007,8 +8792,8 @@ packages: typedarray-to-buffer@3.1.5: resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} - typescript-eslint@7.13.0: - resolution: {integrity: sha512-upO0AXxyBwJ4BbiC6CRgAJKtGYha2zw4m1g7TIVPSonwYEuf7vCicw3syjS1OxdDMTz96sZIXl3Jx3vWJLLKFw==} + typescript-eslint@7.13.1: + resolution: {integrity: sha512-pvLEuRs8iS9s3Cnp/Wt//hpK8nKc8hVa3cLljHqzaJJQYP8oys8GUyIFqtlev+2lT/fqMPcyQko+HJ6iYK3nFA==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: eslint: ^8.56.0 @@ -9017,11 +8802,6 @@ packages: typescript: optional: true - typescript@5.4.2: - resolution: {integrity: sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==} - engines: {node: '>=14.17'} - hasBin: true - typescript@5.4.5: resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==} engines: {node: '>=14.17'} @@ -9170,16 +8950,17 @@ packages: peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 + use-sync-external-store@1.2.2: + resolution: {integrity: sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + usehooks-ts@3.1.0: resolution: {integrity: sha512-bBIa7yUyPhE1BCc0GmR96VU/15l/9gP1Ch5mYdLcFBaFGQsdmXkvjV0TtOqW1yUd6VjIwDunm+flSciCQXujiw==} engines: {node: '>=16.15.0'} peerDependencies: react: ^16.8.0 || ^17 || ^18 - utf-8-validate@6.0.4: - resolution: {integrity: sha512-xu9GQDeFp+eZ6LnCywXN/zBancWvOpUMzgjLPSjy4BRHSmTelvn2E0DG0o1sTiw5hkCKBHo8rwSKncfRfv2EEQ==} - engines: {node: '>=6.14.2'} - util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} @@ -9214,10 +8995,6 @@ packages: resolution: {integrity: sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - validator@13.12.0: - resolution: {integrity: sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==} - engines: {node: '>= 0.10'} - vary@1.1.2: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} @@ -9227,21 +9004,6 @@ packages: engines: {node: ^18.0.0 || >=20.0.0} hasBin: true - vite-plugin-dts@3.9.1: - resolution: {integrity: sha512-rVp2KM9Ue22NGWB8dNtWEr+KekN3rIgz1tWD050QnRGlriUCmaDwa7qA5zDEjbXg5lAXhYMSBJtx3q3hQIJZSg==} - engines: {node: ^14.18.0 || >=16.0.0} - peerDependencies: - typescript: '*' - vite: '*' - peerDependenciesMeta: - vite: - optional: true - - vite-plugin-externalize-deps@0.8.0: - resolution: {integrity: sha512-MdC8kRNQ1ZjhUicU2HcqGVhL0UUFqv83Zp1JZdHjE82PoPR8wsSWZ3axpot7B6img3sW6g8shYJikE0CKA0chA==} - peerDependencies: - vite: ^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 - vite-plugin-top-level-await@1.4.1: resolution: {integrity: sha512-hogbZ6yT7+AqBaV6lK9JRNvJDn4/IJvHLu6ET06arNfo0t2IsyCaon7el9Xa8OumH+ESuq//SDf8xscZFE0rWw==} peerDependencies: @@ -9252,8 +9014,8 @@ packages: peerDependencies: vite: ^2 || ^3 || ^4 || ^5 - vite@5.2.13: - resolution: {integrity: sha512-SSq1noJfY9pR3I1TUENL3rQYDQCFqgD+lM6fTRAM8Nv6Lsg5hDLaXkjETVeBt+7vZBCMoibD+6IWnT2mJ+Zb/A==} + vite@5.3.1: + resolution: {integrity: sha512-XBmSKRLXLxiaPYamLv3/hnP/KXDai1NDexN0FpkTaZXTfycHvkRHoenpgl/fvuK/kPbB6xAgoyiryAhQNxYmAQ==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: @@ -9305,15 +9067,6 @@ packages: jsdom: optional: true - vue-template-compiler@2.7.16: - resolution: {integrity: sha512-AYbUWAJHLGGQM7+cNTELw+KsOG9nl2CnSv467WobS5Cv9uk3wFcnr1Etsz2sEIHEZvw1U+o9mRlEO6QbZvUPGQ==} - - vue-tsc@1.8.27: - resolution: {integrity: sha512-WesKCAZCRAbmmhuGl3+VrdWItEvfoFIPXOvUJkjULi+x+6G/Dy69yO3TBRJDr9eUlmsNAwVmxsNZxvHKzbkKdg==} - hasBin: true - peerDependencies: - typescript: '*' - w3c-xmlserializer@5.0.0: resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} engines: {node: '>=18'} @@ -9479,8 +9232,8 @@ packages: write-file-atomic@3.0.3: resolution: {integrity: sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==} - ws@7.5.9: - resolution: {integrity: sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==} + ws@7.5.10: + resolution: {integrity: sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==} engines: {node: '>=8.3.0'} peerDependencies: bufferutil: ^4.0.1 @@ -9491,8 +9244,8 @@ packages: utf-8-validate: optional: true - ws@8.17.0: - resolution: {integrity: sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==} + ws@8.17.1: + resolution: {integrity: sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 @@ -9571,11 +9324,6 @@ packages: resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==} engines: {node: '>=12.20'} - z-schema@5.0.5: - resolution: {integrity: sha512-D7eujBWkLa3p2sIpJA0d1pr7es+a7m0vFAnZLlCEKq/Ij2k0MLi9Br2UPxoxdYystm5K1yeBGzub0FlYUEWj2Q==} - engines: {node: '>=8.0.0'} - hasBin: true - zip-stream@4.1.1: resolution: {integrity: sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==} engines: {node: '>= 10'} @@ -10209,23 +9957,13 @@ snapshots: dependencies: '@babel/core': 7.24.7 '@babel/helper-annotate-as-pure': 7.24.7 - '@babel/helper-create-class-features-plugin': 7.24.7(@babel/core@7.24.7) - '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.24.7) - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-property-literals@7.24.7(@babel/core@7.24.7)': - dependencies: - '@babel/core': 7.24.7 - '@babel/helper-plugin-utils': 7.24.7 - - '@babel/plugin-transform-react-jsx-self@7.24.7(@babel/core@7.24.7)': - dependencies: - '@babel/core': 7.24.7 + '@babel/helper-create-class-features-plugin': 7.24.7(@babel/core@7.24.7) '@babel/helper-plugin-utils': 7.24.7 + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.24.7) + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-react-jsx-source@7.24.7(@babel/core@7.24.7)': + '@babel/plugin-transform-property-literals@7.24.7(@babel/core@7.24.7)': dependencies: '@babel/core': 7.24.7 '@babel/helper-plugin-utils': 7.24.7 @@ -10463,270 +10201,323 @@ snapshots: '@base2/pretty-print-object@1.0.1': {} - '@buf/connectrpc_eliza.bufbuild_es@1.7.2-20230913231627-233fca715f49.1(@bufbuild/protobuf@1.10.0)': + '@buf/connectrpc_eliza.bufbuild_es@1.10.0-20230913231627-233fca715f49.1(@bufbuild/protobuf@1.10.0)': dependencies: '@bufbuild/protobuf': 1.10.0 - '@buf/connectrpc_eliza.bufbuild_es@1.9.0-20230913231627-233fca715f49.1(@bufbuild/protobuf@1.10.0)': + '@buf/connectrpc_eliza.bufbuild_es@1.7.2-20230913231627-233fca715f49.2(@bufbuild/protobuf@1.10.0)': dependencies: '@bufbuild/protobuf': 1.10.0 - '@buf/connectrpc_eliza.connectrpc_es@1.4.0-20230913231627-233fca715f49.2(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))': + '@buf/connectrpc_eliza.connectrpc_es@1.4.0-20230913231627-233fca715f49.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))': dependencies: - '@buf/connectrpc_eliza.bufbuild_es': 1.7.2-20230913231627-233fca715f49.1(@bufbuild/protobuf@1.10.0) + '@buf/connectrpc_eliza.bufbuild_es': 1.7.2-20230913231627-233fca715f49.2(@bufbuild/protobuf@1.10.0) '@connectrpc/connect': 1.4.0(@bufbuild/protobuf@1.10.0) transitivePeerDependencies: - '@bufbuild/protobuf' - '@buf/cosmos_cosmos-proto.bufbuild_es@1.7.2-20211202220400-1935555c206d.1(@bufbuild/protobuf@1.10.0)': + '@buf/cosmos_cosmos-proto.bufbuild_es@1.10.0-20211202220400-1935555c206d.1(@bufbuild/protobuf@1.10.0)': dependencies: '@bufbuild/protobuf': 1.10.0 - '@buf/cosmos_cosmos-proto.bufbuild_es@1.9.0-20211202220400-1935555c206d.1(@bufbuild/protobuf@1.10.0)': + '@buf/cosmos_cosmos-proto.bufbuild_es@1.7.2-20211202220400-1935555c206d.2(@bufbuild/protobuf@1.10.0)': dependencies: '@bufbuild/protobuf': 1.10.0 - '@buf/cosmos_cosmos-proto.connectrpc_es@1.4.0-20211202220400-1935555c206d.2(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))': + '@buf/cosmos_cosmos-proto.connectrpc_es@1.4.0-20211202220400-1935555c206d.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))': dependencies: - '@buf/cosmos_cosmos-proto.bufbuild_es': 1.7.2-20211202220400-1935555c206d.1(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_cosmos-proto.bufbuild_es': 1.7.2-20211202220400-1935555c206d.2(@bufbuild/protobuf@1.10.0) '@connectrpc/connect': 1.4.0(@bufbuild/protobuf@1.10.0) transitivePeerDependencies: - '@bufbuild/protobuf' - '@buf/cosmos_cosmos-sdk.bufbuild_es@1.7.2-20230522115704-e7a85cef453e.1(@bufbuild/protobuf@1.10.0)': + '@buf/cosmos_cosmos-sdk.bufbuild_es@1.10.0-20230522115704-e7a85cef453e.1(@bufbuild/protobuf@1.10.0)': dependencies: - '@buf/cosmos_cosmos-proto.bufbuild_es': 1.7.2-20211202220400-1935555c206d.1(@bufbuild/protobuf@1.10.0) - '@buf/cosmos_gogo-proto.bufbuild_es': 1.7.2-20221020125208-34d970b699f8.1(@bufbuild/protobuf@1.10.0) - '@buf/googleapis_googleapis.bufbuild_es': 1.7.2-20221214150216-75b4300737fb.1(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_cosmos-proto.bufbuild_es': 1.10.0-20211202220400-1935555c206d.1(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_gogo-proto.bufbuild_es': 1.10.0-20221020125208-34d970b699f8.1(@bufbuild/protobuf@1.10.0) + '@buf/googleapis_googleapis.bufbuild_es': 1.10.0-20221214150216-75b4300737fb.1(@bufbuild/protobuf@1.10.0) '@bufbuild/protobuf': 1.10.0 - '@buf/cosmos_cosmos-sdk.bufbuild_es@1.7.2-20230719110346-aa25660f4ff7.1(@bufbuild/protobuf@1.10.0)': + '@buf/cosmos_cosmos-sdk.bufbuild_es@1.10.0-20230719110346-aa25660f4ff7.1(@bufbuild/protobuf@1.10.0)': dependencies: - '@buf/cosmos_cosmos-proto.bufbuild_es': 1.7.2-20211202220400-1935555c206d.1(@bufbuild/protobuf@1.10.0) - '@buf/cosmos_gogo-proto.bufbuild_es': 1.7.2-20230509103710-5e5b9fdd0180.1(@bufbuild/protobuf@1.10.0) - '@buf/googleapis_googleapis.bufbuild_es': 1.7.2-20230502210827-cc916c318597.1(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_cosmos-proto.bufbuild_es': 1.10.0-20211202220400-1935555c206d.1(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_gogo-proto.bufbuild_es': 1.10.0-20230509103710-5e5b9fdd0180.1(@bufbuild/protobuf@1.10.0) + '@buf/googleapis_googleapis.bufbuild_es': 1.10.0-20230502210827-cc916c318597.1(@bufbuild/protobuf@1.10.0) '@bufbuild/protobuf': 1.10.0 - '@buf/cosmos_cosmos-sdk.bufbuild_es@1.9.0-20230522115704-e7a85cef453e.1(@bufbuild/protobuf@1.10.0)': + '@buf/cosmos_cosmos-sdk.bufbuild_es@1.7.2-20230522115704-e7a85cef453e.2(@bufbuild/protobuf@1.10.0)': dependencies: - '@buf/cosmos_cosmos-proto.bufbuild_es': 1.9.0-20211202220400-1935555c206d.1(@bufbuild/protobuf@1.10.0) - '@buf/cosmos_gogo-proto.bufbuild_es': 1.9.0-20221020125208-34d970b699f8.1(@bufbuild/protobuf@1.10.0) - '@buf/googleapis_googleapis.bufbuild_es': 1.9.0-20221214150216-75b4300737fb.1(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_cosmos-proto.bufbuild_es': 1.7.2-20211202220400-1935555c206d.2(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_gogo-proto.bufbuild_es': 1.7.2-20221020125208-34d970b699f8.2(@bufbuild/protobuf@1.10.0) + '@buf/googleapis_googleapis.bufbuild_es': 1.7.2-20221214150216-75b4300737fb.2(@bufbuild/protobuf@1.10.0) '@bufbuild/protobuf': 1.10.0 - '@buf/cosmos_cosmos-sdk.bufbuild_es@1.9.0-20230719110346-aa25660f4ff7.1(@bufbuild/protobuf@1.10.0)': + '@buf/cosmos_cosmos-sdk.bufbuild_es@1.7.2-20230719110346-aa25660f4ff7.2(@bufbuild/protobuf@1.10.0)': dependencies: - '@buf/cosmos_cosmos-proto.bufbuild_es': 1.9.0-20211202220400-1935555c206d.1(@bufbuild/protobuf@1.10.0) - '@buf/cosmos_gogo-proto.bufbuild_es': 1.9.0-20230509103710-5e5b9fdd0180.1(@bufbuild/protobuf@1.10.0) - '@buf/googleapis_googleapis.bufbuild_es': 1.9.0-20230502210827-cc916c318597.1(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_cosmos-proto.bufbuild_es': 1.7.2-20211202220400-1935555c206d.2(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_gogo-proto.bufbuild_es': 1.7.2-20230509103710-5e5b9fdd0180.2(@bufbuild/protobuf@1.10.0) + '@buf/googleapis_googleapis.bufbuild_es': 1.7.2-20230502210827-cc916c318597.2(@bufbuild/protobuf@1.10.0) '@bufbuild/protobuf': 1.10.0 - '@buf/cosmos_cosmos-sdk.connectrpc_es@1.4.0-20230522115704-e7a85cef453e.2(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))': + '@buf/cosmos_cosmos-sdk.connectrpc_es@1.4.0-20230522115704-e7a85cef453e.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))': dependencies: - '@buf/cosmos_cosmos-proto.connectrpc_es': 1.4.0-20211202220400-1935555c206d.2(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) - '@buf/cosmos_cosmos-sdk.bufbuild_es': 1.7.2-20230522115704-e7a85cef453e.1(@bufbuild/protobuf@1.10.0) - '@buf/cosmos_gogo-proto.connectrpc_es': 1.4.0-20221020125208-34d970b699f8.2(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) - '@buf/googleapis_googleapis.connectrpc_es': 1.4.0-20221214150216-75b4300737fb.2(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) + '@buf/cosmos_cosmos-proto.connectrpc_es': 1.4.0-20211202220400-1935555c206d.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) + '@buf/cosmos_cosmos-sdk.bufbuild_es': 1.7.2-20230522115704-e7a85cef453e.2(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_gogo-proto.connectrpc_es': 1.4.0-20221020125208-34d970b699f8.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) + '@buf/googleapis_googleapis.connectrpc_es': 1.4.0-20221214150216-75b4300737fb.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) '@connectrpc/connect': 1.4.0(@bufbuild/protobuf@1.10.0) transitivePeerDependencies: - '@bufbuild/protobuf' - '@buf/cosmos_cosmos-sdk.connectrpc_es@1.4.0-20230719110346-aa25660f4ff7.2(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))': + '@buf/cosmos_cosmos-sdk.connectrpc_es@1.4.0-20230719110346-aa25660f4ff7.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))': dependencies: - '@buf/cosmos_cosmos-proto.connectrpc_es': 1.4.0-20211202220400-1935555c206d.2(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) - '@buf/cosmos_cosmos-sdk.bufbuild_es': 1.7.2-20230719110346-aa25660f4ff7.1(@bufbuild/protobuf@1.10.0) - '@buf/cosmos_gogo-proto.connectrpc_es': 1.4.0-20230509103710-5e5b9fdd0180.2(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) - '@buf/googleapis_googleapis.connectrpc_es': 1.4.0-20230502210827-cc916c318597.2(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) + '@buf/cosmos_cosmos-proto.connectrpc_es': 1.4.0-20211202220400-1935555c206d.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) + '@buf/cosmos_cosmos-sdk.bufbuild_es': 1.7.2-20230719110346-aa25660f4ff7.2(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_gogo-proto.connectrpc_es': 1.4.0-20230509103710-5e5b9fdd0180.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) + '@buf/googleapis_googleapis.connectrpc_es': 1.4.0-20230502210827-cc916c318597.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) '@connectrpc/connect': 1.4.0(@bufbuild/protobuf@1.10.0) transitivePeerDependencies: - '@bufbuild/protobuf' - '@buf/cosmos_gogo-proto.bufbuild_es@1.7.2-20221020125208-34d970b699f8.1(@bufbuild/protobuf@1.10.0)': + '@buf/cosmos_gogo-proto.bufbuild_es@1.10.0-20221020125208-34d970b699f8.1(@bufbuild/protobuf@1.10.0)': dependencies: '@bufbuild/protobuf': 1.10.0 - '@buf/cosmos_gogo-proto.bufbuild_es@1.7.2-20230509103710-5e5b9fdd0180.1(@bufbuild/protobuf@1.10.0)': + '@buf/cosmos_gogo-proto.bufbuild_es@1.10.0-20230509103710-5e5b9fdd0180.1(@bufbuild/protobuf@1.10.0)': dependencies: '@bufbuild/protobuf': 1.10.0 - '@buf/cosmos_gogo-proto.bufbuild_es@1.9.0-20221020125208-34d970b699f8.1(@bufbuild/protobuf@1.10.0)': + '@buf/cosmos_gogo-proto.bufbuild_es@1.7.2-20221020125208-34d970b699f8.2(@bufbuild/protobuf@1.10.0)': dependencies: '@bufbuild/protobuf': 1.10.0 - '@buf/cosmos_gogo-proto.bufbuild_es@1.9.0-20230509103710-5e5b9fdd0180.1(@bufbuild/protobuf@1.10.0)': + '@buf/cosmos_gogo-proto.bufbuild_es@1.7.2-20230509103710-5e5b9fdd0180.2(@bufbuild/protobuf@1.10.0)': dependencies: '@bufbuild/protobuf': 1.10.0 - '@buf/cosmos_gogo-proto.connectrpc_es@1.4.0-20221020125208-34d970b699f8.2(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))': + '@buf/cosmos_gogo-proto.connectrpc_es@1.4.0-20221020125208-34d970b699f8.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))': dependencies: - '@buf/cosmos_gogo-proto.bufbuild_es': 1.7.2-20221020125208-34d970b699f8.1(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_gogo-proto.bufbuild_es': 1.7.2-20221020125208-34d970b699f8.2(@bufbuild/protobuf@1.10.0) '@connectrpc/connect': 1.4.0(@bufbuild/protobuf@1.10.0) transitivePeerDependencies: - '@bufbuild/protobuf' - '@buf/cosmos_gogo-proto.connectrpc_es@1.4.0-20230509103710-5e5b9fdd0180.2(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))': + '@buf/cosmos_gogo-proto.connectrpc_es@1.4.0-20230509103710-5e5b9fdd0180.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))': dependencies: - '@buf/cosmos_gogo-proto.bufbuild_es': 1.7.2-20230509103710-5e5b9fdd0180.1(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_gogo-proto.bufbuild_es': 1.7.2-20230509103710-5e5b9fdd0180.2(@bufbuild/protobuf@1.10.0) '@connectrpc/connect': 1.4.0(@bufbuild/protobuf@1.10.0) transitivePeerDependencies: - '@bufbuild/protobuf' - '@buf/cosmos_ibc.bufbuild_es@1.7.2-20230913112312-7ab44ae956a0.1(@bufbuild/protobuf@1.10.0)': + '@buf/cosmos_ibc.bufbuild_es@1.10.0-20230913112312-7ab44ae956a0.1(@bufbuild/protobuf@1.10.0)': + dependencies: + '@buf/cosmos_cosmos-proto.bufbuild_es': 1.10.0-20211202220400-1935555c206d.1(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_cosmos-sdk.bufbuild_es': 1.10.0-20230719110346-aa25660f4ff7.1(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_gogo-proto.bufbuild_es': 1.10.0-20221020125208-34d970b699f8.1(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_ics23.bufbuild_es': 1.10.0-20221207100654-55085f7c710a.1(@bufbuild/protobuf@1.10.0) + '@buf/googleapis_googleapis.bufbuild_es': 1.10.0-20220908150232-8d7204855ec1.1(@bufbuild/protobuf@1.10.0) + '@bufbuild/protobuf': 1.10.0 + + '@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0)': dependencies: - '@buf/cosmos_cosmos-proto.bufbuild_es': 1.7.2-20211202220400-1935555c206d.1(@bufbuild/protobuf@1.10.0) - '@buf/cosmos_cosmos-sdk.bufbuild_es': 1.7.2-20230719110346-aa25660f4ff7.1(@bufbuild/protobuf@1.10.0) - '@buf/cosmos_gogo-proto.bufbuild_es': 1.7.2-20221020125208-34d970b699f8.1(@bufbuild/protobuf@1.10.0) - '@buf/cosmos_ics23.bufbuild_es': 1.7.2-20221207100654-55085f7c710a.1(@bufbuild/protobuf@1.10.0) - '@buf/googleapis_googleapis.bufbuild_es': 1.7.2-20220908150232-8d7204855ec1.1(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_cosmos-proto.bufbuild_es': 1.10.0-20211202220400-1935555c206d.1(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_cosmos-sdk.bufbuild_es': 1.10.0-20230719110346-aa25660f4ff7.1(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_gogo-proto.bufbuild_es': 1.10.0-20221020125208-34d970b699f8.1(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_ics23.bufbuild_es': 1.10.0-20221207100654-55085f7c710a.1(@bufbuild/protobuf@1.10.0) + '@buf/googleapis_googleapis.bufbuild_es': 1.10.0-20220908150232-8d7204855ec1.1(@bufbuild/protobuf@1.10.0) '@bufbuild/protobuf': 1.10.0 - '@buf/cosmos_ibc.bufbuild_es@1.7.2-20240530142100-ad4444393387.1(@bufbuild/protobuf@1.10.0)': + '@buf/cosmos_ibc.bufbuild_es@1.10.0-20240618145807-4698edb0fdb0.1(@bufbuild/protobuf@1.10.0)': dependencies: - '@buf/cosmos_cosmos-proto.bufbuild_es': 1.7.2-20211202220400-1935555c206d.1(@bufbuild/protobuf@1.10.0) - '@buf/cosmos_cosmos-sdk.bufbuild_es': 1.7.2-20230719110346-aa25660f4ff7.1(@bufbuild/protobuf@1.10.0) - '@buf/cosmos_gogo-proto.bufbuild_es': 1.7.2-20221020125208-34d970b699f8.1(@bufbuild/protobuf@1.10.0) - '@buf/cosmos_ics23.bufbuild_es': 1.7.2-20221207100654-55085f7c710a.1(@bufbuild/protobuf@1.10.0) - '@buf/googleapis_googleapis.bufbuild_es': 1.7.2-20220908150232-8d7204855ec1.1(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_cosmos-proto.bufbuild_es': 1.10.0-20211202220400-1935555c206d.1(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_cosmos-sdk.bufbuild_es': 1.10.0-20230719110346-aa25660f4ff7.1(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_gogo-proto.bufbuild_es': 1.10.0-20221020125208-34d970b699f8.1(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_ics23.bufbuild_es': 1.10.0-20221207100654-55085f7c710a.1(@bufbuild/protobuf@1.10.0) + '@buf/googleapis_googleapis.bufbuild_es': 1.10.0-20220908150232-8d7204855ec1.1(@bufbuild/protobuf@1.10.0) '@bufbuild/protobuf': 1.10.0 - '@buf/cosmos_ibc.bufbuild_es@1.9.0-20230913112312-7ab44ae956a0.1(@bufbuild/protobuf@1.10.0)': + '@buf/cosmos_ibc.bufbuild_es@1.7.2-20230913112312-7ab44ae956a0.2(@bufbuild/protobuf@1.10.0)': dependencies: - '@buf/cosmos_cosmos-proto.bufbuild_es': 1.9.0-20211202220400-1935555c206d.1(@bufbuild/protobuf@1.10.0) - '@buf/cosmos_cosmos-sdk.bufbuild_es': 1.9.0-20230719110346-aa25660f4ff7.1(@bufbuild/protobuf@1.10.0) - '@buf/cosmos_gogo-proto.bufbuild_es': 1.9.0-20221020125208-34d970b699f8.1(@bufbuild/protobuf@1.10.0) - '@buf/cosmos_ics23.bufbuild_es': 1.9.0-20221207100654-55085f7c710a.1(@bufbuild/protobuf@1.10.0) - '@buf/googleapis_googleapis.bufbuild_es': 1.9.0-20220908150232-8d7204855ec1.1(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_cosmos-proto.bufbuild_es': 1.7.2-20211202220400-1935555c206d.2(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_cosmos-sdk.bufbuild_es': 1.7.2-20230719110346-aa25660f4ff7.2(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_gogo-proto.bufbuild_es': 1.7.2-20221020125208-34d970b699f8.2(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_ics23.bufbuild_es': 1.7.2-20221207100654-55085f7c710a.2(@bufbuild/protobuf@1.10.0) + '@buf/googleapis_googleapis.bufbuild_es': 1.7.2-20220908150232-8d7204855ec1.2(@bufbuild/protobuf@1.10.0) '@bufbuild/protobuf': 1.10.0 - '@buf/cosmos_ibc.bufbuild_es@1.9.0-20240530142100-ad4444393387.1(@bufbuild/protobuf@1.10.0)': + '@buf/cosmos_ibc.bufbuild_es@1.7.2-20240606104028-442292b00c16.2(@bufbuild/protobuf@1.10.0)': dependencies: - '@buf/cosmos_cosmos-proto.bufbuild_es': 1.9.0-20211202220400-1935555c206d.1(@bufbuild/protobuf@1.10.0) - '@buf/cosmos_cosmos-sdk.bufbuild_es': 1.9.0-20230719110346-aa25660f4ff7.1(@bufbuild/protobuf@1.10.0) - '@buf/cosmos_gogo-proto.bufbuild_es': 1.9.0-20221020125208-34d970b699f8.1(@bufbuild/protobuf@1.10.0) - '@buf/cosmos_ics23.bufbuild_es': 1.9.0-20221207100654-55085f7c710a.1(@bufbuild/protobuf@1.10.0) - '@buf/googleapis_googleapis.bufbuild_es': 1.9.0-20220908150232-8d7204855ec1.1(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_cosmos-proto.bufbuild_es': 1.7.2-20211202220400-1935555c206d.2(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_cosmos-sdk.bufbuild_es': 1.7.2-20230719110346-aa25660f4ff7.2(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_gogo-proto.bufbuild_es': 1.7.2-20221020125208-34d970b699f8.2(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_ics23.bufbuild_es': 1.7.2-20221207100654-55085f7c710a.2(@bufbuild/protobuf@1.10.0) + '@buf/googleapis_googleapis.bufbuild_es': 1.7.2-20220908150232-8d7204855ec1.2(@bufbuild/protobuf@1.10.0) '@bufbuild/protobuf': 1.10.0 - '@buf/cosmos_ibc.connectrpc_es@1.4.0-20230913112312-7ab44ae956a0.2(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))': + '@buf/cosmos_ibc.bufbuild_es@1.7.2-20240618145807-4698edb0fdb0.2(@bufbuild/protobuf@1.10.0)': + dependencies: + '@buf/cosmos_cosmos-proto.bufbuild_es': 1.7.2-20211202220400-1935555c206d.2(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_cosmos-sdk.bufbuild_es': 1.7.2-20230719110346-aa25660f4ff7.2(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_gogo-proto.bufbuild_es': 1.7.2-20221020125208-34d970b699f8.2(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_ics23.bufbuild_es': 1.7.2-20221207100654-55085f7c710a.2(@bufbuild/protobuf@1.10.0) + '@buf/googleapis_googleapis.bufbuild_es': 1.7.2-20220908150232-8d7204855ec1.2(@bufbuild/protobuf@1.10.0) + '@bufbuild/protobuf': 1.10.0 + + '@buf/cosmos_ibc.connectrpc_es@1.4.0-20230913112312-7ab44ae956a0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))': + dependencies: + '@buf/cosmos_cosmos-proto.connectrpc_es': 1.4.0-20211202220400-1935555c206d.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) + '@buf/cosmos_cosmos-sdk.connectrpc_es': 1.4.0-20230719110346-aa25660f4ff7.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) + '@buf/cosmos_gogo-proto.connectrpc_es': 1.4.0-20221020125208-34d970b699f8.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) + '@buf/cosmos_ibc.bufbuild_es': 1.7.2-20230913112312-7ab44ae956a0.2(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_ics23.connectrpc_es': 1.4.0-20221207100654-55085f7c710a.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) + '@buf/googleapis_googleapis.connectrpc_es': 1.4.0-20220908150232-8d7204855ec1.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) + '@connectrpc/connect': 1.4.0(@bufbuild/protobuf@1.10.0) + transitivePeerDependencies: + - '@bufbuild/protobuf' + + '@buf/cosmos_ibc.connectrpc_es@1.4.0-20240606104028-442292b00c16.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))': dependencies: - '@buf/cosmos_cosmos-proto.connectrpc_es': 1.4.0-20211202220400-1935555c206d.2(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) - '@buf/cosmos_cosmos-sdk.connectrpc_es': 1.4.0-20230719110346-aa25660f4ff7.2(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) - '@buf/cosmos_gogo-proto.connectrpc_es': 1.4.0-20221020125208-34d970b699f8.2(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) - '@buf/cosmos_ibc.bufbuild_es': 1.7.2-20230913112312-7ab44ae956a0.1(@bufbuild/protobuf@1.10.0) - '@buf/cosmos_ics23.connectrpc_es': 1.4.0-20221207100654-55085f7c710a.2(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) - '@buf/googleapis_googleapis.connectrpc_es': 1.4.0-20220908150232-8d7204855ec1.2(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) + '@buf/cosmos_cosmos-proto.connectrpc_es': 1.4.0-20211202220400-1935555c206d.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) + '@buf/cosmos_cosmos-sdk.connectrpc_es': 1.4.0-20230719110346-aa25660f4ff7.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) + '@buf/cosmos_gogo-proto.connectrpc_es': 1.4.0-20221020125208-34d970b699f8.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) + '@buf/cosmos_ibc.bufbuild_es': 1.7.2-20240606104028-442292b00c16.2(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_ics23.connectrpc_es': 1.4.0-20221207100654-55085f7c710a.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) + '@buf/googleapis_googleapis.connectrpc_es': 1.4.0-20220908150232-8d7204855ec1.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) '@connectrpc/connect': 1.4.0(@bufbuild/protobuf@1.10.0) transitivePeerDependencies: - '@bufbuild/protobuf' - '@buf/cosmos_ibc.connectrpc_es@1.4.0-20240530142100-ad4444393387.2(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))': + '@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))': dependencies: - '@buf/cosmos_cosmos-proto.connectrpc_es': 1.4.0-20211202220400-1935555c206d.2(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) - '@buf/cosmos_cosmos-sdk.connectrpc_es': 1.4.0-20230719110346-aa25660f4ff7.2(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) - '@buf/cosmos_gogo-proto.connectrpc_es': 1.4.0-20221020125208-34d970b699f8.2(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) - '@buf/cosmos_ibc.bufbuild_es': 1.7.2-20240530142100-ad4444393387.1(@bufbuild/protobuf@1.10.0) - '@buf/cosmos_ics23.connectrpc_es': 1.4.0-20221207100654-55085f7c710a.2(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) - '@buf/googleapis_googleapis.connectrpc_es': 1.4.0-20220908150232-8d7204855ec1.2(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) + '@buf/cosmos_cosmos-proto.connectrpc_es': 1.4.0-20211202220400-1935555c206d.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) + '@buf/cosmos_cosmos-sdk.connectrpc_es': 1.4.0-20230719110346-aa25660f4ff7.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) + '@buf/cosmos_gogo-proto.connectrpc_es': 1.4.0-20221020125208-34d970b699f8.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) + '@buf/cosmos_ibc.bufbuild_es': 1.7.2-20240618145807-4698edb0fdb0.2(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_ics23.connectrpc_es': 1.4.0-20221207100654-55085f7c710a.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) + '@buf/googleapis_googleapis.connectrpc_es': 1.4.0-20220908150232-8d7204855ec1.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) '@connectrpc/connect': 1.4.0(@bufbuild/protobuf@1.10.0) transitivePeerDependencies: - '@bufbuild/protobuf' - '@buf/cosmos_ics23.bufbuild_es@1.7.2-20221207100654-55085f7c710a.1(@bufbuild/protobuf@1.10.0)': + '@buf/cosmos_ics23.bufbuild_es@1.10.0-20221207100654-55085f7c710a.1(@bufbuild/protobuf@1.10.0)': dependencies: '@bufbuild/protobuf': 1.10.0 - '@buf/cosmos_ics23.bufbuild_es@1.9.0-20221207100654-55085f7c710a.1(@bufbuild/protobuf@1.10.0)': + '@buf/cosmos_ics23.bufbuild_es@1.7.2-20221207100654-55085f7c710a.2(@bufbuild/protobuf@1.10.0)': dependencies: '@bufbuild/protobuf': 1.10.0 - '@buf/cosmos_ics23.connectrpc_es@1.4.0-20221207100654-55085f7c710a.2(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))': + '@buf/cosmos_ics23.connectrpc_es@1.4.0-20221207100654-55085f7c710a.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))': dependencies: - '@buf/cosmos_ics23.bufbuild_es': 1.7.2-20221207100654-55085f7c710a.1(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_ics23.bufbuild_es': 1.7.2-20221207100654-55085f7c710a.2(@bufbuild/protobuf@1.10.0) '@connectrpc/connect': 1.4.0(@bufbuild/protobuf@1.10.0) transitivePeerDependencies: - '@bufbuild/protobuf' - '@buf/googleapis_googleapis.bufbuild_es@1.7.2-20220908150232-8d7204855ec1.1(@bufbuild/protobuf@1.10.0)': + '@buf/googleapis_googleapis.bufbuild_es@1.10.0-20220908150232-8d7204855ec1.1(@bufbuild/protobuf@1.10.0)': dependencies: '@bufbuild/protobuf': 1.10.0 - '@buf/googleapis_googleapis.bufbuild_es@1.7.2-20221214150216-75b4300737fb.1(@bufbuild/protobuf@1.10.0)': + '@buf/googleapis_googleapis.bufbuild_es@1.10.0-20221214150216-75b4300737fb.1(@bufbuild/protobuf@1.10.0)': dependencies: '@bufbuild/protobuf': 1.10.0 - '@buf/googleapis_googleapis.bufbuild_es@1.7.2-20230502210827-cc916c318597.1(@bufbuild/protobuf@1.10.0)': + '@buf/googleapis_googleapis.bufbuild_es@1.10.0-20230502210827-cc916c318597.1(@bufbuild/protobuf@1.10.0)': dependencies: '@bufbuild/protobuf': 1.10.0 - '@buf/googleapis_googleapis.bufbuild_es@1.9.0-20220908150232-8d7204855ec1.1(@bufbuild/protobuf@1.10.0)': + '@buf/googleapis_googleapis.bufbuild_es@1.7.2-20220908150232-8d7204855ec1.2(@bufbuild/protobuf@1.10.0)': dependencies: '@bufbuild/protobuf': 1.10.0 - '@buf/googleapis_googleapis.bufbuild_es@1.9.0-20221214150216-75b4300737fb.1(@bufbuild/protobuf@1.10.0)': + '@buf/googleapis_googleapis.bufbuild_es@1.7.2-20221214150216-75b4300737fb.2(@bufbuild/protobuf@1.10.0)': dependencies: '@bufbuild/protobuf': 1.10.0 - '@buf/googleapis_googleapis.bufbuild_es@1.9.0-20230502210827-cc916c318597.1(@bufbuild/protobuf@1.10.0)': + '@buf/googleapis_googleapis.bufbuild_es@1.7.2-20230502210827-cc916c318597.2(@bufbuild/protobuf@1.10.0)': dependencies: '@bufbuild/protobuf': 1.10.0 - '@buf/googleapis_googleapis.connectrpc_es@1.4.0-20220908150232-8d7204855ec1.2(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))': + '@buf/googleapis_googleapis.connectrpc_es@1.4.0-20220908150232-8d7204855ec1.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))': dependencies: - '@buf/googleapis_googleapis.bufbuild_es': 1.7.2-20220908150232-8d7204855ec1.1(@bufbuild/protobuf@1.10.0) + '@buf/googleapis_googleapis.bufbuild_es': 1.7.2-20220908150232-8d7204855ec1.2(@bufbuild/protobuf@1.10.0) '@connectrpc/connect': 1.4.0(@bufbuild/protobuf@1.10.0) transitivePeerDependencies: - '@bufbuild/protobuf' - '@buf/googleapis_googleapis.connectrpc_es@1.4.0-20221214150216-75b4300737fb.2(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))': + '@buf/googleapis_googleapis.connectrpc_es@1.4.0-20221214150216-75b4300737fb.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))': dependencies: - '@buf/googleapis_googleapis.bufbuild_es': 1.7.2-20221214150216-75b4300737fb.1(@bufbuild/protobuf@1.10.0) + '@buf/googleapis_googleapis.bufbuild_es': 1.7.2-20221214150216-75b4300737fb.2(@bufbuild/protobuf@1.10.0) '@connectrpc/connect': 1.4.0(@bufbuild/protobuf@1.10.0) transitivePeerDependencies: - '@bufbuild/protobuf' - '@buf/googleapis_googleapis.connectrpc_es@1.4.0-20230502210827-cc916c318597.2(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))': + '@buf/googleapis_googleapis.connectrpc_es@1.4.0-20230502210827-cc916c318597.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))': dependencies: - '@buf/googleapis_googleapis.bufbuild_es': 1.7.2-20230502210827-cc916c318597.1(@bufbuild/protobuf@1.10.0) + '@buf/googleapis_googleapis.bufbuild_es': 1.7.2-20230502210827-cc916c318597.2(@bufbuild/protobuf@1.10.0) '@connectrpc/connect': 1.4.0(@bufbuild/protobuf@1.10.0) transitivePeerDependencies: - '@bufbuild/protobuf' - '@buf/penumbra-zone_penumbra.bufbuild_es@1.7.2-20240528180215-8fe1c79485f8.1(@bufbuild/protobuf@1.10.0)': + '@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0)': dependencies: - '@buf/cosmos_cosmos-proto.bufbuild_es': 1.7.2-20211202220400-1935555c206d.1(@bufbuild/protobuf@1.10.0) - '@buf/cosmos_cosmos-sdk.bufbuild_es': 1.7.2-20230522115704-e7a85cef453e.1(@bufbuild/protobuf@1.10.0) - '@buf/cosmos_gogo-proto.bufbuild_es': 1.7.2-20221020125208-34d970b699f8.1(@bufbuild/protobuf@1.10.0) - '@buf/cosmos_ibc.bufbuild_es': 1.7.2-20230913112312-7ab44ae956a0.1(@bufbuild/protobuf@1.10.0) - '@buf/cosmos_ics23.bufbuild_es': 1.7.2-20221207100654-55085f7c710a.1(@bufbuild/protobuf@1.10.0) - '@buf/googleapis_googleapis.bufbuild_es': 1.7.2-20221214150216-75b4300737fb.1(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_cosmos-proto.bufbuild_es': 1.10.0-20211202220400-1935555c206d.1(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_cosmos-sdk.bufbuild_es': 1.10.0-20230522115704-e7a85cef453e.1(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_gogo-proto.bufbuild_es': 1.10.0-20221020125208-34d970b699f8.1(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_ibc.bufbuild_es': 1.10.0-20230913112312-7ab44ae956a0.1(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_ics23.bufbuild_es': 1.10.0-20221207100654-55085f7c710a.1(@bufbuild/protobuf@1.10.0) + '@buf/googleapis_googleapis.bufbuild_es': 1.10.0-20221214150216-75b4300737fb.1(@bufbuild/protobuf@1.10.0) '@bufbuild/protobuf': 1.10.0 - '@buf/penumbra-zone_penumbra.bufbuild_es@1.9.0-20240528180215-8fe1c79485f8.1(@bufbuild/protobuf@1.10.0)': + '@buf/penumbra-zone_penumbra.bufbuild_es@1.7.2-20240616005217-ca45ca80333e.2(@bufbuild/protobuf@1.10.0)': dependencies: - '@buf/cosmos_cosmos-proto.bufbuild_es': 1.9.0-20211202220400-1935555c206d.1(@bufbuild/protobuf@1.10.0) - '@buf/cosmos_cosmos-sdk.bufbuild_es': 1.9.0-20230522115704-e7a85cef453e.1(@bufbuild/protobuf@1.10.0) - '@buf/cosmos_gogo-proto.bufbuild_es': 1.9.0-20221020125208-34d970b699f8.1(@bufbuild/protobuf@1.10.0) - '@buf/cosmos_ibc.bufbuild_es': 1.9.0-20230913112312-7ab44ae956a0.1(@bufbuild/protobuf@1.10.0) - '@buf/cosmos_ics23.bufbuild_es': 1.9.0-20221207100654-55085f7c710a.1(@bufbuild/protobuf@1.10.0) - '@buf/googleapis_googleapis.bufbuild_es': 1.9.0-20221214150216-75b4300737fb.1(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_cosmos-proto.bufbuild_es': 1.7.2-20211202220400-1935555c206d.2(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_cosmos-sdk.bufbuild_es': 1.7.2-20230522115704-e7a85cef453e.2(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_gogo-proto.bufbuild_es': 1.7.2-20221020125208-34d970b699f8.2(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_ibc.bufbuild_es': 1.7.2-20230913112312-7ab44ae956a0.2(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_ics23.bufbuild_es': 1.7.2-20221207100654-55085f7c710a.2(@bufbuild/protobuf@1.10.0) + '@buf/googleapis_googleapis.bufbuild_es': 1.7.2-20221214150216-75b4300737fb.2(@bufbuild/protobuf@1.10.0) '@bufbuild/protobuf': 1.10.0 - '@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240528180215-8fe1c79485f8.2(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))': + '@buf/penumbra-zone_penumbra.bufbuild_es@1.7.2-20240618173046-185f930afaf0.2(@bufbuild/protobuf@1.10.0)': dependencies: - '@buf/cosmos_cosmos-proto.connectrpc_es': 1.4.0-20211202220400-1935555c206d.2(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) - '@buf/cosmos_cosmos-sdk.connectrpc_es': 1.4.0-20230522115704-e7a85cef453e.2(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) - '@buf/cosmos_gogo-proto.connectrpc_es': 1.4.0-20221020125208-34d970b699f8.2(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) - '@buf/cosmos_ibc.connectrpc_es': 1.4.0-20230913112312-7ab44ae956a0.2(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) - '@buf/cosmos_ics23.connectrpc_es': 1.4.0-20221207100654-55085f7c710a.2(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) - '@buf/googleapis_googleapis.connectrpc_es': 1.4.0-20221214150216-75b4300737fb.2(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) - '@buf/penumbra-zone_penumbra.bufbuild_es': 1.7.2-20240528180215-8fe1c79485f8.1(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_cosmos-proto.bufbuild_es': 1.7.2-20211202220400-1935555c206d.2(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_cosmos-sdk.bufbuild_es': 1.7.2-20230522115704-e7a85cef453e.2(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_gogo-proto.bufbuild_es': 1.7.2-20221020125208-34d970b699f8.2(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_ibc.bufbuild_es': 1.7.2-20230913112312-7ab44ae956a0.2(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_ics23.bufbuild_es': 1.7.2-20221207100654-55085f7c710a.2(@bufbuild/protobuf@1.10.0) + '@buf/googleapis_googleapis.bufbuild_es': 1.7.2-20221214150216-75b4300737fb.2(@bufbuild/protobuf@1.10.0) + '@bufbuild/protobuf': 1.10.0 + + '@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240616005217-ca45ca80333e.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))': + dependencies: + '@buf/cosmos_cosmos-proto.connectrpc_es': 1.4.0-20211202220400-1935555c206d.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) + '@buf/cosmos_cosmos-sdk.connectrpc_es': 1.4.0-20230522115704-e7a85cef453e.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) + '@buf/cosmos_gogo-proto.connectrpc_es': 1.4.0-20221020125208-34d970b699f8.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) + '@buf/cosmos_ibc.connectrpc_es': 1.4.0-20230913112312-7ab44ae956a0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) + '@buf/cosmos_ics23.connectrpc_es': 1.4.0-20221207100654-55085f7c710a.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) + '@buf/googleapis_googleapis.connectrpc_es': 1.4.0-20221214150216-75b4300737fb.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) + '@buf/penumbra-zone_penumbra.bufbuild_es': 1.7.2-20240616005217-ca45ca80333e.2(@bufbuild/protobuf@1.10.0) + '@connectrpc/connect': 1.4.0(@bufbuild/protobuf@1.10.0) + transitivePeerDependencies: + - '@bufbuild/protobuf' + + '@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))': + dependencies: + '@buf/cosmos_cosmos-proto.connectrpc_es': 1.4.0-20211202220400-1935555c206d.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) + '@buf/cosmos_cosmos-sdk.connectrpc_es': 1.4.0-20230522115704-e7a85cef453e.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) + '@buf/cosmos_gogo-proto.connectrpc_es': 1.4.0-20221020125208-34d970b699f8.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) + '@buf/cosmos_ibc.connectrpc_es': 1.4.0-20230913112312-7ab44ae956a0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) + '@buf/cosmos_ics23.connectrpc_es': 1.4.0-20221207100654-55085f7c710a.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) + '@buf/googleapis_googleapis.connectrpc_es': 1.4.0-20221214150216-75b4300737fb.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) + '@buf/penumbra-zone_penumbra.bufbuild_es': 1.7.2-20240618173046-185f930afaf0.2(@bufbuild/protobuf@1.10.0) '@connectrpc/connect': 1.4.0(@bufbuild/protobuf@1.10.0) transitivePeerDependencies: - '@bufbuild/protobuf' - '@buf/tendermint_tendermint.bufbuild_es@1.9.0-20231117195010-33ed361a9051.1(@bufbuild/protobuf@1.10.0)': + '@buf/tendermint_tendermint.bufbuild_es@1.10.0-20231117195010-33ed361a9051.1(@bufbuild/protobuf@1.10.0)': dependencies: - '@buf/cosmos_gogo-proto.bufbuild_es': 1.9.0-20230509103710-5e5b9fdd0180.1(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_gogo-proto.bufbuild_es': 1.10.0-20230509103710-5e5b9fdd0180.1(@bufbuild/protobuf@1.10.0) '@bufbuild/protobuf': 1.10.0 '@bufbuild/protobuf@1.10.0': {} @@ -11005,84 +10796,153 @@ snapshots: '@esbuild/aix-ppc64@0.20.2': optional: true + '@esbuild/aix-ppc64@0.21.5': + optional: true + '@esbuild/android-arm64@0.20.2': optional: true + '@esbuild/android-arm64@0.21.5': + optional: true + '@esbuild/android-arm@0.20.2': optional: true + '@esbuild/android-arm@0.21.5': + optional: true + '@esbuild/android-x64@0.20.2': optional: true + '@esbuild/android-x64@0.21.5': + optional: true + '@esbuild/darwin-arm64@0.20.2': optional: true + '@esbuild/darwin-arm64@0.21.5': + optional: true + '@esbuild/darwin-x64@0.20.2': optional: true + '@esbuild/darwin-x64@0.21.5': + optional: true + '@esbuild/freebsd-arm64@0.20.2': optional: true + '@esbuild/freebsd-arm64@0.21.5': + optional: true + '@esbuild/freebsd-x64@0.20.2': optional: true + '@esbuild/freebsd-x64@0.21.5': + optional: true + '@esbuild/linux-arm64@0.20.2': optional: true + '@esbuild/linux-arm64@0.21.5': + optional: true + '@esbuild/linux-arm@0.20.2': optional: true + '@esbuild/linux-arm@0.21.5': + optional: true + '@esbuild/linux-ia32@0.20.2': optional: true + '@esbuild/linux-ia32@0.21.5': + optional: true + '@esbuild/linux-loong64@0.20.2': optional: true + '@esbuild/linux-loong64@0.21.5': + optional: true + '@esbuild/linux-mips64el@0.20.2': optional: true + '@esbuild/linux-mips64el@0.21.5': + optional: true + '@esbuild/linux-ppc64@0.20.2': optional: true + '@esbuild/linux-ppc64@0.21.5': + optional: true + '@esbuild/linux-riscv64@0.20.2': optional: true + '@esbuild/linux-riscv64@0.21.5': + optional: true + '@esbuild/linux-s390x@0.20.2': optional: true + '@esbuild/linux-s390x@0.21.5': + optional: true + '@esbuild/linux-x64@0.20.2': optional: true + '@esbuild/linux-x64@0.21.5': + optional: true + '@esbuild/netbsd-x64@0.20.2': optional: true + '@esbuild/netbsd-x64@0.21.5': + optional: true + '@esbuild/openbsd-x64@0.20.2': optional: true + '@esbuild/openbsd-x64@0.21.5': + optional: true + '@esbuild/sunos-x64@0.20.2': optional: true + '@esbuild/sunos-x64@0.21.5': + optional: true + '@esbuild/win32-arm64@0.20.2': optional: true + '@esbuild/win32-arm64@0.21.5': + optional: true + '@esbuild/win32-ia32@0.20.2': optional: true + '@esbuild/win32-ia32@0.21.5': + optional: true + '@esbuild/win32-x64@0.20.2': optional: true - '@eslint-community/eslint-utils@4.4.0(eslint@9.4.0)': + '@esbuild/win32-x64@0.21.5': + optional: true + + '@eslint-community/eslint-utils@4.4.0(eslint@9.5.0)': dependencies: - eslint: 9.4.0 + eslint: 9.5.0 eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.10.1': {} - '@eslint/compat@1.0.3': {} + '@eslint/compat@1.1.0': {} - '@eslint/config-array@0.15.1': + '@eslint/config-array@0.16.0': dependencies: - '@eslint/object-schema': 2.1.3 + '@eslint/object-schema': 2.1.4 debug: 4.3.5 minimatch: 3.1.2 transitivePeerDependencies: @@ -11092,7 +10952,7 @@ snapshots: dependencies: ajv: 6.12.6 debug: 4.3.5 - espree: 10.0.1 + espree: 10.1.0 globals: 14.0.0 ignore: 5.3.1 import-fresh: 3.3.0 @@ -11102,9 +10962,9 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/js@9.4.0': {} + '@eslint/js@9.5.0': {} - '@eslint/object-schema@2.1.3': {} + '@eslint/object-schema@2.1.4': {} '@fal-works/esbuild-plugin-global-externals@2.1.2': {} @@ -11202,13 +11062,13 @@ snapshots: dependencies: '@sinclair/typebox': 0.27.8 - '@joshwooding/vite-plugin-react-docgen-typescript@0.3.1(typescript@5.4.5)(vite@5.2.13(@types/node@20.14.2)(terser@5.31.1))': + '@joshwooding/vite-plugin-react-docgen-typescript@0.3.1(typescript@5.4.5)(vite@5.3.1(@types/node@20.14.5)(terser@5.31.1))': dependencies: glob: 7.2.3 glob-promise: 4.2.2(glob@7.2.3) magic-string: 0.27.0 react-docgen-typescript: 2.2.2(typescript@5.4.5) - vite: 5.2.13(@types/node@20.14.2)(terser@5.31.1) + vite: 5.3.1(@types/node@20.14.5)(terser@5.31.1) optionalDependencies: typescript: 5.4.5 @@ -11265,47 +11125,12 @@ snapshots: '@types/react': 18.3.3 react: 18.3.1 - '@microsoft/api-extractor-model@7.28.13(@types/node@20.14.2)': - dependencies: - '@microsoft/tsdoc': 0.14.2 - '@microsoft/tsdoc-config': 0.16.2 - '@rushstack/node-core-library': 4.0.2(@types/node@20.14.2) - transitivePeerDependencies: - - '@types/node' - - '@microsoft/api-extractor@7.43.0(@types/node@20.14.2)': - dependencies: - '@microsoft/api-extractor-model': 7.28.13(@types/node@20.14.2) - '@microsoft/tsdoc': 0.14.2 - '@microsoft/tsdoc-config': 0.16.2 - '@rushstack/node-core-library': 4.0.2(@types/node@20.14.2) - '@rushstack/rig-package': 0.5.2 - '@rushstack/terminal': 0.10.0(@types/node@20.14.2) - '@rushstack/ts-command-line': 4.19.1(@types/node@20.14.2) - lodash: 4.17.21 - minimatch: 3.0.8 - resolve: 1.22.8 - semver: 7.5.4 - source-map: 0.6.1 - typescript: 5.4.2 - transitivePeerDependencies: - - '@types/node' - - '@microsoft/tsdoc-config@0.16.2': - dependencies: - '@microsoft/tsdoc': 0.14.2 - ajv: 6.12.6 - jju: 1.4.0 - resolve: 1.19.0 - - '@microsoft/tsdoc@0.14.2': {} - '@mui/base@5.0.0-beta.40(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@babel/runtime': 7.24.7 '@floating-ui/react-dom': 2.1.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@mui/types': 7.2.14(@types/react@18.3.3) - '@mui/utils': 5.15.14(@types/react@18.3.3)(react@18.3.1) + '@mui/utils': 5.15.20(@types/react@18.3.3)(react@18.3.1) '@popperjs/core': 2.11.8 clsx: 2.1.1 prop-types: 15.8.1 @@ -11314,16 +11139,16 @@ snapshots: optionalDependencies: '@types/react': 18.3.3 - '@mui/core-downloads-tracker@5.15.19': {} + '@mui/core-downloads-tracker@5.15.20': {} - '@mui/material@5.15.19(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@mui/material@5.15.20(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@babel/runtime': 7.24.7 '@mui/base': 5.0.0-beta.40(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@mui/core-downloads-tracker': 5.15.19 - '@mui/system': 5.15.15(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1) + '@mui/core-downloads-tracker': 5.15.20 + '@mui/system': 5.15.20(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1) '@mui/types': 7.2.14(@types/react@18.3.3) - '@mui/utils': 5.15.14(@types/react@18.3.3)(react@18.3.1) + '@mui/utils': 5.15.20(@types/react@18.3.3)(react@18.3.1) '@types/react-transition-group': 4.4.10 clsx: 2.1.1 csstype: 3.1.3 @@ -11337,10 +11162,10 @@ snapshots: '@emotion/styled': 11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1) '@types/react': 18.3.3 - '@mui/private-theming@5.15.14(@types/react@18.3.3)(react@18.3.1)': + '@mui/private-theming@5.15.20(@types/react@18.3.3)(react@18.3.1)': dependencies: '@babel/runtime': 7.24.7 - '@mui/utils': 5.15.14(@types/react@18.3.3)(react@18.3.1) + '@mui/utils': 5.15.20(@types/react@18.3.3)(react@18.3.1) prop-types: 15.8.1 react: 18.3.1 optionalDependencies: @@ -11357,13 +11182,13 @@ snapshots: '@emotion/react': 11.11.4(@types/react@18.3.3)(react@18.3.1) '@emotion/styled': 11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1) - '@mui/system@5.15.15(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1)': + '@mui/system@5.15.20(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1)': dependencies: '@babel/runtime': 7.24.7 - '@mui/private-theming': 5.15.14(@types/react@18.3.3)(react@18.3.1) + '@mui/private-theming': 5.15.20(@types/react@18.3.3)(react@18.3.1) '@mui/styled-engine': 5.15.14(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(react@18.3.1) '@mui/types': 7.2.14(@types/react@18.3.3) - '@mui/utils': 5.15.14(@types/react@18.3.3)(react@18.3.1) + '@mui/utils': 5.15.20(@types/react@18.3.3)(react@18.3.1) clsx: 2.1.1 csstype: 3.1.3 prop-types: 15.8.1 @@ -11377,7 +11202,7 @@ snapshots: optionalDependencies: '@types/react': 18.3.3 - '@mui/utils@5.15.14(@types/react@18.3.3)(react@18.3.1)': + '@mui/utils@5.15.20(@types/react@18.3.3)(react@18.3.1)': dependencies: '@babel/runtime': 7.24.7 '@types/prop-types': 15.7.12 @@ -11429,6 +11254,162 @@ snapshots: '@penumbra-labs/registry@8.0.1': {} + '@penumbra-zone/bech32m@6.1.0': + dependencies: + bech32: 2.0.0 + + '@penumbra-zone/client@8.0.0(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))(@penumbra-zone/transport-dom@7.1.0)': + dependencies: + '@penumbra-zone/protobuf': 5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))) + '@penumbra-zone/transport-dom': 7.1.0 + + ? '@penumbra-zone/crypto-web@5.0.0(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))))' + : dependencies: + '@penumbra-zone/types': 9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))) + bip39: 3.1.0 + crypto-js: 4.2.0 + + '@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))': + dependencies: + '@buf/penumbra-zone_penumbra.bufbuild_es': 1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0) + '@bufbuild/protobuf': 1.10.0 + '@penumbra-zone/bech32m': 6.1.0 + '@penumbra-zone/protobuf': 5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))) + + '@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240618145807-4698edb0fdb0.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))': + dependencies: + '@buf/penumbra-zone_penumbra.bufbuild_es': 1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0) + '@bufbuild/protobuf': 1.10.0 + '@penumbra-zone/bech32m': 6.1.0 + '@penumbra-zone/protobuf': 5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240618145807-4698edb0fdb0.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))) + + '@penumbra-zone/keys@4.1.0': {} + + ? '@penumbra-zone/perspective@6.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))))(@penumbra-zone/wasm@9.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))))))' + : dependencies: + '@buf/penumbra-zone_penumbra.bufbuild_es': 1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0) + '@penumbra-zone/bech32m': 6.1.0 + '@penumbra-zone/getters': 8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))) + '@penumbra-zone/wasm': 9.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))))) + + ? '@penumbra-zone/perspective@6.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240618145807-4698edb0fdb0.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))))(@penumbra-zone/wasm@9.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240618145807-4698edb0fdb0.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240618145807-4698edb0fdb0.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240618145807-4698edb0fdb0.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))))))' + : dependencies: + '@buf/penumbra-zone_penumbra.bufbuild_es': 1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0) + '@penumbra-zone/bech32m': 6.1.0 + '@penumbra-zone/getters': 8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240618145807-4698edb0fdb0.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))) + '@penumbra-zone/wasm': 9.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240618145807-4698edb0fdb0.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240618145807-4698edb0fdb0.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240618145807-4698edb0fdb0.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))))) + + '@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))': + dependencies: + '@buf/cosmos_ibc.bufbuild_es': 1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_ibc.connectrpc_es': 1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) + '@buf/penumbra-zone_penumbra.bufbuild_es': 1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0) + '@buf/penumbra-zone_penumbra.connectrpc_es': 1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) + '@bufbuild/protobuf': 1.10.0 + + '@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240618145807-4698edb0fdb0.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))': + dependencies: + '@buf/cosmos_ibc.bufbuild_es': 1.10.0-20240618145807-4698edb0fdb0.1(@bufbuild/protobuf@1.10.0) + '@buf/cosmos_ibc.connectrpc_es': 1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) + '@buf/penumbra-zone_penumbra.bufbuild_es': 1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0) + '@buf/penumbra-zone_penumbra.connectrpc_es': 1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) + '@bufbuild/protobuf': 1.10.0 + + ? '@penumbra-zone/query@6.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/crypto-web@5.0.0(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))))))(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))))(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))))(@penumbra-zone/wasm@9.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))))))' + : dependencies: + '@buf/cosmos_ibc.bufbuild_es': 1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0) + '@buf/penumbra-zone_penumbra.bufbuild_es': 1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0) + '@bufbuild/protobuf': 1.10.0 + '@connectrpc/connect': 1.4.0(@bufbuild/protobuf@1.10.0) + '@connectrpc/connect-web': 1.4.0(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)) + '@penumbra-zone/bech32m': 6.1.0 + '@penumbra-zone/crypto-web': 5.0.0(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))))) + '@penumbra-zone/getters': 8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))) + '@penumbra-zone/protobuf': 5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))) + '@penumbra-zone/types': 9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))) + '@penumbra-zone/wasm': 9.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))))) + exponential-backoff: 3.1.1 + + ? '@penumbra-zone/services@6.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/crypto-web@5.0.0(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))))))(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))))(@penumbra-zone/perspective@6.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))))(@penumbra-zone/wasm@9.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))))))(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))(@penumbra-zone/query@6.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/crypto-web@5.0.0(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))))))(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))))(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))))(@penumbra-zone/wasm@9.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))))))(@penumbra-zone/storage@6.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))))(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))))(@penumbra-zone/wasm@9.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))))))(@penumbra-zone/transport-dom@7.1.0)(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))))(@penumbra-zone/wasm@9.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))))))' + : dependencies: + '@buf/penumbra-zone_penumbra.bufbuild_es': 1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0) + '@bufbuild/protobuf': 1.10.0 + '@connectrpc/connect': 1.4.0(@bufbuild/protobuf@1.10.0) + '@penumbra-zone/bech32m': 6.1.0 + '@penumbra-zone/crypto-web': 5.0.0(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))))) + '@penumbra-zone/getters': 8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))) + '@penumbra-zone/perspective': 6.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))))(@penumbra-zone/wasm@9.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))))) + '@penumbra-zone/protobuf': 5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))) + '@penumbra-zone/query': 6.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/crypto-web@5.0.0(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))))))(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))))(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))))(@penumbra-zone/wasm@9.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))))) + '@penumbra-zone/storage': 6.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))))(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))))(@penumbra-zone/wasm@9.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))))) + '@penumbra-zone/transport-dom': 7.1.0 + '@penumbra-zone/types': 9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))) + '@penumbra-zone/wasm': 9.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))))) + + ? '@penumbra-zone/storage@6.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))))(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))))(@penumbra-zone/wasm@9.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))))))' + : dependencies: + '@buf/penumbra-zone_penumbra.bufbuild_es': 1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0) + '@bufbuild/protobuf': 1.10.0 + '@penumbra-labs/registry': 8.0.1 + '@penumbra-zone/bech32m': 6.1.0 + '@penumbra-zone/getters': 8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))) + '@penumbra-zone/types': 9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))) + '@penumbra-zone/wasm': 9.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))))) + idb: 8.0.0 + + '@penumbra-zone/transport-chrome@4.0.0(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))(@penumbra-zone/transport-dom@7.1.0)': + dependencies: + '@bufbuild/protobuf': 1.10.0 + '@connectrpc/connect': 1.4.0(@bufbuild/protobuf@1.10.0) + '@penumbra-zone/transport-dom': 7.1.0 + + '@penumbra-zone/transport-dom@7.1.0': + dependencies: + '@bufbuild/protobuf': 1.10.0 + '@connectrpc/connect': 1.4.0(@bufbuild/protobuf@1.10.0) + + '@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))))': + dependencies: + '@buf/cosmos_ibc.bufbuild_es': 1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0) + '@buf/penumbra-zone_penumbra.bufbuild_es': 1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0) + '@bufbuild/protobuf': 1.10.0 + '@penumbra-zone/bech32m': 6.1.0 + '@penumbra-zone/getters': 8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))) + bignumber.js: 9.1.2 + idb: 8.0.0 + zod: 3.23.8 + + '@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240618145807-4698edb0fdb0.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240618145807-4698edb0fdb0.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))))': + dependencies: + '@buf/cosmos_ibc.bufbuild_es': 1.10.0-20240618145807-4698edb0fdb0.1(@bufbuild/protobuf@1.10.0) + '@buf/penumbra-zone_penumbra.bufbuild_es': 1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0) + '@bufbuild/protobuf': 1.10.0 + '@penumbra-zone/bech32m': 6.1.0 + '@penumbra-zone/getters': 8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240618145807-4698edb0fdb0.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))) + bignumber.js: 9.1.2 + idb: 8.0.0 + zod: 3.23.8 + + ? '@penumbra-zone/wasm@9.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))))' + : dependencies: + '@buf/penumbra-zone_penumbra.bufbuild_es': 1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0) + '@bufbuild/protobuf': 1.10.0 + '@penumbra-zone/bech32m': 6.1.0 + '@penumbra-zone/protobuf': 5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))) + '@penumbra-zone/types': 9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240606104028-442292b00c16.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))) + optionalDependencies: + '@penumbra-zone/keys': 4.1.0 + + ? '@penumbra-zone/wasm@9.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240618145807-4698edb0fdb0.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))(@penumbra-zone/types@9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240618145807-4698edb0fdb0.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240618145807-4698edb0fdb0.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))))' + : dependencies: + '@buf/penumbra-zone_penumbra.bufbuild_es': 1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0) + '@bufbuild/protobuf': 1.10.0 + '@penumbra-zone/bech32m': 6.1.0 + '@penumbra-zone/protobuf': 5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240618145807-4698edb0fdb0.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))) + '@penumbra-zone/types': 9.0.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240618145807-4698edb0fdb0.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/getters@8.0.0(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@bufbuild/protobuf@1.10.0)(@penumbra-zone/bech32m@6.1.0)(@penumbra-zone/protobuf@5.1.0(@buf/cosmos_ibc.bufbuild_es@1.10.0-20240618145807-4698edb0fdb0.1(@bufbuild/protobuf@1.10.0))(@buf/cosmos_ibc.connectrpc_es@1.4.0-20240618145807-4698edb0fdb0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0)))(@buf/penumbra-zone_penumbra.bufbuild_es@1.10.0-20240616005217-ca45ca80333e.1(@bufbuild/protobuf@1.10.0))(@buf/penumbra-zone_penumbra.connectrpc_es@1.4.0-20240618173046-185f930afaf0.3(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0(@bufbuild/protobuf@1.10.0))))) + optionalDependencies: + '@penumbra-zone/keys': 4.1.0 + '@pkgjs/parseargs@0.11.0': optional: true @@ -12140,60 +12121,28 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.18.0': optional: true - '@rushstack/node-core-library@4.0.2(@types/node@20.14.2)': - dependencies: - fs-extra: 7.0.1 - import-lazy: 4.0.0 - jju: 1.4.0 - resolve: 1.22.8 - semver: 7.5.4 - z-schema: 5.0.5 - optionalDependencies: - '@types/node': 20.14.2 - - '@rushstack/rig-package@0.5.2': - dependencies: - resolve: 1.22.8 - strip-json-comments: 3.1.1 - - '@rushstack/terminal@0.10.0(@types/node@20.14.2)': - dependencies: - '@rushstack/node-core-library': 4.0.2(@types/node@20.14.2) - supports-color: 8.1.1 - optionalDependencies: - '@types/node': 20.14.2 - - '@rushstack/ts-command-line@4.19.1(@types/node@20.14.2)': - dependencies: - '@rushstack/terminal': 0.10.0(@types/node@20.14.2) - '@types/argparse': 1.0.38 - argparse: 1.0.10 - string-argv: 0.3.2 - transitivePeerDependencies: - - '@types/node' - '@sinclair/typebox@0.27.8': {} '@sindresorhus/merge-streams@2.3.0': {} - '@storybook/addon-actions@8.1.6': + '@storybook/addon-actions@8.1.10': dependencies: - '@storybook/core-events': 8.1.6 + '@storybook/core-events': 8.1.10 '@storybook/global': 5.0.0 '@types/uuid': 9.0.8 dequal: 2.0.3 polished: 4.3.1 uuid: 9.0.1 - '@storybook/addon-backgrounds@8.1.6': + '@storybook/addon-backgrounds@8.1.10': dependencies: '@storybook/global': 5.0.0 memoizerific: 1.11.3 ts-dedent: 2.2.0 - '@storybook/addon-controls@8.1.6(@types/react-dom@18.3.0)(@types/react@18.3.3)(encoding@0.1.13)(prettier@3.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@storybook/addon-controls@8.1.10(@types/react-dom@18.3.0)(@types/react@18.3.3)(encoding@0.1.13)(prettier@3.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@storybook/blocks': 8.1.6(@types/react-dom@18.3.0)(@types/react@18.3.3)(encoding@0.1.13)(prettier@3.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@storybook/blocks': 8.1.10(@types/react-dom@18.3.0)(@types/react@18.3.3)(encoding@0.1.13)(prettier@3.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) dequal: 2.0.3 lodash: 4.17.21 ts-dedent: 2.2.0 @@ -12206,21 +12155,21 @@ snapshots: - react-dom - supports-color - '@storybook/addon-docs@8.1.6(@types/react-dom@18.3.0)(encoding@0.1.13)(prettier@3.3.2)': + '@storybook/addon-docs@8.1.10(@types/react-dom@18.3.0)(encoding@0.1.13)(prettier@3.3.2)': dependencies: '@babel/core': 7.24.7 '@mdx-js/react': 3.0.1(@types/react@18.3.3)(react@18.3.1) - '@storybook/blocks': 8.1.6(@types/react-dom@18.3.0)(@types/react@18.3.3)(encoding@0.1.13)(prettier@3.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@storybook/client-logger': 8.1.6 - '@storybook/components': 8.1.6(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@storybook/csf-plugin': 8.1.6 - '@storybook/csf-tools': 8.1.6 + '@storybook/blocks': 8.1.10(@types/react-dom@18.3.0)(@types/react@18.3.3)(encoding@0.1.13)(prettier@3.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@storybook/client-logger': 8.1.10 + '@storybook/components': 8.1.10(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@storybook/csf-plugin': 8.1.10 + '@storybook/csf-tools': 8.1.10 '@storybook/global': 5.0.0 - '@storybook/node-logger': 8.1.6 - '@storybook/preview-api': 8.1.6 - '@storybook/react-dom-shim': 8.1.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@storybook/theming': 8.1.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@storybook/types': 8.1.6 + '@storybook/node-logger': 8.1.10 + '@storybook/preview-api': 8.1.10 + '@storybook/react-dom-shim': 8.1.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@storybook/theming': 8.1.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@storybook/types': 8.1.10 '@types/react': 18.3.3 fs-extra: 11.2.0 react: 18.3.1 @@ -12234,21 +12183,21 @@ snapshots: - prettier - supports-color - '@storybook/addon-essentials@8.1.6(@types/react-dom@18.3.0)(@types/react@18.3.3)(encoding@0.1.13)(prettier@3.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@storybook/addon-actions': 8.1.6 - '@storybook/addon-backgrounds': 8.1.6 - '@storybook/addon-controls': 8.1.6(@types/react-dom@18.3.0)(@types/react@18.3.3)(encoding@0.1.13)(prettier@3.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@storybook/addon-docs': 8.1.6(@types/react-dom@18.3.0)(encoding@0.1.13)(prettier@3.3.2) - '@storybook/addon-highlight': 8.1.6 - '@storybook/addon-measure': 8.1.6 - '@storybook/addon-outline': 8.1.6 - '@storybook/addon-toolbars': 8.1.6 - '@storybook/addon-viewport': 8.1.6 - '@storybook/core-common': 8.1.6(encoding@0.1.13)(prettier@3.3.2) - '@storybook/manager-api': 8.1.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@storybook/node-logger': 8.1.6 - '@storybook/preview-api': 8.1.6 + '@storybook/addon-essentials@8.1.10(@types/react-dom@18.3.0)(@types/react@18.3.3)(encoding@0.1.13)(prettier@3.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@storybook/addon-actions': 8.1.10 + '@storybook/addon-backgrounds': 8.1.10 + '@storybook/addon-controls': 8.1.10(@types/react-dom@18.3.0)(@types/react@18.3.3)(encoding@0.1.13)(prettier@3.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@storybook/addon-docs': 8.1.10(@types/react-dom@18.3.0)(encoding@0.1.13)(prettier@3.3.2) + '@storybook/addon-highlight': 8.1.10 + '@storybook/addon-measure': 8.1.10 + '@storybook/addon-outline': 8.1.10 + '@storybook/addon-toolbars': 8.1.10 + '@storybook/addon-viewport': 8.1.10 + '@storybook/core-common': 8.1.10(encoding@0.1.13)(prettier@3.3.2) + '@storybook/manager-api': 8.1.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@storybook/node-logger': 8.1.10 + '@storybook/preview-api': 8.1.10 ts-dedent: 2.2.0 transitivePeerDependencies: - '@types/react' @@ -12259,16 +12208,16 @@ snapshots: - react-dom - supports-color - '@storybook/addon-highlight@8.1.6': + '@storybook/addon-highlight@8.1.10': dependencies: '@storybook/global': 5.0.0 - '@storybook/addon-interactions@8.1.6(vitest@1.6.0(@types/node@20.14.2)(@vitest/browser@1.6.0(playwright@1.44.1)(vitest@1.6.0))(jsdom@24.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(terser@5.31.1))': + '@storybook/addon-interactions@8.1.10(vitest@1.6.0(@types/node@20.14.5)(@vitest/browser@1.6.0(playwright@1.44.1)(vitest@1.6.0))(jsdom@24.1.0)(terser@5.31.1))': dependencies: '@storybook/global': 5.0.0 - '@storybook/instrumenter': 8.1.6 - '@storybook/test': 8.1.6(vitest@1.6.0(@types/node@20.14.2)(@vitest/browser@1.6.0(playwright@1.44.1)(vitest@1.6.0))(jsdom@24.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(terser@5.31.1)) - '@storybook/types': 8.1.6 + '@storybook/instrumenter': 8.1.10 + '@storybook/test': 8.1.10(vitest@1.6.0(@types/node@20.14.5)(@vitest/browser@1.6.0(playwright@1.44.1)(vitest@1.6.0))(jsdom@24.1.0)(terser@5.31.1)) + '@storybook/types': 8.1.10 polished: 4.3.1 ts-dedent: 2.2.0 transitivePeerDependencies: @@ -12278,7 +12227,7 @@ snapshots: - jest - vitest - '@storybook/addon-links@8.1.6(react@18.3.1)': + '@storybook/addon-links@8.1.10(react@18.3.1)': dependencies: '@storybook/csf': 0.1.8 '@storybook/global': 5.0.0 @@ -12286,46 +12235,46 @@ snapshots: optionalDependencies: react: 18.3.1 - '@storybook/addon-measure@8.1.6': + '@storybook/addon-measure@8.1.10': dependencies: '@storybook/global': 5.0.0 tiny-invariant: 1.3.3 - '@storybook/addon-outline@8.1.6': + '@storybook/addon-outline@8.1.10': dependencies: '@storybook/global': 5.0.0 ts-dedent: 2.2.0 - '@storybook/addon-postcss@2.0.0(webpack@5.92.0(@swc/core@1.5.28(@swc/helpers@0.5.11))(esbuild@0.20.2))': + '@storybook/addon-postcss@2.0.0(webpack@5.92.0(@swc/core@1.6.3)(esbuild@0.20.2))': dependencies: '@storybook/node-logger': 6.5.16 - css-loader: 3.6.0(webpack@5.92.0(@swc/core@1.5.28(@swc/helpers@0.5.11))(esbuild@0.20.2)) + css-loader: 3.6.0(webpack@5.92.0(@swc/core@1.6.3)(esbuild@0.20.2)) postcss: 7.0.39 - postcss-loader: 4.3.0(postcss@7.0.39)(webpack@5.92.0(@swc/core@1.5.28(@swc/helpers@0.5.11))(esbuild@0.20.2)) - style-loader: 1.3.0(webpack@5.92.0(@swc/core@1.5.28(@swc/helpers@0.5.11))(esbuild@0.20.2)) + postcss-loader: 4.3.0(postcss@7.0.39)(webpack@5.92.0(@swc/core@1.6.3)(esbuild@0.20.2)) + style-loader: 1.3.0(webpack@5.92.0(@swc/core@1.6.3)(esbuild@0.20.2)) transitivePeerDependencies: - webpack - '@storybook/addon-toolbars@8.1.6': {} + '@storybook/addon-toolbars@8.1.10': {} - '@storybook/addon-viewport@8.1.6': + '@storybook/addon-viewport@8.1.10': dependencies: memoizerific: 1.11.3 - '@storybook/blocks@8.1.6(@types/react-dom@18.3.0)(@types/react@18.3.3)(encoding@0.1.13)(prettier@3.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@storybook/blocks@8.1.10(@types/react-dom@18.3.0)(@types/react@18.3.3)(encoding@0.1.13)(prettier@3.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@storybook/channels': 8.1.6 - '@storybook/client-logger': 8.1.6 - '@storybook/components': 8.1.6(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@storybook/core-events': 8.1.6 + '@storybook/channels': 8.1.10 + '@storybook/client-logger': 8.1.10 + '@storybook/components': 8.1.10(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@storybook/core-events': 8.1.10 '@storybook/csf': 0.1.8 - '@storybook/docs-tools': 8.1.6(encoding@0.1.13)(prettier@3.3.2) + '@storybook/docs-tools': 8.1.10(encoding@0.1.13)(prettier@3.3.2) '@storybook/global': 5.0.0 '@storybook/icons': 1.2.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@storybook/manager-api': 8.1.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@storybook/preview-api': 8.1.6 - '@storybook/theming': 8.1.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@storybook/types': 8.1.6 + '@storybook/manager-api': 8.1.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@storybook/preview-api': 8.1.10 + '@storybook/theming': 8.1.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@storybook/types': 8.1.10 '@types/lodash': 4.17.5 color-convert: 2.0.1 dequal: 2.0.3 @@ -12348,12 +12297,12 @@ snapshots: - prettier - supports-color - '@storybook/builder-manager@8.1.6(encoding@0.1.13)(prettier@3.3.2)': + '@storybook/builder-manager@8.1.10(encoding@0.1.13)(prettier@3.3.2)': dependencies: '@fal-works/esbuild-plugin-global-externals': 2.1.2 - '@storybook/core-common': 8.1.6(encoding@0.1.13)(prettier@3.3.2) - '@storybook/manager': 8.1.6 - '@storybook/node-logger': 8.1.6 + '@storybook/core-common': 8.1.10(encoding@0.1.13)(prettier@3.3.2) + '@storybook/manager': 8.1.10 + '@storybook/node-logger': 8.1.10 '@types/ejs': 3.1.5 '@yarnpkg/esbuild-plugin-pnp': 3.0.0-rc.15(esbuild@0.20.2) browser-assert: 1.2.1 @@ -12369,7 +12318,7 @@ snapshots: - prettier - supports-color - '@storybook/builder-vite@8.1.1(encoding@0.1.13)(prettier@3.3.2)(typescript@5.4.5)(vite@5.2.13(@types/node@20.14.2)(terser@5.31.1))': + '@storybook/builder-vite@8.1.1(encoding@0.1.13)(prettier@3.3.2)(typescript@5.4.5)(vite@5.3.1(@types/node@20.14.5)(terser@5.31.1))': dependencies: '@storybook/channels': 8.1.1 '@storybook/client-logger': 8.1.1 @@ -12388,7 +12337,7 @@ snapshots: fs-extra: 11.2.0 magic-string: 0.30.10 ts-dedent: 2.2.0 - vite: 5.2.13(@types/node@20.14.2)(terser@5.31.1) + vite: 5.3.1(@types/node@20.14.5)(terser@5.31.1) optionalDependencies: typescript: 5.4.5 transitivePeerDependencies: @@ -12404,27 +12353,27 @@ snapshots: telejson: 7.2.0 tiny-invariant: 1.3.3 - '@storybook/channels@8.1.6': + '@storybook/channels@8.1.10': dependencies: - '@storybook/client-logger': 8.1.6 - '@storybook/core-events': 8.1.6 + '@storybook/client-logger': 8.1.10 + '@storybook/core-events': 8.1.10 '@storybook/global': 5.0.0 telejson: 7.2.0 tiny-invariant: 1.3.3 - '@storybook/cli@8.1.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(utf-8-validate@6.0.4)': + '@storybook/cli@8.1.10(@babel/preset-env@7.24.7(@babel/core@7.24.7))(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@babel/core': 7.24.7 '@babel/types': 7.24.7 '@ndelangen/get-tarball': 3.0.9 - '@storybook/codemod': 8.1.6 - '@storybook/core-common': 8.1.6(encoding@0.1.13)(prettier@3.3.2) - '@storybook/core-events': 8.1.6 - '@storybook/core-server': 8.1.6(bufferutil@4.0.8)(encoding@0.1.13)(prettier@3.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(utf-8-validate@6.0.4) - '@storybook/csf-tools': 8.1.6 - '@storybook/node-logger': 8.1.6 - '@storybook/telemetry': 8.1.6(encoding@0.1.13)(prettier@3.3.2) - '@storybook/types': 8.1.6 + '@storybook/codemod': 8.1.10 + '@storybook/core-common': 8.1.10(encoding@0.1.13)(prettier@3.3.2) + '@storybook/core-events': 8.1.10 + '@storybook/core-server': 8.1.10(encoding@0.1.13)(prettier@3.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@storybook/csf-tools': 8.1.10 + '@storybook/node-logger': 8.1.10 + '@storybook/telemetry': 8.1.10(encoding@0.1.13)(prettier@3.3.2) + '@storybook/types': 8.1.10 '@types/semver': 7.5.8 '@yarnpkg/fslib': 2.10.3 '@yarnpkg/libzip': 2.3.0 @@ -12463,19 +12412,19 @@ snapshots: dependencies: '@storybook/global': 5.0.0 - '@storybook/client-logger@8.1.6': + '@storybook/client-logger@8.1.10': dependencies: '@storybook/global': 5.0.0 - '@storybook/codemod@8.1.6': + '@storybook/codemod@8.1.10': dependencies: '@babel/core': 7.24.7 '@babel/preset-env': 7.24.7(@babel/core@7.24.7) '@babel/types': 7.24.7 '@storybook/csf': 0.1.8 - '@storybook/csf-tools': 8.1.6 - '@storybook/node-logger': 8.1.6 - '@storybook/types': 8.1.6 + '@storybook/csf-tools': 8.1.10 + '@storybook/node-logger': 8.1.10 + '@storybook/types': 8.1.10 '@types/cross-spawn': 6.0.6 cross-spawn: 7.0.3 globby: 14.0.1 @@ -12487,16 +12436,16 @@ snapshots: transitivePeerDependencies: - supports-color - '@storybook/components@8.1.6(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@storybook/components@8.1.10(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/react-dialog': 1.0.5(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-slot': 1.0.2(@types/react@18.3.3)(react@18.3.1) - '@storybook/client-logger': 8.1.6 + '@storybook/client-logger': 8.1.10 '@storybook/csf': 0.1.8 '@storybook/global': 5.0.0 '@storybook/icons': 1.2.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@storybook/theming': 8.1.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@storybook/types': 8.1.6 + '@storybook/theming': 8.1.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@storybook/types': 8.1.10 memoizerific: 1.11.3 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -12522,7 +12471,7 @@ snapshots: find-cache-dir: 3.3.2 find-up: 5.0.0 fs-extra: 11.2.0 - glob: 10.4.1 + glob: 10.4.2 handlebars: 4.7.8 lazy-universal-dotenv: 4.0.0 node-fetch: 2.7.0(encoding@0.1.13) @@ -12542,12 +12491,12 @@ snapshots: - encoding - supports-color - '@storybook/core-common@8.1.6(encoding@0.1.13)(prettier@3.3.2)': + '@storybook/core-common@8.1.10(encoding@0.1.13)(prettier@3.3.2)': dependencies: - '@storybook/core-events': 8.1.6 - '@storybook/csf-tools': 8.1.6 - '@storybook/node-logger': 8.1.6 - '@storybook/types': 8.1.6 + '@storybook/core-events': 8.1.10 + '@storybook/csf-tools': 8.1.10 + '@storybook/node-logger': 8.1.10 + '@storybook/types': 8.1.10 '@yarnpkg/fslib': 2.10.3 '@yarnpkg/libzip': 2.3.0 chalk: 4.1.2 @@ -12559,7 +12508,7 @@ snapshots: find-cache-dir: 3.3.2 find-up: 5.0.0 fs-extra: 11.2.0 - glob: 10.4.1 + glob: 10.4.2 handlebars: 4.7.8 lazy-universal-dotenv: 4.0.0 node-fetch: 2.7.0(encoding@0.1.13) @@ -12584,34 +12533,34 @@ snapshots: '@storybook/csf': 0.1.8 ts-dedent: 2.2.0 - '@storybook/core-events@8.1.6': + '@storybook/core-events@8.1.10': dependencies: '@storybook/csf': 0.1.8 ts-dedent: 2.2.0 - '@storybook/core-server@8.1.6(bufferutil@4.0.8)(encoding@0.1.13)(prettier@3.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(utf-8-validate@6.0.4)': + '@storybook/core-server@8.1.10(encoding@0.1.13)(prettier@3.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@aw-web-design/x-default-browser': 1.4.126 '@babel/core': 7.24.7 '@babel/parser': 7.24.7 '@discoveryjs/json-ext': 0.5.7 - '@storybook/builder-manager': 8.1.6(encoding@0.1.13)(prettier@3.3.2) - '@storybook/channels': 8.1.6 - '@storybook/core-common': 8.1.6(encoding@0.1.13)(prettier@3.3.2) - '@storybook/core-events': 8.1.6 + '@storybook/builder-manager': 8.1.10(encoding@0.1.13)(prettier@3.3.2) + '@storybook/channels': 8.1.10 + '@storybook/core-common': 8.1.10(encoding@0.1.13)(prettier@3.3.2) + '@storybook/core-events': 8.1.10 '@storybook/csf': 0.1.8 - '@storybook/csf-tools': 8.1.6 + '@storybook/csf-tools': 8.1.10 '@storybook/docs-mdx': 3.1.0-next.0 '@storybook/global': 5.0.0 - '@storybook/manager': 8.1.6 - '@storybook/manager-api': 8.1.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@storybook/node-logger': 8.1.6 - '@storybook/preview-api': 8.1.6 - '@storybook/telemetry': 8.1.6(encoding@0.1.13)(prettier@3.3.2) - '@storybook/types': 8.1.6 + '@storybook/manager': 8.1.10 + '@storybook/manager-api': 8.1.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@storybook/node-logger': 8.1.10 + '@storybook/preview-api': 8.1.10 + '@storybook/telemetry': 8.1.10(encoding@0.1.13)(prettier@3.3.2) + '@storybook/types': 8.1.10 '@types/detect-port': 1.3.5 '@types/diff': 5.2.1 - '@types/node': 18.19.34 + '@types/node': 18.19.36 '@types/pretty-hrtime': 1.0.3 '@types/semver': 7.5.8 better-opn: 3.0.2 @@ -12635,7 +12584,7 @@ snapshots: util: 0.12.5 util-deprecate: 1.0.2 watchpack: 2.4.1 - ws: 8.17.0(bufferutil@4.0.8)(utf-8-validate@6.0.4) + ws: 8.17.1 transitivePeerDependencies: - bufferutil - encoding @@ -12652,9 +12601,9 @@ snapshots: transitivePeerDependencies: - supports-color - '@storybook/csf-plugin@8.1.6': + '@storybook/csf-plugin@8.1.10': dependencies: - '@storybook/csf-tools': 8.1.6 + '@storybook/csf-tools': 8.1.10 unplugin: 1.10.1 transitivePeerDependencies: - supports-color @@ -12673,14 +12622,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@storybook/csf-tools@8.1.6': + '@storybook/csf-tools@8.1.10': dependencies: '@babel/generator': 7.24.7 '@babel/parser': 7.24.7 '@babel/traverse': 7.24.7 '@babel/types': 7.24.7 '@storybook/csf': 0.1.8 - '@storybook/types': 8.1.6 + '@storybook/types': 8.1.10 fs-extra: 11.2.0 recast: 0.23.9 ts-dedent: 2.2.0 @@ -12712,12 +12661,12 @@ snapshots: - prettier - supports-color - '@storybook/docs-tools@8.1.6(encoding@0.1.13)(prettier@3.3.2)': + '@storybook/docs-tools@8.1.10(encoding@0.1.13)(prettier@3.3.2)': dependencies: - '@storybook/core-common': 8.1.6(encoding@0.1.13)(prettier@3.3.2) - '@storybook/core-events': 8.1.6 - '@storybook/preview-api': 8.1.6 - '@storybook/types': 8.1.6 + '@storybook/core-common': 8.1.10(encoding@0.1.13)(prettier@3.3.2) + '@storybook/core-events': 8.1.10 + '@storybook/preview-api': 8.1.10 + '@storybook/types': 8.1.10 '@types/doctrine': 0.0.3 assert: 2.1.0 doctrine: 3.0.0 @@ -12734,27 +12683,27 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@storybook/instrumenter@8.1.6': + '@storybook/instrumenter@8.1.10': dependencies: - '@storybook/channels': 8.1.6 - '@storybook/client-logger': 8.1.6 - '@storybook/core-events': 8.1.6 + '@storybook/channels': 8.1.10 + '@storybook/client-logger': 8.1.10 + '@storybook/core-events': 8.1.10 '@storybook/global': 5.0.0 - '@storybook/preview-api': 8.1.6 + '@storybook/preview-api': 8.1.10 '@vitest/utils': 1.6.0 util: 0.12.5 - '@storybook/manager-api@8.1.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@storybook/manager-api@8.1.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@storybook/channels': 8.1.6 - '@storybook/client-logger': 8.1.6 - '@storybook/core-events': 8.1.6 + '@storybook/channels': 8.1.10 + '@storybook/client-logger': 8.1.10 + '@storybook/core-events': 8.1.10 '@storybook/csf': 0.1.8 '@storybook/global': 5.0.0 '@storybook/icons': 1.2.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@storybook/router': 8.1.6 - '@storybook/theming': 8.1.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@storybook/types': 8.1.6 + '@storybook/router': 8.1.10 + '@storybook/theming': 8.1.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@storybook/types': 8.1.10 dequal: 2.0.3 lodash: 4.17.21 memoizerific: 1.11.3 @@ -12765,7 +12714,7 @@ snapshots: - react - react-dom - '@storybook/manager@8.1.6': {} + '@storybook/manager@8.1.10': {} '@storybook/node-logger@6.5.16': dependencies: @@ -12777,7 +12726,7 @@ snapshots: '@storybook/node-logger@8.1.1': {} - '@storybook/node-logger@8.1.6': {} + '@storybook/node-logger@8.1.10': {} '@storybook/preview-api@8.1.1': dependencies: @@ -12796,14 +12745,14 @@ snapshots: ts-dedent: 2.2.0 util-deprecate: 1.0.2 - '@storybook/preview-api@8.1.6': + '@storybook/preview-api@8.1.10': dependencies: - '@storybook/channels': 8.1.6 - '@storybook/client-logger': 8.1.6 - '@storybook/core-events': 8.1.6 + '@storybook/channels': 8.1.10 + '@storybook/client-logger': 8.1.10 + '@storybook/core-events': 8.1.10 '@storybook/csf': 0.1.8 '@storybook/global': 5.0.0 - '@storybook/types': 8.1.6 + '@storybook/types': 8.1.10 '@types/qs': 6.9.15 dequal: 2.0.3 lodash: 4.17.21 @@ -12820,16 +12769,16 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@storybook/react-dom-shim@8.1.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@storybook/react-dom-shim@8.1.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@storybook/react-vite@8.1.1(encoding@0.1.13)(prettier@3.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.18.0)(typescript@5.4.5)(vite@5.2.13(@types/node@20.14.2)(terser@5.31.1))': + '@storybook/react-vite@8.1.1(encoding@0.1.13)(prettier@3.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.18.0)(typescript@5.4.5)(vite@5.3.1(@types/node@20.14.5)(terser@5.31.1))': dependencies: - '@joshwooding/vite-plugin-react-docgen-typescript': 0.3.1(typescript@5.4.5)(vite@5.2.13(@types/node@20.14.2)(terser@5.31.1)) + '@joshwooding/vite-plugin-react-docgen-typescript': 0.3.1(typescript@5.4.5)(vite@5.3.1(@types/node@20.14.5)(terser@5.31.1)) '@rollup/pluginutils': 5.1.0(rollup@4.18.0) - '@storybook/builder-vite': 8.1.1(encoding@0.1.13)(prettier@3.3.2)(typescript@5.4.5)(vite@5.2.13(@types/node@20.14.2)(terser@5.31.1)) + '@storybook/builder-vite': 8.1.1(encoding@0.1.13)(prettier@3.3.2)(typescript@5.4.5)(vite@5.3.1(@types/node@20.14.5)(terser@5.31.1)) '@storybook/node-logger': 8.1.1 '@storybook/react': 8.1.1(encoding@0.1.13)(prettier@3.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5) '@storybook/types': 8.1.1 @@ -12840,7 +12789,7 @@ snapshots: react-dom: 18.3.1(react@18.3.1) resolve: 1.22.8 tsconfig-paths: 4.2.0 - vite: 5.2.13(@types/node@20.14.2)(terser@5.31.1) + vite: 5.3.1(@types/node@20.14.5)(terser@5.31.1) transitivePeerDependencies: - '@preact/preset-vite' - encoding @@ -12860,7 +12809,7 @@ snapshots: '@storybook/types': 8.1.1 '@types/escodegen': 0.0.6 '@types/estree': 0.0.51 - '@types/node': 18.19.34 + '@types/node': 18.19.36 acorn: 7.4.1 acorn-jsx: 5.3.2(acorn@7.4.1) acorn-walk: 7.2.0 @@ -12882,17 +12831,17 @@ snapshots: - prettier - supports-color - '@storybook/react@8.1.6(encoding@0.1.13)(prettier@3.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)': + '@storybook/react@8.1.10(encoding@0.1.13)(prettier@3.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)': dependencies: - '@storybook/client-logger': 8.1.6 - '@storybook/docs-tools': 8.1.6(encoding@0.1.13)(prettier@3.3.2) + '@storybook/client-logger': 8.1.10 + '@storybook/docs-tools': 8.1.10(encoding@0.1.13)(prettier@3.3.2) '@storybook/global': 5.0.0 - '@storybook/preview-api': 8.1.6 - '@storybook/react-dom-shim': 8.1.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@storybook/types': 8.1.6 + '@storybook/preview-api': 8.1.10 + '@storybook/react-dom-shim': 8.1.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@storybook/types': 8.1.10 '@types/escodegen': 0.0.6 '@types/estree': 0.0.51 - '@types/node': 18.19.34 + '@types/node': 18.19.36 acorn: 7.4.1 acorn-jsx: 5.3.2(acorn@7.4.1) acorn-walk: 7.2.0 @@ -12914,17 +12863,17 @@ snapshots: - prettier - supports-color - '@storybook/router@8.1.6': + '@storybook/router@8.1.10': dependencies: - '@storybook/client-logger': 8.1.6 + '@storybook/client-logger': 8.1.10 memoizerific: 1.11.3 qs: 6.12.1 - '@storybook/telemetry@8.1.6(encoding@0.1.13)(prettier@3.3.2)': + '@storybook/telemetry@8.1.10(encoding@0.1.13)(prettier@3.3.2)': dependencies: - '@storybook/client-logger': 8.1.6 - '@storybook/core-common': 8.1.6(encoding@0.1.13)(prettier@3.3.2) - '@storybook/csf-tools': 8.1.6 + '@storybook/client-logger': 8.1.10 + '@storybook/core-common': 8.1.10(encoding@0.1.13)(prettier@3.3.2) + '@storybook/csf-tools': 8.1.10 chalk: 4.1.2 detect-package-manager: 2.0.1 fetch-retry: 5.0.6 @@ -12935,14 +12884,14 @@ snapshots: - prettier - supports-color - '@storybook/test@8.1.6(vitest@1.6.0(@types/node@20.14.2)(@vitest/browser@1.6.0(playwright@1.44.1)(vitest@1.6.0))(jsdom@24.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(terser@5.31.1))': + '@storybook/test@8.1.10(vitest@1.6.0(@types/node@20.14.5)(@vitest/browser@1.6.0(playwright@1.44.1)(vitest@1.6.0))(jsdom@24.1.0)(terser@5.31.1))': dependencies: - '@storybook/client-logger': 8.1.6 - '@storybook/core-events': 8.1.6 - '@storybook/instrumenter': 8.1.6 - '@storybook/preview-api': 8.1.6 + '@storybook/client-logger': 8.1.10 + '@storybook/core-events': 8.1.10 + '@storybook/instrumenter': 8.1.10 + '@storybook/preview-api': 8.1.10 '@testing-library/dom': 9.3.4 - '@testing-library/jest-dom': 6.4.6(vitest@1.6.0(@types/node@20.14.2)(@vitest/browser@1.6.0(playwright@1.44.1)(vitest@1.6.0))(jsdom@24.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(terser@5.31.1)) + '@testing-library/jest-dom': 6.4.6(vitest@1.6.0(@types/node@20.14.5)(@vitest/browser@1.6.0(playwright@1.44.1)(vitest@1.6.0))(jsdom@24.1.0)(terser@5.31.1)) '@testing-library/user-event': 14.5.2(@testing-library/dom@9.3.4) '@vitest/expect': 1.3.1 '@vitest/spy': 1.6.0 @@ -12954,10 +12903,10 @@ snapshots: - jest - vitest - '@storybook/theming@8.1.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@storybook/theming@8.1.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@emotion/use-insertion-effect-with-fallbacks': 1.0.1(react@18.3.1) - '@storybook/client-logger': 8.1.6 + '@storybook/client-logger': 8.1.10 '@storybook/global': 5.0.0 memoizerific: 1.11.3 optionalDependencies: @@ -12970,66 +12919,60 @@ snapshots: '@types/express': 4.17.21 file-system-cache: 2.3.0 - '@storybook/types@8.1.6': + '@storybook/types@8.1.10': dependencies: - '@storybook/channels': 8.1.6 + '@storybook/channels': 8.1.10 '@types/express': 4.17.21 file-system-cache: 2.3.0 - '@swc/core-darwin-arm64@1.5.28': + '@swc/core-darwin-arm64@1.6.3': optional: true - '@swc/core-darwin-x64@1.5.28': + '@swc/core-darwin-x64@1.6.3': optional: true - '@swc/core-linux-arm-gnueabihf@1.5.28': + '@swc/core-linux-arm-gnueabihf@1.6.3': optional: true - '@swc/core-linux-arm64-gnu@1.5.28': + '@swc/core-linux-arm64-gnu@1.6.3': optional: true - '@swc/core-linux-arm64-musl@1.5.28': + '@swc/core-linux-arm64-musl@1.6.3': optional: true - '@swc/core-linux-x64-gnu@1.5.28': + '@swc/core-linux-x64-gnu@1.6.3': optional: true - '@swc/core-linux-x64-musl@1.5.28': + '@swc/core-linux-x64-musl@1.6.3': optional: true - '@swc/core-win32-arm64-msvc@1.5.28': + '@swc/core-win32-arm64-msvc@1.6.3': optional: true - '@swc/core-win32-ia32-msvc@1.5.28': + '@swc/core-win32-ia32-msvc@1.6.3': optional: true - '@swc/core-win32-x64-msvc@1.5.28': + '@swc/core-win32-x64-msvc@1.6.3': optional: true - '@swc/core@1.5.28(@swc/helpers@0.5.11)': + '@swc/core@1.6.3': dependencies: '@swc/counter': 0.1.3 '@swc/types': 0.1.8 optionalDependencies: - '@swc/core-darwin-arm64': 1.5.28 - '@swc/core-darwin-x64': 1.5.28 - '@swc/core-linux-arm-gnueabihf': 1.5.28 - '@swc/core-linux-arm64-gnu': 1.5.28 - '@swc/core-linux-arm64-musl': 1.5.28 - '@swc/core-linux-x64-gnu': 1.5.28 - '@swc/core-linux-x64-musl': 1.5.28 - '@swc/core-win32-arm64-msvc': 1.5.28 - '@swc/core-win32-ia32-msvc': 1.5.28 - '@swc/core-win32-x64-msvc': 1.5.28 - '@swc/helpers': 0.5.11 + '@swc/core-darwin-arm64': 1.6.3 + '@swc/core-darwin-x64': 1.6.3 + '@swc/core-linux-arm-gnueabihf': 1.6.3 + '@swc/core-linux-arm64-gnu': 1.6.3 + '@swc/core-linux-arm64-musl': 1.6.3 + '@swc/core-linux-x64-gnu': 1.6.3 + '@swc/core-linux-x64-musl': 1.6.3 + '@swc/core-win32-arm64-msvc': 1.6.3 + '@swc/core-win32-ia32-msvc': 1.6.3 + '@swc/core-win32-x64-msvc': 1.6.3 '@swc/counter@0.1.3': {} - '@swc/helpers@0.5.11': - dependencies: - tslib: 2.6.3 - optional: true - '@swc/types@0.1.8': dependencies: '@swc/counter': 0.1.3 @@ -13040,7 +12983,7 @@ snapshots: dependencies: '@tanstack/query-core': 4.36.1 react: 18.3.1 - use-sync-external-store: 1.2.0(react@18.3.1) + use-sync-external-store: 1.2.2(react@18.3.1) optionalDependencies: react-dom: 18.3.1(react@18.3.1) @@ -13066,7 +13009,7 @@ snapshots: lz-string: 1.5.0 pretty-format: 27.5.1 - '@testing-library/jest-dom@6.4.6(vitest@1.6.0(@types/node@20.14.2)(@vitest/browser@1.6.0(playwright@1.44.1)(vitest@1.6.0))(jsdom@24.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(terser@5.31.1))': + '@testing-library/jest-dom@6.4.6(vitest@1.6.0(@types/node@20.14.5)(@vitest/browser@1.6.0(playwright@1.44.1)(vitest@1.6.0))(jsdom@24.1.0)(terser@5.31.1))': dependencies: '@adobe/css-tools': 4.4.0 '@babel/runtime': 7.24.7 @@ -13077,7 +13020,7 @@ snapshots: lodash: 4.17.21 redent: 3.0.0 optionalDependencies: - vitest: 1.6.0(@types/node@20.14.2)(@vitest/browser@1.6.0(playwright@1.44.1)(vitest@1.6.0))(jsdom@24.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(terser@5.31.1) + vitest: 1.6.0(@types/node@20.14.5)(@vitest/browser@1.6.0(playwright@1.44.1)(vitest@1.6.0))(jsdom@24.1.0)(terser@5.31.1) '@testing-library/react@15.0.7(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: @@ -13093,11 +13036,11 @@ snapshots: dependencies: '@testing-library/dom': 9.3.4 - '@textea/json-viewer@3.4.1(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@mui/material@5.15.19(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@types/react@18.3.3)(immer@10.1.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@textea/json-viewer@3.4.1(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@mui/material@5.15.20(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@types/react@18.3.3)(immer@10.1.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@emotion/react': 11.11.4(@types/react@18.3.3)(react@18.3.1) '@emotion/styled': 11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1) - '@mui/material': 5.15.19(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@mui/material': 5.15.20(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) clsx: 2.1.1 copy-to-clipboard: 3.3.3 react: 18.3.1 @@ -13119,7 +13062,7 @@ snapshots: '@tsconfig/node16@1.0.4': {} - '@turbo/gen@1.13.4(@swc/core@1.5.28(@swc/helpers@0.5.11))(@types/node@20.14.2)(typescript@5.4.5)': + '@turbo/gen@1.13.4(@swc/core@1.6.3)(@types/node@20.14.5)(typescript@5.4.5)': dependencies: '@turbo/workspaces': 1.13.4 chalk: 2.4.2 @@ -13129,7 +13072,7 @@ snapshots: minimatch: 9.0.4 node-plop: 0.26.3 proxy-agent: 6.4.0 - ts-node: 10.9.2(@swc/core@1.5.28(@swc/helpers@0.5.11))(@types/node@20.14.2)(typescript@5.4.5) + ts-node: 10.9.2(@swc/core@1.6.3)(@types/node@20.14.5)(typescript@5.4.5) update-check: 1.5.4 validate-npm-package-name: 5.0.1 transitivePeerDependencies: @@ -13154,8 +13097,6 @@ snapshots: semver: 7.6.2 update-check: 1.5.4 - '@types/argparse@1.0.38': {} - '@types/aria-query@5.0.4': {} '@types/babel__core@7.20.5': @@ -13182,7 +13123,7 @@ snapshots: '@types/body-parser@1.19.5': dependencies: '@types/connect': 3.4.38 - '@types/node': 20.14.2 + '@types/node': 20.14.5 '@types/caseless@0.12.5': {} @@ -13193,13 +13134,11 @@ snapshots: '@types/connect@3.4.38': dependencies: - '@types/node': 20.14.2 + '@types/node': 20.14.5 '@types/cross-spawn@6.0.6': dependencies: - '@types/node': 20.14.2 - - '@types/crypto-js@4.2.2': {} + '@types/node': 20.14.5 '@types/d3-array@3.0.3': {} @@ -13261,7 +13200,7 @@ snapshots: '@types/express-serve-static-core@4.19.3': dependencies: - '@types/node': 20.14.2 + '@types/node': 20.14.5 '@types/qs': 6.9.15 '@types/range-parser': 1.2.7 '@types/send': 0.17.4 @@ -13281,14 +13220,14 @@ snapshots: '@types/find-cache-dir@3.2.1': {} - '@types/firefox-webext-browser@120.0.3': {} + '@types/firefox-webext-browser@120.0.4': {} '@types/geojson@7946.0.14': {} '@types/glob@7.2.0': dependencies: '@types/minimatch': 5.1.2 - '@types/node': 20.14.2 + '@types/node': 20.14.5 '@types/har-format@1.2.15': {} @@ -13325,11 +13264,11 @@ snapshots: '@types/node@12.20.55': {} - '@types/node@18.19.34': + '@types/node@18.19.36': dependencies: undici-types: 5.26.5 - '@types/node@20.14.2': + '@types/node@20.14.5': dependencies: undici-types: 5.26.5 @@ -13337,7 +13276,7 @@ snapshots: '@types/npmlog@4.1.6': dependencies: - '@types/node': 20.14.2 + '@types/node': 20.14.5 '@types/parse-json@4.0.2': {} @@ -13365,7 +13304,7 @@ snapshots: '@types/request@2.48.12': dependencies: '@types/caseless': 0.12.5 - '@types/node': 20.14.2 + '@types/node': 20.14.5 '@types/tough-cookie': 4.0.5 form-data: 2.5.1 @@ -13376,19 +13315,19 @@ snapshots: '@types/send@0.17.4': dependencies: '@types/mime': 1.3.5 - '@types/node': 20.14.2 + '@types/node': 20.14.5 '@types/serve-static@1.15.7': dependencies: '@types/http-errors': 2.0.4 - '@types/node': 20.14.2 + '@types/node': 20.14.5 '@types/send': 0.17.4 '@types/stylis@4.2.5': {} '@types/through@0.0.33': dependencies: - '@types/node': 20.14.2 + '@types/node': 20.14.5 '@types/tinycolor2@1.4.6': {} @@ -13400,26 +13339,26 @@ snapshots: '@types/uuid@9.0.8': {} - '@types/webpack@5.28.5(@swc/core@1.5.28(@swc/helpers@0.5.11))(webpack-cli@5.1.4(webpack@5.92.0))': + '@types/webpack@5.28.5(@swc/core@1.6.3)(esbuild@0.20.2)(webpack-cli@5.1.4(webpack@5.92.0))': dependencies: - '@types/node': 20.14.2 + '@types/node': 20.14.5 tapable: 2.2.1 - webpack: 5.92.0(@swc/core@1.5.28(@swc/helpers@0.5.11))(webpack-cli@5.1.4) + webpack: 5.92.0(@swc/core@1.6.3)(esbuild@0.20.2)(webpack-cli@5.1.4(webpack@5.92.0)) transitivePeerDependencies: - '@swc/core' - esbuild - uglify-js - webpack-cli - '@typescript-eslint/eslint-plugin@7.13.0(@typescript-eslint/parser@7.13.0(eslint@9.4.0)(typescript@5.4.5))(eslint@9.4.0)(typescript@5.4.5)': + '@typescript-eslint/eslint-plugin@7.13.1(@typescript-eslint/parser@7.13.1(eslint@9.5.0)(typescript@5.4.5))(eslint@9.5.0)(typescript@5.4.5)': dependencies: '@eslint-community/regexpp': 4.10.1 - '@typescript-eslint/parser': 7.13.0(eslint@9.4.0)(typescript@5.4.5) - '@typescript-eslint/scope-manager': 7.13.0 - '@typescript-eslint/type-utils': 7.13.0(eslint@9.4.0)(typescript@5.4.5) - '@typescript-eslint/utils': 7.13.0(eslint@9.4.0)(typescript@5.4.5) - '@typescript-eslint/visitor-keys': 7.13.0 - eslint: 9.4.0 + '@typescript-eslint/parser': 7.13.1(eslint@9.5.0)(typescript@5.4.5) + '@typescript-eslint/scope-manager': 7.13.1 + '@typescript-eslint/type-utils': 7.13.1(eslint@9.5.0)(typescript@5.4.5) + '@typescript-eslint/utils': 7.13.1(eslint@9.5.0)(typescript@5.4.5) + '@typescript-eslint/visitor-keys': 7.13.1 + eslint: 9.5.0 graphemer: 1.4.0 ignore: 5.3.1 natural-compare: 1.4.0 @@ -13429,14 +13368,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@7.13.0(eslint@9.4.0)(typescript@5.4.5)': + '@typescript-eslint/parser@7.13.1(eslint@9.5.0)(typescript@5.4.5)': dependencies: - '@typescript-eslint/scope-manager': 7.13.0 - '@typescript-eslint/types': 7.13.0 - '@typescript-eslint/typescript-estree': 7.13.0(typescript@5.4.5) - '@typescript-eslint/visitor-keys': 7.13.0 + '@typescript-eslint/scope-manager': 7.13.1 + '@typescript-eslint/types': 7.13.1 + '@typescript-eslint/typescript-estree': 7.13.1(typescript@5.4.5) + '@typescript-eslint/visitor-keys': 7.13.1 debug: 4.3.5 - eslint: 9.4.0 + eslint: 9.5.0 optionalDependencies: typescript: 5.4.5 transitivePeerDependencies: @@ -13447,17 +13386,17 @@ snapshots: '@typescript-eslint/types': 5.62.0 '@typescript-eslint/visitor-keys': 5.62.0 - '@typescript-eslint/scope-manager@7.13.0': + '@typescript-eslint/scope-manager@7.13.1': dependencies: - '@typescript-eslint/types': 7.13.0 - '@typescript-eslint/visitor-keys': 7.13.0 + '@typescript-eslint/types': 7.13.1 + '@typescript-eslint/visitor-keys': 7.13.1 - '@typescript-eslint/type-utils@7.13.0(eslint@9.4.0)(typescript@5.4.5)': + '@typescript-eslint/type-utils@7.13.1(eslint@9.5.0)(typescript@5.4.5)': dependencies: - '@typescript-eslint/typescript-estree': 7.13.0(typescript@5.4.5) - '@typescript-eslint/utils': 7.13.0(eslint@9.4.0)(typescript@5.4.5) + '@typescript-eslint/typescript-estree': 7.13.1(typescript@5.4.5) + '@typescript-eslint/utils': 7.13.1(eslint@9.5.0)(typescript@5.4.5) debug: 4.3.5 - eslint: 9.4.0 + eslint: 9.5.0 ts-api-utils: 1.3.0(typescript@5.4.5) optionalDependencies: typescript: 5.4.5 @@ -13466,7 +13405,7 @@ snapshots: '@typescript-eslint/types@5.62.0': {} - '@typescript-eslint/types@7.13.0': {} + '@typescript-eslint/types@7.13.1': {} '@typescript-eslint/typescript-estree@5.62.0(typescript@5.4.5)': dependencies: @@ -13482,10 +13421,10 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/typescript-estree@7.13.0(typescript@5.4.5)': + '@typescript-eslint/typescript-estree@7.13.1(typescript@5.4.5)': dependencies: - '@typescript-eslint/types': 7.13.0 - '@typescript-eslint/visitor-keys': 7.13.0 + '@typescript-eslint/types': 7.13.1 + '@typescript-eslint/visitor-keys': 7.13.1 debug: 4.3.5 globby: 11.1.0 is-glob: 4.0.3 @@ -13497,28 +13436,28 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@5.62.0(eslint@9.4.0)(typescript@5.4.5)': + '@typescript-eslint/utils@5.62.0(eslint@9.5.0)(typescript@5.4.5)': dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@9.4.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@9.5.0) '@types/json-schema': 7.0.15 '@types/semver': 7.5.8 '@typescript-eslint/scope-manager': 5.62.0 '@typescript-eslint/types': 5.62.0 '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.4.5) - eslint: 9.4.0 + eslint: 9.5.0 eslint-scope: 5.1.1 semver: 7.6.2 transitivePeerDependencies: - supports-color - typescript - '@typescript-eslint/utils@7.13.0(eslint@9.4.0)(typescript@5.4.5)': + '@typescript-eslint/utils@7.13.1(eslint@9.5.0)(typescript@5.4.5)': dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@9.4.0) - '@typescript-eslint/scope-manager': 7.13.0 - '@typescript-eslint/types': 7.13.0 - '@typescript-eslint/typescript-estree': 7.13.0(typescript@5.4.5) - eslint: 9.4.0 + '@eslint-community/eslint-utils': 4.4.0(eslint@9.5.0) + '@typescript-eslint/scope-manager': 7.13.1 + '@typescript-eslint/types': 7.13.1 + '@typescript-eslint/typescript-estree': 7.13.1(typescript@5.4.5) + eslint: 9.5.0 transitivePeerDependencies: - supports-color - typescript @@ -13528,9 +13467,9 @@ snapshots: '@typescript-eslint/types': 5.62.0 eslint-visitor-keys: 3.4.3 - '@typescript-eslint/visitor-keys@7.13.0': + '@typescript-eslint/visitor-keys@7.13.1': dependencies: - '@typescript-eslint/types': 7.13.0 + '@typescript-eslint/types': 7.13.1 eslint-visitor-keys: 3.4.3 '@ungap/structured-clone@1.2.0': {} @@ -13677,34 +13616,19 @@ snapshots: d3-time-format: 4.1.0 internmap: 2.0.3 - '@vitejs/plugin-basic-ssl@1.1.0(vite@5.2.13(@types/node@20.14.2)(terser@5.31.1))': - dependencies: - vite: 5.2.13(@types/node@20.14.2)(terser@5.31.1) - - '@vitejs/plugin-react-swc@3.7.0(@swc/helpers@0.5.11)(vite@5.2.13(@types/node@20.14.2)(terser@5.31.1))': + '@vitejs/plugin-react-swc@3.7.0(vite@5.3.1(@types/node@20.14.5)(terser@5.31.1))': dependencies: - '@swc/core': 1.5.28(@swc/helpers@0.5.11) - vite: 5.2.13(@types/node@20.14.2)(terser@5.31.1) + '@swc/core': 1.6.3 + vite: 5.3.1(@types/node@20.14.5)(terser@5.31.1) transitivePeerDependencies: - '@swc/helpers' - '@vitejs/plugin-react@4.3.1(vite@5.2.13(@types/node@20.14.2)(terser@5.31.1))': - dependencies: - '@babel/core': 7.24.7 - '@babel/plugin-transform-react-jsx-self': 7.24.7(@babel/core@7.24.7) - '@babel/plugin-transform-react-jsx-source': 7.24.7(@babel/core@7.24.7) - '@types/babel__core': 7.20.5 - react-refresh: 0.14.2 - vite: 5.2.13(@types/node@20.14.2)(terser@5.31.1) - transitivePeerDependencies: - - supports-color - '@vitest/browser@1.6.0(playwright@1.44.1)(vitest@1.6.0)': dependencies: '@vitest/utils': 1.6.0 magic-string: 0.30.10 sirv: 2.0.4 - vitest: 1.6.0(@types/node@20.14.2)(@vitest/browser@1.6.0(playwright@1.44.1)(vitest@1.6.0))(jsdom@24.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(terser@5.31.1) + vitest: 1.6.0(@types/node@20.14.5)(@vitest/browser@1.6.0(playwright@1.44.1)(vitest@1.6.0))(jsdom@24.1.0)(terser@5.31.1) optionalDependencies: playwright: 1.44.1 @@ -13754,48 +13678,6 @@ snapshots: loupe: 2.3.7 pretty-format: 29.7.0 - '@volar/language-core@1.11.1': - dependencies: - '@volar/source-map': 1.11.1 - - '@volar/source-map@1.11.1': - dependencies: - muggle-string: 0.3.1 - - '@volar/typescript@1.11.1': - dependencies: - '@volar/language-core': 1.11.1 - path-browserify: 1.0.1 - - '@vue/compiler-core@3.4.27': - dependencies: - '@babel/parser': 7.24.7 - '@vue/shared': 3.4.27 - entities: 4.5.0 - estree-walker: 2.0.2 - source-map-js: 1.2.0 - - '@vue/compiler-dom@3.4.27': - dependencies: - '@vue/compiler-core': 3.4.27 - '@vue/shared': 3.4.27 - - '@vue/language-core@1.8.27(typescript@5.4.5)': - dependencies: - '@volar/language-core': 1.11.1 - '@volar/source-map': 1.11.1 - '@vue/compiler-dom': 3.4.27 - '@vue/shared': 3.4.27 - computeds: 0.0.1 - minimatch: 9.0.4 - muggle-string: 0.3.1 - path-browserify: 1.0.1 - vue-template-compiler: 2.7.16 - optionalDependencies: - typescript: 5.4.5 - - '@vue/shared@3.4.27': {} - '@webassemblyjs/ast@1.12.1': dependencies: '@webassemblyjs/helper-numbers': 1.11.6 @@ -13872,19 +13754,19 @@ snapshots: '@webassemblyjs/ast': 1.12.1 '@xtuc/long': 4.2.2 - '@webpack-cli/configtest@2.1.1(webpack-cli@5.1.4(webpack@5.92.0))(webpack@5.92.0(@swc/core@1.5.28(@swc/helpers@0.5.11))(webpack-cli@5.1.4))': + '@webpack-cli/configtest@2.1.1(webpack-cli@5.1.4(webpack@5.92.0))(webpack@5.92.0(@swc/core@1.6.3)(esbuild@0.20.2)(webpack-cli@5.1.4(webpack@5.92.0)))': dependencies: - webpack: 5.92.0(@swc/core@1.5.28(@swc/helpers@0.5.11))(webpack-cli@5.1.4) + webpack: 5.92.0(@swc/core@1.6.3)(esbuild@0.20.2)(webpack-cli@5.1.4(webpack@5.92.0)) webpack-cli: 5.1.4(webpack@5.92.0) - '@webpack-cli/info@2.0.2(webpack-cli@5.1.4(webpack@5.92.0))(webpack@5.92.0(@swc/core@1.5.28(@swc/helpers@0.5.11))(webpack-cli@5.1.4))': + '@webpack-cli/info@2.0.2(webpack-cli@5.1.4(webpack@5.92.0))(webpack@5.92.0(@swc/core@1.6.3)(esbuild@0.20.2)(webpack-cli@5.1.4(webpack@5.92.0)))': dependencies: - webpack: 5.92.0(@swc/core@1.5.28(@swc/helpers@0.5.11))(webpack-cli@5.1.4) + webpack: 5.92.0(@swc/core@1.6.3)(esbuild@0.20.2)(webpack-cli@5.1.4(webpack@5.92.0)) webpack-cli: 5.1.4(webpack@5.92.0) - '@webpack-cli/serve@2.0.5(webpack-cli@5.1.4(webpack@5.92.0))(webpack@5.92.0(@swc/core@1.5.28(@swc/helpers@0.5.11))(webpack-cli@5.1.4))': + '@webpack-cli/serve@2.0.5(webpack-cli@5.1.4(webpack@5.92.0))(webpack@5.92.0(@swc/core@1.6.3)(esbuild@0.20.2)(webpack-cli@5.1.4(webpack@5.92.0)))': dependencies: - webpack: 5.92.0(@swc/core@1.5.28(@swc/helpers@0.5.11))(webpack-cli@5.1.4) + webpack: 5.92.0(@swc/core@1.6.3)(esbuild@0.20.2)(webpack-cli@5.1.4(webpack@5.92.0)) webpack-cli: 5.1.4(webpack@5.92.0) '@xtuc/ieee754@1.2.0': {} @@ -13918,25 +13800,27 @@ snapshots: mime-types: 2.1.35 negotiator: 0.6.3 - acorn-import-attributes@1.9.5(acorn@8.11.3): + acorn-import-attributes@1.9.5(acorn@8.12.0): dependencies: - acorn: 8.11.3 + acorn: 8.12.0 acorn-jsx@5.3.2(acorn@7.4.1): dependencies: acorn: 7.4.1 - acorn-jsx@5.3.2(acorn@8.11.3): + acorn-jsx@5.3.2(acorn@8.12.0): dependencies: - acorn: 8.11.3 + acorn: 8.12.0 acorn-walk@7.2.0: {} - acorn-walk@8.3.2: {} + acorn-walk@8.3.3: + dependencies: + acorn: 8.12.0 acorn@7.4.1: {} - acorn@8.11.3: {} + acorn@8.12.0: {} address@1.2.2: {} @@ -14097,8 +13981,6 @@ snapshots: array-flatten@3.0.0: {} - array-from-async@3.0.0: {} - array-includes@3.1.8: dependencies: call-bind: 1.0.7 @@ -14205,7 +14087,7 @@ snapshots: autoprefixer@10.4.19(postcss@8.4.38): dependencies: browserslist: 4.23.1 - caniuse-lite: 1.0.30001632 + caniuse-lite: 1.0.30001636 fraction.js: 4.3.7 normalize-range: 0.1.2 picocolors: 1.0.1 @@ -14351,8 +14233,8 @@ snapshots: browserslist@4.23.1: dependencies: - caniuse-lite: 1.0.30001632 - electron-to-chromium: 1.4.799 + caniuse-lite: 1.0.30001636 + electron-to-chromium: 1.4.806 node-releases: 2.0.14 update-browserslist-db: 1.0.16(browserslist@4.23.1) @@ -14372,11 +14254,6 @@ snapshots: base64-js: 1.5.1 ieee754: 1.2.1 - bufferutil@4.0.8: - dependencies: - node-gyp-build: 4.8.1 - optional: true - bytes@3.0.0: {} bytes@3.1.2: {} @@ -14387,7 +14264,7 @@ snapshots: dependencies: '@npmcli/fs': 3.1.1 fs-minipass: 3.0.3 - glob: 10.4.1 + glob: 10.4.2 lru-cache: 10.2.2 minipass: 7.1.2 minipass-collect: 2.0.1 @@ -14435,7 +14312,7 @@ snapshots: camelize@1.0.1: {} - caniuse-lite@1.0.30001632: {} + caniuse-lite@1.0.30001636: {} cardinal@2.1.1: dependencies: @@ -14651,9 +14528,6 @@ snapshots: commander@8.3.0: {} - commander@9.5.0: - optional: true - commondir@1.0.1: {} compress-commons@4.1.2: @@ -14679,8 +14553,6 @@ snapshots: transitivePeerDependencies: - supports-color - computeds@0.0.1: {} - concat-map@0.0.1: {} confbox@0.1.7: {} @@ -14735,7 +14607,7 @@ snapshots: dependencies: toggle-selection: 1.0.6 - copy-webpack-plugin@12.0.2(webpack@5.92.0(@swc/core@1.5.28(@swc/helpers@0.5.11))(webpack-cli@5.1.4)): + copy-webpack-plugin@12.0.2(webpack@5.92.0(@swc/core@1.6.3)(esbuild@0.20.2)(webpack-cli@5.1.4(webpack@5.92.0))): dependencies: fast-glob: 3.3.2 glob-parent: 6.0.2 @@ -14743,7 +14615,7 @@ snapshots: normalize-path: 3.0.0 schema-utils: 4.2.0 serialize-javascript: 6.0.2 - webpack: 5.92.0(@swc/core@1.5.28(@swc/helpers@0.5.11))(webpack-cli@5.1.4) + webpack: 5.92.0(@swc/core@1.6.3)(esbuild@0.20.2)(webpack-cli@5.1.4(webpack@5.92.0)) core-js-compat@3.37.1: dependencies: @@ -14820,7 +14692,7 @@ snapshots: css-color-keywords@1.0.0: {} - css-loader@3.6.0(webpack@5.92.0(@swc/core@1.5.28(@swc/helpers@0.5.11))(esbuild@0.20.2)): + css-loader@3.6.0(webpack@5.92.0(@swc/core@1.6.3)(esbuild@0.20.2)): dependencies: camelcase: 5.3.1 cssesc: 3.0.0 @@ -14835,9 +14707,9 @@ snapshots: postcss-value-parser: 4.2.0 schema-utils: 2.7.1 semver: 6.3.1 - webpack: 5.92.0(@swc/core@1.5.28(@swc/helpers@0.5.11))(esbuild@0.20.2) + webpack: 5.92.0(@swc/core@1.6.3)(esbuild@0.20.2) - css-loader@7.1.2(webpack@5.92.0(@swc/core@1.5.28(@swc/helpers@0.5.11))(webpack-cli@5.1.4)): + css-loader@7.1.2(webpack@5.92.0(@swc/core@1.6.3)(esbuild@0.20.2)(webpack-cli@5.1.4(webpack@5.92.0))): dependencies: icss-utils: 5.1.0(postcss@8.4.38) postcss: 8.4.38 @@ -14848,7 +14720,7 @@ snapshots: postcss-value-parser: 4.2.0 semver: 7.6.2 optionalDependencies: - webpack: 5.92.0(@swc/core@1.5.28(@swc/helpers@0.5.11))(webpack-cli@5.1.4) + webpack: 5.92.0(@swc/core@1.6.3)(esbuild@0.20.2)(webpack-cli@5.1.4(webpack@5.92.0)) css-select@4.3.0: dependencies: @@ -14960,8 +14832,6 @@ snapshots: es-errors: 1.3.0 is-data-view: 1.0.1 - de-indent@1.0.2: {} - debounce@1.2.1: {} debug@2.6.9: @@ -15211,7 +15081,7 @@ snapshots: dependencies: jake: 10.9.1 - electron-to-chromium@1.4.799: {} + electron-to-chromium@1.4.806: {} emoji-regex@10.3.0: {} @@ -15400,6 +15270,32 @@ snapshots: '@esbuild/win32-ia32': 0.20.2 '@esbuild/win32-x64': 0.20.2 + esbuild@0.21.5: + optionalDependencies: + '@esbuild/aix-ppc64': 0.21.5 + '@esbuild/android-arm': 0.21.5 + '@esbuild/android-arm64': 0.21.5 + '@esbuild/android-x64': 0.21.5 + '@esbuild/darwin-arm64': 0.21.5 + '@esbuild/darwin-x64': 0.21.5 + '@esbuild/freebsd-arm64': 0.21.5 + '@esbuild/freebsd-x64': 0.21.5 + '@esbuild/linux-arm': 0.21.5 + '@esbuild/linux-arm64': 0.21.5 + '@esbuild/linux-ia32': 0.21.5 + '@esbuild/linux-loong64': 0.21.5 + '@esbuild/linux-mips64el': 0.21.5 + '@esbuild/linux-ppc64': 0.21.5 + '@esbuild/linux-riscv64': 0.21.5 + '@esbuild/linux-s390x': 0.21.5 + '@esbuild/linux-x64': 0.21.5 + '@esbuild/netbsd-x64': 0.21.5 + '@esbuild/openbsd-x64': 0.21.5 + '@esbuild/sunos-x64': 0.21.5 + '@esbuild/win32-arm64': 0.21.5 + '@esbuild/win32-ia32': 0.21.5 + '@esbuild/win32-x64': 0.21.5 + escalade@3.1.2: {} escape-goat@2.1.1: {} @@ -15418,9 +15314,9 @@ snapshots: optionalDependencies: source-map: 0.6.1 - eslint-config-prettier@9.1.0(eslint@9.4.0): + eslint-config-prettier@9.1.0(eslint@9.5.0): dependencies: - eslint: 9.4.0 + eslint: 9.5.0 eslint-import-resolver-node@0.3.9: dependencies: @@ -15430,13 +15326,13 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.13.0(eslint@9.4.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@9.4.0): + eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.13.1(eslint@9.5.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@9.5.0): dependencies: debug: 4.3.5 enhanced-resolve: 5.17.0 - eslint: 9.4.0 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.13.0(eslint@9.4.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.13.0(eslint@9.4.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@9.4.0))(eslint@9.4.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.13.0(eslint@9.4.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@9.4.0) + eslint: 9.5.0 + eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.13.1(eslint@9.5.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.13.1(eslint@9.5.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@9.5.0))(eslint@9.5.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.13.1(eslint@9.5.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@9.5.0) fast-glob: 3.3.2 get-tsconfig: 4.7.5 is-core-module: 2.13.1 @@ -15447,18 +15343,18 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-module-utils@2.8.1(@typescript-eslint/parser@7.13.0(eslint@9.4.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.13.0(eslint@9.4.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@9.4.0))(eslint@9.4.0): + eslint-module-utils@2.8.1(@typescript-eslint/parser@7.13.1(eslint@9.5.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.13.1(eslint@9.5.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@9.5.0))(eslint@9.5.0): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 7.13.0(eslint@9.4.0)(typescript@5.4.5) - eslint: 9.4.0 + '@typescript-eslint/parser': 7.13.1(eslint@9.5.0)(typescript@5.4.5) + eslint: 9.5.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.13.0(eslint@9.4.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@9.4.0) + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.13.1(eslint@9.5.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@9.5.0) transitivePeerDependencies: - supports-color - eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.13.0(eslint@9.4.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@9.4.0): + eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.13.1(eslint@9.5.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@9.5.0): dependencies: array-includes: 3.1.8 array.prototype.findlastindex: 1.2.5 @@ -15466,9 +15362,9 @@ snapshots: array.prototype.flatmap: 1.3.2 debug: 3.2.7 doctrine: 2.1.0 - eslint: 9.4.0 + eslint: 9.5.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.13.0(eslint@9.4.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.13.0(eslint@9.4.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@9.4.0))(eslint@9.4.0) + eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.13.1(eslint@9.5.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.13.1(eslint@9.5.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@9.5.0))(eslint@9.5.0) hasown: 2.0.2 is-core-module: 2.13.1 is-glob: 4.0.3 @@ -15479,27 +15375,27 @@ snapshots: semver: 6.3.1 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 7.13.0(eslint@9.4.0)(typescript@5.4.5) + '@typescript-eslint/parser': 7.13.1(eslint@9.5.0)(typescript@5.4.5) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - eslint-plugin-prettier@5.1.3(@types/eslint@8.56.10)(eslint-config-prettier@9.1.0(eslint@9.4.0))(eslint@9.4.0)(prettier@3.3.2): + eslint-plugin-prettier@5.1.3(@types/eslint@8.56.10)(eslint-config-prettier@9.1.0(eslint@9.5.0))(eslint@9.5.0)(prettier@3.3.2): dependencies: - eslint: 9.4.0 + eslint: 9.5.0 prettier: 3.3.2 prettier-linter-helpers: 1.0.0 synckit: 0.8.8 optionalDependencies: '@types/eslint': 8.56.10 - eslint-config-prettier: 9.1.0(eslint@9.4.0) + eslint-config-prettier: 9.1.0(eslint@9.5.0) - eslint-plugin-react-hooks@4.6.2(eslint@9.4.0): + eslint-plugin-react-hooks@4.6.2(eslint@9.5.0): dependencies: - eslint: 9.4.0 + eslint: 9.5.0 - eslint-plugin-react@7.34.1(eslint@9.4.0): + eslint-plugin-react@7.34.1(eslint@9.5.0): dependencies: array-includes: 3.1.8 array.prototype.findlast: 1.2.5 @@ -15508,7 +15404,7 @@ snapshots: array.prototype.tosorted: 1.1.4 doctrine: 2.1.0 es-iterator-helpers: 1.0.19 - eslint: 9.4.0 + eslint: 9.5.0 estraverse: 5.3.0 jsx-ast-utils: 3.3.5 minimatch: 3.1.2 @@ -15521,34 +15417,34 @@ snapshots: semver: 6.3.1 string.prototype.matchall: 4.0.11 - eslint-plugin-storybook@0.8.0(eslint@9.4.0)(typescript@5.4.5): + eslint-plugin-storybook@0.8.0(eslint@9.5.0)(typescript@5.4.5): dependencies: '@storybook/csf': 0.0.1 - '@typescript-eslint/utils': 5.62.0(eslint@9.4.0)(typescript@5.4.5) - eslint: 9.4.0 + '@typescript-eslint/utils': 5.62.0(eslint@9.5.0)(typescript@5.4.5) + eslint: 9.5.0 requireindex: 1.2.0 ts-dedent: 2.2.0 transitivePeerDependencies: - supports-color - typescript - eslint-plugin-tailwindcss@3.17.3(tailwindcss@3.4.4(ts-node@10.9.2(@swc/core@1.5.28(@swc/helpers@0.5.11))(@types/node@20.14.2)(typescript@5.4.5))): + eslint-plugin-tailwindcss@3.17.3(tailwindcss@3.4.4(ts-node@10.9.2(@swc/core@1.6.3)(@types/node@20.14.5)(typescript@5.4.5))): dependencies: fast-glob: 3.3.2 postcss: 8.4.38 - tailwindcss: 3.4.4(ts-node@10.9.2(@swc/core@1.5.28(@swc/helpers@0.5.11))(@types/node@20.14.2)(typescript@5.4.5)) + tailwindcss: 3.4.4(ts-node@10.9.2(@swc/core@1.6.3)(@types/node@20.14.5)(typescript@5.4.5)) - eslint-plugin-turbo@1.13.4(eslint@9.4.0): + eslint-plugin-turbo@1.13.4(eslint@9.5.0): dependencies: dotenv: 16.0.3 - eslint: 9.4.0 + eslint: 9.5.0 - eslint-plugin-vitest@0.5.4(eslint@9.4.0)(typescript@5.4.5)(vitest@1.6.0(@types/node@20.14.2)(@vitest/browser@1.6.0(playwright@1.44.1)(vitest@1.6.0))(jsdom@24.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(terser@5.31.1)): + eslint-plugin-vitest@0.5.4(eslint@9.5.0)(typescript@5.4.5)(vitest@1.6.0(@types/node@20.14.5)(@vitest/browser@1.6.0(playwright@1.44.1)(vitest@1.6.0))(jsdom@24.1.0)(terser@5.31.1)): dependencies: - '@typescript-eslint/utils': 7.13.0(eslint@9.4.0)(typescript@5.4.5) - eslint: 9.4.0 + '@typescript-eslint/utils': 7.13.1(eslint@9.5.0)(typescript@5.4.5) + eslint: 9.5.0 optionalDependencies: - vitest: 1.6.0(@types/node@20.14.2)(@vitest/browser@1.6.0(playwright@1.44.1)(vitest@1.6.0))(jsdom@24.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(terser@5.31.1) + vitest: 1.6.0(@types/node@20.14.5)(@vitest/browser@1.6.0(playwright@1.44.1)(vitest@1.6.0))(jsdom@24.1.0)(terser@5.31.1) transitivePeerDependencies: - supports-color - typescript @@ -15567,13 +15463,13 @@ snapshots: eslint-visitor-keys@4.0.0: {} - eslint@9.4.0: + eslint@9.5.0: dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@9.4.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@9.5.0) '@eslint-community/regexpp': 4.10.1 - '@eslint/config-array': 0.15.1 + '@eslint/config-array': 0.16.0 '@eslint/eslintrc': 3.1.0 - '@eslint/js': 9.4.0 + '@eslint/js': 9.5.0 '@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/retry': 0.3.0 '@nodelib/fs.walk': 1.2.8 @@ -15584,7 +15480,7 @@ snapshots: escape-string-regexp: 4.0.0 eslint-scope: 8.0.1 eslint-visitor-keys: 4.0.0 - espree: 10.0.1 + espree: 10.1.0 esquery: 1.5.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 @@ -15606,10 +15502,10 @@ snapshots: transitivePeerDependencies: - supports-color - espree@10.0.1: + espree@10.1.0: dependencies: - acorn: 8.11.3 - acorn-jsx: 5.3.2(acorn@8.11.3) + acorn: 8.12.0 + acorn-jsx: 5.3.2(acorn@8.12.0) eslint-visitor-keys: 4.0.0 esprima@4.0.1: {} @@ -15681,7 +15577,7 @@ snapshots: content-type: 1.0.5 deep-freeze: 0.0.1 events-listener: 1.1.0 - glob: 10.4.1 + glob: 10.4.2 json-ptr: 3.1.1 json-schema-traverse: 1.0.0 lodash: 4.17.21 @@ -15742,8 +15638,6 @@ snapshots: iconv-lite: 0.4.24 tmp: 0.0.33 - fake-indexeddb@6.0.0: {} - fast-check@3.17.2: dependencies: pure-rand: 6.1.0 @@ -15863,7 +15757,7 @@ snapshots: micromatch: 4.0.7 pkg-dir: 4.2.0 - firebase-tools@13.11.2(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@6.0.4): + firebase-tools@13.11.2(encoding@0.1.13): dependencies: '@google-cloud/cloud-sql-connector': 1.3.1(encoding@0.1.13) '@google-cloud/pubsub': 4.5.0(encoding@0.1.13) @@ -15929,7 +15823,7 @@ snapshots: uuid: 8.3.2 winston: 3.13.0 winston-transport: 4.7.0 - ws: 7.5.9(bufferutil@4.0.8)(utf-8-validate@6.0.4) + ws: 7.5.10 yaml: 2.4.5 transitivePeerDependencies: - bufferutil @@ -15947,7 +15841,7 @@ snapshots: flatted@3.3.1: {} - flow-parser@0.237.2: {} + flow-parser@0.238.0: {} fn.name@1.1.0: {} @@ -15955,7 +15849,7 @@ snapshots: dependencies: is-callable: 1.2.7 - foreground-child@3.2.0: + foreground-child@3.2.1: dependencies: cross-spawn: 7.0.3 signal-exit: 4.1.0 @@ -16164,12 +16058,13 @@ snapshots: glob-to-regexp@0.4.1: {} - glob@10.4.1: + glob@10.4.2: dependencies: - foreground-child: 3.2.0 + foreground-child: 3.2.1 jackspeak: 3.4.0 minimatch: 9.0.4 minipass: 7.1.2 + package-json-from-dist: 1.0.0 path-scurry: 1.11.1 glob@7.2.3: @@ -16383,7 +16278,7 @@ snapshots: html-tags@3.3.1: {} - html-webpack-plugin@5.6.0(webpack@5.92.0(@swc/core@1.5.28(@swc/helpers@0.5.11))(webpack-cli@5.1.4)): + html-webpack-plugin@5.6.0(webpack@5.92.0(@swc/core@1.6.3)(esbuild@0.20.2)(webpack-cli@5.1.4(webpack@5.92.0))): dependencies: '@types/html-minifier-terser': 6.1.0 html-minifier-terser: 6.1.0 @@ -16391,7 +16286,7 @@ snapshots: pretty-error: 4.0.0 tapable: 2.2.1 optionalDependencies: - webpack: 5.92.0(@swc/core@1.5.28(@swc/helpers@0.5.11))(webpack-cli@5.1.4) + webpack: 5.92.0(@swc/core@1.6.3)(esbuild@0.20.2)(webpack-cli@5.1.4(webpack@5.92.0)) htmlparser2@6.1.0: dependencies: @@ -16479,8 +16374,6 @@ snapshots: import-lazy@2.1.0: {} - import-lazy@4.0.0: {} - import-local@3.1.0: dependencies: pkg-dir: 4.2.0 @@ -16811,7 +16704,7 @@ snapshots: jest-worker@27.5.1: dependencies: - '@types/node': 20.14.2 + '@types/node': 20.14.5 merge-stream: 2.0.0 supports-color: 8.1.1 @@ -16854,7 +16747,7 @@ snapshots: '@babel/register': 7.24.6(@babel/core@7.24.7) babel-core: 7.0.0-bridge.0(@babel/core@7.24.7) chalk: 4.1.2 - flow-parser: 0.237.2 + flow-parser: 0.238.0 graceful-fs: 4.2.11 micromatch: 4.0.7 neo-async: 2.6.2 @@ -16867,7 +16760,7 @@ snapshots: transitivePeerDependencies: - supports-color - jsdom@24.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.4): + jsdom@24.1.0: dependencies: cssstyle: 4.0.1 data-urls: 5.0.0 @@ -16888,7 +16781,7 @@ snapshots: whatwg-encoding: 3.1.1 whatwg-mimetype: 4.0.0 whatwg-url: 14.0.0 - ws: 8.17.0(bufferutil@4.0.8)(utf-8-validate@6.0.4) + ws: 8.17.1 xml-name-validator: 5.0.0 transitivePeerDependencies: - bufferutil @@ -16989,8 +16882,6 @@ snapshots: klona@2.0.6: {} - kolorist@1.8.0: {} - kuler@2.0.0: {} lazy-universal-dotenv@4.0.0: @@ -17079,8 +16970,6 @@ snapshots: lodash.isboolean@3.0.3: {} - lodash.isequal@4.5.0: {} - lodash.isinteger@4.0.4: {} lodash.isnumber@3.0.3: {} @@ -17283,10 +17172,6 @@ snapshots: min-indent@1.0.1: {} - minimatch@3.0.8: - dependencies: - brace-expansion: 1.1.11 - minimatch@3.1.2: dependencies: brace-expansion: 1.1.11 @@ -17365,7 +17250,7 @@ snapshots: mlly@1.7.1: dependencies: - acorn: 8.11.3 + acorn: 8.12.0 pathe: 1.1.2 pkg-types: 1.1.1 ufo: 1.5.3 @@ -17390,8 +17275,6 @@ snapshots: ms@2.1.3: {} - muggle-string@0.3.1: {} - mute-stream@0.0.8: {} mz@2.7.0: @@ -17455,14 +17338,11 @@ snapshots: fetch-blob: 3.2.0 formdata-polyfill: 4.0.10 - node-gyp-build@4.8.1: - optional: true - node-gyp@10.1.0: dependencies: env-paths: 2.2.1 exponential-backoff: 3.1.1 - glob: 10.4.1 + glob: 10.4.2 graceful-fs: 4.2.11 make-fetch-happen: 13.0.1 nopt: 7.2.1 @@ -17510,7 +17390,7 @@ snapshots: dependencies: hosted-git-info: 7.0.2 proc-log: 4.2.0 - semver: 7.6.2 + semver: 7.6.0 validate-npm-package-name: 5.0.1 npm-run-path@4.0.1: @@ -17745,6 +17625,8 @@ snapshots: degenerator: 5.0.1 netmask: 2.0.2 + package-json-from-dist@1.0.0: {} + pako@0.2.9: {} param-case@2.1.1: @@ -17783,8 +17665,6 @@ snapshots: no-case: 3.0.4 tslib: 2.6.3 - path-browserify@1.0.1: {} - path-case@2.1.1: dependencies: no-case: 2.3.2 @@ -17927,15 +17807,15 @@ snapshots: camelcase-css: 2.0.1 postcss: 8.4.38 - postcss-load-config@4.0.2(postcss@8.4.38)(ts-node@10.9.2(@swc/core@1.5.28(@swc/helpers@0.5.11))(@types/node@20.14.2)(typescript@5.4.5)): + postcss-load-config@4.0.2(postcss@8.4.38)(ts-node@10.9.2(@swc/core@1.6.3)(@types/node@20.14.5)(typescript@5.4.5)): dependencies: lilconfig: 3.1.2 yaml: 2.4.5 optionalDependencies: postcss: 8.4.38 - ts-node: 10.9.2(@swc/core@1.5.28(@swc/helpers@0.5.11))(@types/node@20.14.2)(typescript@5.4.5) + ts-node: 10.9.2(@swc/core@1.6.3)(@types/node@20.14.5)(typescript@5.4.5) - postcss-loader@4.3.0(postcss@7.0.39)(webpack@5.92.0(@swc/core@1.5.28(@swc/helpers@0.5.11))(esbuild@0.20.2)): + postcss-loader@4.3.0(postcss@7.0.39)(webpack@5.92.0(@swc/core@1.6.3)(esbuild@0.20.2)): dependencies: cosmiconfig: 7.1.0 klona: 2.0.6 @@ -17943,16 +17823,16 @@ snapshots: postcss: 7.0.39 schema-utils: 3.3.0 semver: 7.6.2 - webpack: 5.92.0(@swc/core@1.5.28(@swc/helpers@0.5.11))(esbuild@0.20.2) + webpack: 5.92.0(@swc/core@1.6.3)(esbuild@0.20.2) - postcss-loader@8.1.1(postcss@8.4.38)(typescript@5.4.5)(webpack@5.92.0(@swc/core@1.5.28(@swc/helpers@0.5.11))(webpack-cli@5.1.4)): + postcss-loader@8.1.1(postcss@8.4.38)(typescript@5.4.5)(webpack@5.92.0(@swc/core@1.6.3)(esbuild@0.20.2)(webpack-cli@5.1.4(webpack@5.92.0))): dependencies: cosmiconfig: 9.0.0(typescript@5.4.5) jiti: 1.21.6 postcss: 8.4.38 semver: 7.6.2 optionalDependencies: - webpack: 5.92.0(@swc/core@1.5.28(@swc/helpers@0.5.11))(webpack-cli@5.1.4) + webpack: 5.92.0(@swc/core@1.6.3)(esbuild@0.20.2)(webpack-cli@5.1.4(webpack@5.92.0)) transitivePeerDependencies: - typescript @@ -18122,7 +18002,7 @@ snapshots: '@protobufjs/path': 1.1.2 '@protobufjs/pool': 1.1.0 '@protobufjs/utf8': 1.1.0 - '@types/node': 20.14.2 + '@types/node': 20.14.5 long: 5.2.3 proxy-addr@2.0.7: @@ -18218,7 +18098,7 @@ snapshots: minimist: 1.2.8 strip-json-comments: 2.0.1 - re2@1.21.2: + re2@1.21.3: dependencies: install-artifact-from-github: 1.3.5 nan: 2.20.0 @@ -18280,8 +18160,6 @@ snapshots: react-is: 18.3.1 styled-components: 6.1.11(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react-refresh@0.14.2: {} - react-remove-scroll-bar@2.3.6(@types/react@18.3.3)(react@18.3.1): dependencies: react: 18.3.1 @@ -18542,11 +18420,6 @@ snapshots: resolve-pkg-maps@1.0.0: {} - resolve@1.19.0: - dependencies: - is-core-module: 2.13.1 - path-parse: 1.0.7 - resolve@1.22.8: dependencies: is-core-module: 2.13.1 @@ -18705,10 +18578,6 @@ snapshots: semver@6.3.1: {} - semver@7.5.4: - dependencies: - lru-cache: 6.0.0 - semver@7.6.0: dependencies: lru-cache: 6.0.0 @@ -18924,9 +18793,9 @@ snapshots: store2@2.14.3: {} - storybook@8.1.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(utf-8-validate@6.0.4): + storybook@8.1.10(@babel/preset-env@7.24.7(@babel/core@7.24.7))(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: - '@storybook/cli': 8.1.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(utf-8-validate@6.0.4) + '@storybook/cli': 8.1.10(@babel/preset-env@7.24.7(@babel/core@7.24.7))(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) transitivePeerDependencies: - '@babel/preset-env' - bufferutil @@ -18952,8 +18821,6 @@ snapshots: dependencies: mixme: 0.5.10 - string-argv@0.3.2: {} - string-width@4.2.3: dependencies: emoji-regex: 8.0.0 @@ -19048,15 +18915,15 @@ snapshots: stubs@3.0.0: {} - style-loader@1.3.0(webpack@5.92.0(@swc/core@1.5.28(@swc/helpers@0.5.11))(esbuild@0.20.2)): + style-loader@1.3.0(webpack@5.92.0(@swc/core@1.6.3)(esbuild@0.20.2)): dependencies: loader-utils: 2.0.4 schema-utils: 2.7.1 - webpack: 5.92.0(@swc/core@1.5.28(@swc/helpers@0.5.11))(esbuild@0.20.2) + webpack: 5.92.0(@swc/core@1.6.3)(esbuild@0.20.2) - style-loader@4.0.0(webpack@5.92.0(@swc/core@1.5.28(@swc/helpers@0.5.11))(webpack-cli@5.1.4)): + style-loader@4.0.0(webpack@5.92.0(@swc/core@1.6.3)(esbuild@0.20.2)(webpack-cli@5.1.4(webpack@5.92.0))): dependencies: - webpack: 5.92.0(@swc/core@1.5.28(@swc/helpers@0.5.11))(webpack-cli@5.1.4) + webpack: 5.92.0(@swc/core@1.6.3)(esbuild@0.20.2)(webpack-cli@5.1.4(webpack@5.92.0)) styled-components@6.1.11(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: @@ -19080,7 +18947,7 @@ snapshots: dependencies: '@jridgewell/gen-mapping': 0.3.5 commander: 4.1.1 - glob: 10.4.1 + glob: 10.4.2 lines-and-columns: 1.2.4 mz: 2.7.0 pirates: 4.0.6 @@ -19107,7 +18974,7 @@ snapshots: router: 1.3.8 update-notifier-cjs: 5.1.6(encoding@0.1.13) optionalDependencies: - re2: 1.21.2 + re2: 1.21.3 transitivePeerDependencies: - encoding - supports-color @@ -19169,11 +19036,11 @@ snapshots: dependencies: '@babel/runtime': 7.24.7 - tailwindcss-animate@1.0.7(tailwindcss@3.4.4(ts-node@10.9.2(@swc/core@1.5.28(@swc/helpers@0.5.11))(@types/node@20.14.2)(typescript@5.4.5))): + tailwindcss-animate@1.0.7(tailwindcss@3.4.4(ts-node@10.9.2(@swc/core@1.6.3)(@types/node@20.14.5)(typescript@5.4.5))): dependencies: - tailwindcss: 3.4.4(ts-node@10.9.2(@swc/core@1.5.28(@swc/helpers@0.5.11))(@types/node@20.14.2)(typescript@5.4.5)) + tailwindcss: 3.4.4(ts-node@10.9.2(@swc/core@1.6.3)(@types/node@20.14.5)(typescript@5.4.5)) - tailwindcss@3.4.4(ts-node@10.9.2(@swc/core@1.5.28(@swc/helpers@0.5.11))(@types/node@20.14.2)(typescript@5.4.5)): + tailwindcss@3.4.4(ts-node@10.9.2(@swc/core@1.6.3)(@types/node@20.14.5)(typescript@5.4.5)): dependencies: '@alloc/quick-lru': 5.2.0 arg: 5.0.2 @@ -19192,7 +19059,7 @@ snapshots: postcss: 8.4.38 postcss-import: 15.1.0(postcss@8.4.38) postcss-js: 4.0.1(postcss@8.4.38) - postcss-load-config: 4.0.2(postcss@8.4.38)(ts-node@10.9.2(@swc/core@1.5.28(@swc/helpers@0.5.11))(@types/node@20.14.2)(typescript@5.4.5)) + postcss-load-config: 4.0.2(postcss@8.4.38)(ts-node@10.9.2(@swc/core@1.6.3)(@types/node@20.14.5)(typescript@5.4.5)) postcss-nested: 6.0.1(postcss@8.4.38) postcss-selector-parser: 6.1.0 resolve: 1.22.8 @@ -19273,33 +19140,34 @@ snapshots: term-size@2.2.1: {} - terser-webpack-plugin@5.3.10(@swc/core@1.5.28(@swc/helpers@0.5.11))(esbuild@0.20.2)(webpack@5.92.0(@swc/core@1.5.28(@swc/helpers@0.5.11))(esbuild@0.20.2)): + terser-webpack-plugin@5.3.10(@swc/core@1.6.3)(esbuild@0.20.2)(webpack@5.92.0(@swc/core@1.6.3)(esbuild@0.20.2)(webpack-cli@5.1.4(webpack@5.92.0))): dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 schema-utils: 3.3.0 serialize-javascript: 6.0.2 terser: 5.31.1 - webpack: 5.92.0(@swc/core@1.5.28(@swc/helpers@0.5.11))(esbuild@0.20.2) + webpack: 5.92.0(@swc/core@1.6.3)(esbuild@0.20.2)(webpack-cli@5.1.4(webpack@5.92.0)) optionalDependencies: - '@swc/core': 1.5.28(@swc/helpers@0.5.11) + '@swc/core': 1.6.3 esbuild: 0.20.2 - terser-webpack-plugin@5.3.10(@swc/core@1.5.28(@swc/helpers@0.5.11))(webpack@5.92.0(@swc/core@1.5.28(@swc/helpers@0.5.11))(webpack-cli@5.1.4)): + terser-webpack-plugin@5.3.10(@swc/core@1.6.3)(esbuild@0.20.2)(webpack@5.92.0(@swc/core@1.6.3)(esbuild@0.20.2)): dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 schema-utils: 3.3.0 serialize-javascript: 6.0.2 terser: 5.31.1 - webpack: 5.92.0(@swc/core@1.5.28(@swc/helpers@0.5.11))(webpack-cli@5.1.4) + webpack: 5.92.0(@swc/core@1.6.3)(esbuild@0.20.2) optionalDependencies: - '@swc/core': 1.5.28(@swc/helpers@0.5.11) + '@swc/core': 1.6.3 + esbuild: 0.20.2 terser@5.31.1: dependencies: '@jridgewell/source-map': 0.3.6 - acorn: 8.11.3 + acorn: 8.12.0 commander: 2.20.3 source-map-support: 0.5.21 @@ -19393,7 +19261,7 @@ snapshots: ts-interface-checker@0.1.13: {} - ts-loader@9.5.1(typescript@5.4.5)(webpack@5.92.0(@swc/core@1.5.28(@swc/helpers@0.5.11))(webpack-cli@5.1.4)): + ts-loader@9.5.1(typescript@5.4.5)(webpack@5.92.0(@swc/core@1.6.3)(esbuild@0.20.2)(webpack-cli@5.1.4(webpack@5.92.0))): dependencies: chalk: 4.1.2 enhanced-resolve: 5.17.0 @@ -19401,18 +19269,18 @@ snapshots: semver: 7.6.2 source-map: 0.7.4 typescript: 5.4.5 - webpack: 5.92.0(@swc/core@1.5.28(@swc/helpers@0.5.11))(webpack-cli@5.1.4) + webpack: 5.92.0(@swc/core@1.6.3)(esbuild@0.20.2)(webpack-cli@5.1.4(webpack@5.92.0)) - ts-node@10.9.2(@swc/core@1.5.28(@swc/helpers@0.5.11))(@types/node@20.14.2)(typescript@5.4.5): + ts-node@10.9.2(@swc/core@1.6.3)(@types/node@20.14.5)(typescript@5.4.5): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.11 '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 20.14.2 - acorn: 8.11.3 - acorn-walk: 8.3.2 + '@types/node': 20.14.5 + acorn: 8.12.0 + acorn-walk: 8.3.3 arg: 4.1.3 create-require: 1.1.1 diff: 4.0.2 @@ -19421,7 +19289,7 @@ snapshots: v8-compile-cache-lib: 3.0.1 yn: 3.1.1 optionalDependencies: - '@swc/core': 1.5.28(@swc/helpers@0.5.11) + '@swc/core': 1.6.3 ts-toolbelt@9.6.0: {} @@ -19549,19 +19417,17 @@ snapshots: dependencies: is-typedarray: 1.0.0 - typescript-eslint@7.13.0(eslint@9.4.0)(typescript@5.4.5): + typescript-eslint@7.13.1(eslint@9.5.0)(typescript@5.4.5): dependencies: - '@typescript-eslint/eslint-plugin': 7.13.0(@typescript-eslint/parser@7.13.0(eslint@9.4.0)(typescript@5.4.5))(eslint@9.4.0)(typescript@5.4.5) - '@typescript-eslint/parser': 7.13.0(eslint@9.4.0)(typescript@5.4.5) - '@typescript-eslint/utils': 7.13.0(eslint@9.4.0)(typescript@5.4.5) - eslint: 9.4.0 + '@typescript-eslint/eslint-plugin': 7.13.1(@typescript-eslint/parser@7.13.1(eslint@9.5.0)(typescript@5.4.5))(eslint@9.5.0)(typescript@5.4.5) + '@typescript-eslint/parser': 7.13.1(eslint@9.5.0)(typescript@5.4.5) + '@typescript-eslint/utils': 7.13.1(eslint@9.5.0)(typescript@5.4.5) + eslint: 9.5.0 optionalDependencies: typescript: 5.4.5 transitivePeerDependencies: - supports-color - typescript@5.4.2: {} - typescript@5.4.5: {} ufo@1.5.3: {} @@ -19641,7 +19507,7 @@ snapshots: unplugin@1.10.1: dependencies: - acorn: 8.11.3 + acorn: 8.12.0 chokidar: 3.6.0 webpack-sources: 3.2.3 webpack-virtual-modules: 0.6.2 @@ -19718,15 +19584,14 @@ snapshots: dependencies: react: 18.3.1 - usehooks-ts@3.1.0(react@18.3.1): + use-sync-external-store@1.2.2(react@18.3.1): dependencies: - lodash.debounce: 4.0.8 react: 18.3.1 - utf-8-validate@6.0.4: + usehooks-ts@3.1.0(react@18.3.1): dependencies: - node-gyp-build: 4.8.1 - optional: true + lodash.debounce: 4.0.8 + react: 18.3.1 util-deprecate@1.0.2: {} @@ -19757,17 +19622,15 @@ snapshots: validate-npm-package-name@5.0.1: {} - validator@13.12.0: {} - vary@1.1.2: {} - vite-node@1.6.0(@types/node@20.14.2)(terser@5.31.1): + vite-node@1.6.0(@types/node@20.14.5)(terser@5.31.1): dependencies: cac: 6.7.14 debug: 4.3.5 pathe: 1.1.2 picocolors: 1.0.1 - vite: 5.2.13(@types/node@20.14.2)(terser@5.31.1) + vite: 5.3.1(@types/node@20.14.5)(terser@5.31.1) transitivePeerDependencies: - '@types/node' - less @@ -19778,59 +19641,38 @@ snapshots: - supports-color - terser - vite-plugin-dts@3.9.1(@types/node@20.14.2)(rollup@4.18.0)(typescript@5.4.5)(vite@5.2.13(@types/node@20.14.2)(terser@5.31.1)): - dependencies: - '@microsoft/api-extractor': 7.43.0(@types/node@20.14.2) - '@rollup/pluginutils': 5.1.0(rollup@4.18.0) - '@vue/language-core': 1.8.27(typescript@5.4.5) - debug: 4.3.5 - kolorist: 1.8.0 - magic-string: 0.30.10 - typescript: 5.4.5 - vue-tsc: 1.8.27(typescript@5.4.5) - optionalDependencies: - vite: 5.2.13(@types/node@20.14.2)(terser@5.31.1) - transitivePeerDependencies: - - '@types/node' - - rollup - - supports-color - - vite-plugin-externalize-deps@0.8.0(vite@5.2.13(@types/node@20.14.2)(terser@5.31.1)): - dependencies: - vite: 5.2.13(@types/node@20.14.2)(terser@5.31.1) - - vite-plugin-top-level-await@1.4.1(@swc/helpers@0.5.11)(rollup@4.18.0)(vite@5.2.13(@types/node@20.14.2)(terser@5.31.1)): + vite-plugin-top-level-await@1.4.1(rollup@4.18.0)(vite@5.3.1(@types/node@20.14.5)(terser@5.31.1)): dependencies: '@rollup/plugin-virtual': 3.0.2(rollup@4.18.0) - '@swc/core': 1.5.28(@swc/helpers@0.5.11) + '@swc/core': 1.6.3 uuid: 9.0.1 - vite: 5.2.13(@types/node@20.14.2)(terser@5.31.1) + vite: 5.3.1(@types/node@20.14.5)(terser@5.31.1) transitivePeerDependencies: - '@swc/helpers' - rollup - vite-plugin-wasm@3.3.0(vite@5.2.13(@types/node@20.14.2)(terser@5.31.1)): + vite-plugin-wasm@3.3.0(vite@5.3.1(@types/node@20.14.5)(terser@5.31.1)): dependencies: - vite: 5.2.13(@types/node@20.14.2)(terser@5.31.1) + vite: 5.3.1(@types/node@20.14.5)(terser@5.31.1) - vite@5.2.13(@types/node@20.14.2)(terser@5.31.1): + vite@5.3.1(@types/node@20.14.5)(terser@5.31.1): dependencies: - esbuild: 0.20.2 + esbuild: 0.21.5 postcss: 8.4.38 rollup: 4.18.0 optionalDependencies: - '@types/node': 20.14.2 + '@types/node': 20.14.5 fsevents: 2.3.3 terser: 5.31.1 - vitest@1.6.0(@types/node@20.14.2)(@vitest/browser@1.6.0(playwright@1.44.1)(vitest@1.6.0))(jsdom@24.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(terser@5.31.1): + vitest@1.6.0(@types/node@20.14.5)(@vitest/browser@1.6.0(playwright@1.44.1)(vitest@1.6.0))(jsdom@24.1.0)(terser@5.31.1): dependencies: '@vitest/expect': 1.6.0 '@vitest/runner': 1.6.0 '@vitest/snapshot': 1.6.0 '@vitest/spy': 1.6.0 '@vitest/utils': 1.6.0 - acorn-walk: 8.3.2 + acorn-walk: 8.3.3 chai: 4.4.1 debug: 4.3.5 execa: 8.0.1 @@ -19842,13 +19684,13 @@ snapshots: strip-literal: 2.1.0 tinybench: 2.8.0 tinypool: 0.8.4 - vite: 5.2.13(@types/node@20.14.2)(terser@5.31.1) - vite-node: 1.6.0(@types/node@20.14.2)(terser@5.31.1) + vite: 5.3.1(@types/node@20.14.5)(terser@5.31.1) + vite-node: 1.6.0(@types/node@20.14.5)(terser@5.31.1) why-is-node-running: 2.2.2 optionalDependencies: - '@types/node': 20.14.2 + '@types/node': 20.14.5 '@vitest/browser': 1.6.0(playwright@1.44.1)(vitest@1.6.0) - jsdom: 24.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.4) + jsdom: 24.1.0 transitivePeerDependencies: - less - lightningcss @@ -19858,18 +19700,6 @@ snapshots: - supports-color - terser - vue-template-compiler@2.7.16: - dependencies: - de-indent: 1.0.2 - he: 1.2.0 - - vue-tsc@1.8.27(typescript@5.4.5): - dependencies: - '@volar/typescript': 1.11.1 - '@vue/language-core': 1.8.27(typescript@5.4.5) - semver: 7.6.2 - typescript: 5.4.5 - w3c-xmlserializer@5.0.0: dependencies: xml-name-validator: 5.0.0 @@ -19892,9 +19722,9 @@ snapshots: webpack-cli@5.1.4(webpack@5.92.0): dependencies: '@discoveryjs/json-ext': 0.5.7 - '@webpack-cli/configtest': 2.1.1(webpack-cli@5.1.4(webpack@5.92.0))(webpack@5.92.0(@swc/core@1.5.28(@swc/helpers@0.5.11))(webpack-cli@5.1.4)) - '@webpack-cli/info': 2.0.2(webpack-cli@5.1.4(webpack@5.92.0))(webpack@5.92.0(@swc/core@1.5.28(@swc/helpers@0.5.11))(webpack-cli@5.1.4)) - '@webpack-cli/serve': 2.0.5(webpack-cli@5.1.4(webpack@5.92.0))(webpack@5.92.0(@swc/core@1.5.28(@swc/helpers@0.5.11))(webpack-cli@5.1.4)) + '@webpack-cli/configtest': 2.1.1(webpack-cli@5.1.4(webpack@5.92.0))(webpack@5.92.0(@swc/core@1.6.3)(esbuild@0.20.2)(webpack-cli@5.1.4(webpack@5.92.0))) + '@webpack-cli/info': 2.0.2(webpack-cli@5.1.4(webpack@5.92.0))(webpack@5.92.0(@swc/core@1.6.3)(esbuild@0.20.2)(webpack-cli@5.1.4(webpack@5.92.0))) + '@webpack-cli/serve': 2.0.5(webpack-cli@5.1.4(webpack@5.92.0))(webpack@5.92.0(@swc/core@1.6.3)(esbuild@0.20.2)(webpack-cli@5.1.4(webpack@5.92.0))) colorette: 2.0.20 commander: 10.0.1 cross-spawn: 7.0.3 @@ -19903,7 +19733,7 @@ snapshots: import-local: 3.1.0 interpret: 3.1.1 rechoir: 0.8.0 - webpack: 5.92.0(@swc/core@1.5.28(@swc/helpers@0.5.11))(webpack-cli@5.1.4) + webpack: 5.92.0(@swc/core@1.6.3)(esbuild@0.20.2)(webpack-cli@5.1.4(webpack@5.92.0)) webpack-merge: 5.10.0 webpack-merge@5.10.0: @@ -19916,15 +19746,15 @@ snapshots: webpack-virtual-modules@0.6.2: {} - webpack@5.92.0(@swc/core@1.5.28(@swc/helpers@0.5.11))(esbuild@0.20.2): + webpack@5.92.0(@swc/core@1.6.3)(esbuild@0.20.2): dependencies: '@types/eslint-scope': 3.7.7 '@types/estree': 1.0.5 '@webassemblyjs/ast': 1.12.1 '@webassemblyjs/wasm-edit': 1.12.1 '@webassemblyjs/wasm-parser': 1.12.1 - acorn: 8.11.3 - acorn-import-attributes: 1.9.5(acorn@8.11.3) + acorn: 8.12.0 + acorn-import-attributes: 1.9.5(acorn@8.12.0) browserslist: 4.23.1 chrome-trace-event: 1.0.4 enhanced-resolve: 5.17.0 @@ -19939,7 +19769,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.10(@swc/core@1.5.28(@swc/helpers@0.5.11))(esbuild@0.20.2)(webpack@5.92.0(@swc/core@1.5.28(@swc/helpers@0.5.11))(esbuild@0.20.2)) + terser-webpack-plugin: 5.3.10(@swc/core@1.6.3)(esbuild@0.20.2)(webpack@5.92.0(@swc/core@1.6.3)(esbuild@0.20.2)) watchpack: 2.4.1 webpack-sources: 3.2.3 transitivePeerDependencies: @@ -19947,15 +19777,15 @@ snapshots: - esbuild - uglify-js - webpack@5.92.0(@swc/core@1.5.28(@swc/helpers@0.5.11))(webpack-cli@5.1.4): + webpack@5.92.0(@swc/core@1.6.3)(esbuild@0.20.2)(webpack-cli@5.1.4(webpack@5.92.0)): dependencies: '@types/eslint-scope': 3.7.7 '@types/estree': 1.0.5 '@webassemblyjs/ast': 1.12.1 '@webassemblyjs/wasm-edit': 1.12.1 '@webassemblyjs/wasm-parser': 1.12.1 - acorn: 8.11.3 - acorn-import-attributes: 1.9.5(acorn@8.11.3) + acorn: 8.12.0 + acorn-import-attributes: 1.9.5(acorn@8.12.0) browserslist: 4.23.1 chrome-trace-event: 1.0.4 enhanced-resolve: 5.17.0 @@ -19970,7 +19800,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.10(@swc/core@1.5.28(@swc/helpers@0.5.11))(webpack@5.92.0(@swc/core@1.5.28(@swc/helpers@0.5.11))(webpack-cli@5.1.4)) + terser-webpack-plugin: 5.3.10(@swc/core@1.6.3)(esbuild@0.20.2)(webpack@5.92.0(@swc/core@1.6.3)(esbuild@0.20.2)(webpack-cli@5.1.4(webpack@5.92.0))) watchpack: 2.4.1 webpack-sources: 3.2.3 optionalDependencies: @@ -20128,15 +19958,9 @@ snapshots: signal-exit: 3.0.7 typedarray-to-buffer: 3.1.5 - ws@7.5.9(bufferutil@4.0.8)(utf-8-validate@6.0.4): - optionalDependencies: - bufferutil: 4.0.8 - utf-8-validate: 6.0.4 + ws@7.5.10: {} - ws@8.17.0(bufferutil@4.0.8)(utf-8-validate@6.0.4): - optionalDependencies: - bufferutil: 4.0.8 - utf-8-validate: 6.0.4 + ws@8.17.1: {} xdg-basedir@4.0.0: {} @@ -20197,14 +20021,6 @@ snapshots: yocto-queue@1.0.0: {} - z-schema@5.0.5: - dependencies: - lodash.get: 4.4.2 - lodash.isequal: 4.5.0 - validator: 13.12.0 - optionalDependencies: - commander: 9.5.0 - zip-stream@4.1.1: dependencies: archiver-utils: 3.0.4 From 4a6862edd172d346c441a78917e4a2afb6e1f429 Mon Sep 17 00:00:00 2001 From: turbocrime Date: Tue, 18 Jun 2024 23:42:55 -0700 Subject: [PATCH 2/4] changeset --- .changeset/silly-lemons-fly.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.changeset/silly-lemons-fly.md b/.changeset/silly-lemons-fly.md index 10448984..acdd7c05 100644 --- a/.changeset/silly-lemons-fly.md +++ b/.changeset/silly-lemons-fly.md @@ -1,10 +1,11 @@ --- -'context': major 'prax-marketing-website': major -'tailwind-config': major +'@repo/tailwind-config': major '@repo/eslint-config': major +'@repo/tsconfig': major +'@repo/context': major 'chrome-extension': major -'ui': major +'@repo/ui': major --- use imported packages From 6de1ca0c33bd42e82d9d34b2d5a4f6326dd11a77 Mon Sep 17 00:00:00 2001 From: turbocrime Date: Wed, 19 Jun 2024 08:50:07 -0700 Subject: [PATCH 3/4] workflows --- .github/workflows/compile-wasm.yml | 36 ---------- .github/workflows/extension-upload.yml | 15 ++-- .github/workflows/turbo-ci.yml | 97 +++++--------------------- 3 files changed, 22 insertions(+), 126 deletions(-) delete mode 100644 .github/workflows/compile-wasm.yml diff --git a/.github/workflows/compile-wasm.yml b/.github/workflows/compile-wasm.yml deleted file mode 100644 index 23d7282d..00000000 --- a/.github/workflows/compile-wasm.yml +++ /dev/null @@ -1,36 +0,0 @@ -name: Compile WASM -on: - workflow_call: - workflow_dispatch: - -jobs: - wasm: - runs-on: buildjet-16vcpu-ubuntu-2204 - steps: - - uses: actions/checkout@v4 - - id: compiled - uses: buildjet/cache@v3 - with: - path: .turbo - key: ${{ hashFiles('**/Cargo.lock') }}-${{ hashFiles('pnpm-lock.yaml') }}-${{ github.ref }}-${{ github.sha }}-compiled - restore-keys: ${{ hashFiles('**/Cargo.lock') }} - - uses: pnpm/action-setup@v2 - - uses: buildjet/setup-node@v4 - with: - node-version: '21' - cache: 'pnpm' - - run: pnpm install --frozen-lockfile - - run: pnpm turbo telemetry disable - - uses: dtolnay/rust-toolchain@stable # rust only on buildjet - with: - targets: wasm32-unknown-unknown - - uses: jetli/wasm-pack-action@v0.4.0 # preinstall wasm-pack - with: - version: 'latest' - - run: pnpm turbo compile --cache-dir=.turbo # compile wasm - - name: Verify no unexpected file changes (like cargo.lock change) - run: git diff --exit-code - working-directory: packages/wasm/crate - - run: cargo tree --invert penumbra-wasm --edges features # debug tree - if: failure() - working-directory: packages/wasm/crate diff --git a/.github/workflows/extension-upload.yml b/.github/workflows/extension-upload.yml index 7f8e63b0..e55c7c71 100644 --- a/.github/workflows/extension-upload.yml +++ b/.github/workflows/extension-upload.yml @@ -13,16 +13,14 @@ on: workflow_call: workflow_dispatch: -jobs: - turbo-compile: - name: Compile - uses: ./.github/workflows/compile-wasm.yml +env: + DO_NOT_TRACK: 1 +jobs: publish: environment: ext-publish name: Upload extension dist runs-on: buildjet-16vcpu-ubuntu-2204 - needs: turbo-compile steps: - uses: actions/checkout@v4 @@ -30,15 +28,14 @@ jobs: uses: buildjet/cache@v3 with: path: .turbo - key: ${{ hashFiles('**/Cargo.lock') }}-${{ hashFiles('pnpm-lock.yaml') }}-${{ github.ref }}-${{ github.sha }}-built - restore-keys: ${{ hashFiles('**/Cargo.lock') }}-${{ hashFiles('pnpm-lock.yaml') }}-${{ github.ref }}-${{ github.sha }}-compiled + key: ${{ hashFiles('pnpm-lock.yaml') }}-${{ github.ref }}-${{ github.sha }}-publish + restore-keys: ${{ hashFiles('pnpm-lock.yaml') }}-${{ github.ref }}-${{ github.sha }}-test - uses: pnpm/action-setup@v2 - uses: buildjet/setup-node@v4 with: - node-version: '21' + node-version: '22' cache: 'pnpm' - run: pnpm install --frozen-lockfile - - run: pnpm turbo telemetry disable - run: pnpm turbo build --cache-dir=.turbo # Outputs beta.zip and prod.zip diff --git a/.github/workflows/turbo-ci.yml b/.github/workflows/turbo-ci.yml index e644bb70..a366d833 100644 --- a/.github/workflows/turbo-ci.yml +++ b/.github/workflows/turbo-ci.yml @@ -7,6 +7,9 @@ on: branches: - main +env: + DO_NOT_TRACK: 1 + concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true @@ -15,131 +18,63 @@ concurrency: # the first action is commented, most of those comments apply to all actions # every 'turbo' call is cached and essentially no-op if the inputs match -# tried to make wasm compile conditional, but that turned out to be complex. -# cache should make it decently fast. - # pnpm cached by lock hash -# turbo cached by cargo lock, pnpm lock in that order -# mostly, compiled wasm will restore from turbo cache -# rust cache only used in rust jobs +# turbo cached pnpm lock jobs: - turbo-compile: - name: Compile - uses: ./.github/workflows/compile-wasm.yml - turbo-lint: name: Lint runs-on: buildjet-8vcpu-ubuntu-2204 - needs: turbo-compile steps: - uses: actions/checkout@v4 - id: lint uses: buildjet/cache@v3 with: path: .turbo - key: ${{ hashFiles('**/Cargo.lock') }}-${{ hashFiles('pnpm-lock.yaml') }}-${{ github.ref }}-${{ github.sha }}-lint - restore-keys: ${{ hashFiles('**/Cargo.lock') }}-${{ hashFiles('pnpm-lock.yaml') }}-${{ github.ref }}-${{ github.sha }}-compiled + key: ${{ hashFiles('pnpm-lock.yaml') }}-${{ github.ref }}-${{ github.sha }}-lint + restore-keys: ${{ hashFiles('pnpm-lock.yaml') }} - uses: pnpm/action-setup@v2 - uses: buildjet/setup-node@v4 with: - node-version: '21' - cache: 'pnpm' + node-version: "22" + cache: "pnpm" - run: pnpm install --frozen-lockfile - - run: pnpm turbo telemetry disable - run: pnpm turbo lint --cache-dir=.turbo turbo-build: name: Build runs-on: buildjet-8vcpu-ubuntu-2204 - needs: turbo-compile steps: - uses: actions/checkout@v4 - id: built uses: buildjet/cache@v3 with: path: .turbo - key: ${{ hashFiles('**/Cargo.lock') }}-${{ hashFiles('pnpm-lock.yaml') }}-${{ github.ref }}-${{ github.sha }}-built - restore-keys: ${{ hashFiles('**/Cargo.lock') }}-${{ hashFiles('pnpm-lock.yaml') }}-${{ github.ref }}-${{ github.sha }}-compiled + key: ${{ hashFiles('pnpm-lock.yaml') }}-${{ github.ref }}-${{ github.sha }}-built + restore-keys: ${{ hashFiles('pnpm-lock.yaml') }} - uses: pnpm/action-setup@v2 - uses: buildjet/setup-node@v4 with: - node-version: '21' - cache: 'pnpm' + node-version: "22" + cache: "pnpm" - run: pnpm install --frozen-lockfile - - run: pnpm turbo telemetry disable - run: pnpm turbo build --cache-dir=.turbo turbo-test: name: test runs-on: buildjet-4vcpu-ubuntu-2204 - needs: turbo-compile steps: - uses: actions/checkout@v4 - id: tested uses: buildjet/cache@v3 with: path: .turbo - key: ${{ hashFiles('**/Cargo.lock') }}-${{ hashFiles('pnpm-lock.yaml') }}-${{ github.ref }}-${{ github.sha }}-test - restore-keys: ${{ hashFiles('**/Cargo.lock') }}-${{ hashFiles('pnpm-lock.yaml') }}-${{ github.ref }}-${{ github.sha }}-compiled + key: ${{ hashFiles('pnpm-lock.yaml') }}-${{ github.ref }}-${{ github.sha }}-test + restore-keys: ${{ hashFiles('pnpm-lock.yaml') }} - uses: pnpm/action-setup@v2 - uses: buildjet/setup-node@v4 with: - node-version: '21' - cache: 'pnpm' + node-version: "22" + cache: "pnpm" - run: pnpm install --frozen-lockfile - - run: pnpm turbo telemetry disable - - run: pnpm playwright install --with-deps chromium - run: pnpm turbo test --cache-dir=.turbo - - turbo-lint-rust: - name: lint:rust - runs-on: buildjet-4vcpu-ubuntu-2204 - needs: turbo-compile - steps: - - uses: actions/checkout@v4 - - id: rust-linted - uses: buildjet/cache@v3 - with: - path: .turbo - key: ${{ hashFiles('**/Cargo.lock') }}-${{ hashFiles('pnpm-lock.yaml') }}-${{ github.ref }}-${{ github.sha }}-lint:rust - restore-keys: ${{ hashFiles('**/Cargo.lock') }}-${{ hashFiles('pnpm-lock.yaml') }}-${{ github.ref }}-${{ github.sha }}-compiled - - uses: pnpm/action-setup@v2 - - uses: buildjet/setup-node@v4 - with: - node-version: '21' - cache: 'pnpm' - - run: pnpm install --frozen-lockfile - - uses: dtolnay/rust-toolchain@stable - with: - targets: wasm32-unknown-unknown - - run: pnpm turbo telemetry disable - - run: pnpm turbo lint:rust --cache-dir=.turbo - - turbo-test-rust: - name: test:rust - runs-on: buildjet-16vcpu-ubuntu-2204 - needs: turbo-compile - steps: - - uses: actions/checkout@v4 - - id: tested - uses: buildjet/cache@v3 - with: - path: .turbo - key: ${{ hashFiles('**/Cargo.lock') }}-${{ hashFiles('pnpm-lock.yaml') }}-${{ github.ref }}-${{ github.sha }}-test:rust - restore-keys: ${{ hashFiles('**/Cargo.lock') }}-${{ hashFiles('pnpm-lock.yaml') }}-${{ github.ref }}-${{ github.sha }}-compiled - - uses: pnpm/action-setup@v2 - - uses: buildjet/setup-node@v4 - with: - node-version: '21' - cache: 'pnpm' - - run: pnpm install --frozen-lockfile - - uses: dtolnay/rust-toolchain@stable - with: - targets: wasm32-unknown-unknown - - uses: jetli/wasm-pack-action@v0.4.0 - with: - version: 'latest' - - uses: browser-actions/setup-firefox@v1 - - run: pnpm turbo telemetry disable - - run: pnpm turbo test:rust --cache-dir=.turbo From 653f2a687f771be7e74e4709efa6cae0c0bef2ce Mon Sep 17 00:00:00 2001 From: turbocrime Date: Wed, 19 Jun 2024 08:56:36 -0700 Subject: [PATCH 4/4] lint --- .github/workflows/turbo-ci.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/turbo-ci.yml b/.github/workflows/turbo-ci.yml index a366d833..7dcacd69 100644 --- a/.github/workflows/turbo-ci.yml +++ b/.github/workflows/turbo-ci.yml @@ -36,8 +36,8 @@ jobs: - uses: pnpm/action-setup@v2 - uses: buildjet/setup-node@v4 with: - node-version: "22" - cache: "pnpm" + node-version: '22' + cache: 'pnpm' - run: pnpm install --frozen-lockfile - run: pnpm turbo lint --cache-dir=.turbo @@ -55,8 +55,8 @@ jobs: - uses: pnpm/action-setup@v2 - uses: buildjet/setup-node@v4 with: - node-version: "22" - cache: "pnpm" + node-version: '22' + cache: 'pnpm' - run: pnpm install --frozen-lockfile - run: pnpm turbo build --cache-dir=.turbo @@ -74,7 +74,7 @@ jobs: - uses: pnpm/action-setup@v2 - uses: buildjet/setup-node@v4 with: - node-version: "22" - cache: "pnpm" + node-version: '22' + cache: 'pnpm' - run: pnpm install --frozen-lockfile - run: pnpm turbo test --cache-dir=.turbo