From b1003b74c2d16cbda66b146c26e1b8fba636f546 Mon Sep 17 00:00:00 2001 From: Steven Luscher Date: Wed, 31 Jul 2024 10:23:55 -0700 Subject: [PATCH] Delete the v1.x line from the default branch (#3011) # Summary In this PR we eliminate the v1.x line from the default branch, it now lives on the `maintenance/v1.x` branch. # Test Plan ``` pnpm i pnpm test:live-with-test-validator:setup ./scripts/start-shared-test-validator.sh pnpm build ``` --- .changeset/chilled-waves-lay.md | 2 +- .changeset/chilly-seas-act.md | 2 +- .changeset/config.json | 3 - .changeset/pre.json | 77 +- .changeset/rare-goats-sell.md | 2 +- .changeset/strong-pandas-marry.md | 2 +- .changeset/tidy-wolves-share.md | 2 +- .changeset/two-cougars-try.md | 2 +- .github/dependabot.yml | 12 +- .github/workflows/bundlesize.yml | 2 +- .github/workflows/commit-lint.yml | 40 - ...ckages.yml => publish-canary-releases.yml} | 12 +- .github/workflows/publish-gh-pages.yml | 55 +- .github/workflows/publish-legacy-package.yml | 48 - .github/workflows/publish-packages.yml | 2 +- .github/workflows/pull-requests.yml | 2 +- .mergify.yml | 11 +- CONTRIBUTING.md | 33 - README.md | 1483 +++- commitlint.sh | 32 - examples/README.md | 2 - examples/deserialize-transaction/package.json | 2 +- examples/react-app/package.json | 2 +- examples/rpc-custom-api/package.json | 2 +- examples/rpc-transport-throttled/package.json | 2 +- examples/transfer-lamports/package.json | 2 +- packages/accounts/package.json | 2 +- packages/addresses/package.json | 2 +- packages/assertions/package.json | 2 +- packages/codecs-core/package.json | 2 +- packages/codecs-data-structures/package.json | 2 +- packages/codecs-numbers/package.json | 2 +- packages/codecs-strings/package.json | 2 +- packages/codecs/package.json | 2 +- packages/compat/package.json | 4 +- packages/errors/package.json | 2 +- packages/fast-stable-stringify/package.json | 2 +- packages/functional/package.json | 2 +- packages/instructions/package.json | 2 +- packages/keys/package.json | 2 +- packages/library-legacy/.eslintignore | 10 - packages/library-legacy/.eslintrc.js | 48 - packages/library-legacy/.gitignore | 22 - packages/library-legacy/.prettierignore | 2 - packages/library-legacy/.prettierrc.yaml | 6 - packages/library-legacy/.releaserc.json | 8 - packages/library-legacy/.sgcrc | 11 - packages/library-legacy/LICENSE | 20 - packages/library-legacy/README.md | 155 - packages/library-legacy/babel.config.json | 31 - packages/library-legacy/commitlint.config.js | 6 - packages/library-legacy/package.json | 125 - packages/library-legacy/rollup.config.mjs | 215 - .../library-legacy/rollup.config.types.mjs | 8 - packages/library-legacy/scripts/typegen.sh | 10 - .../src/__forks__/browser/fetch-impl.ts | 4 - .../src/__forks__/react-native/fetch-impl.ts | 4 - packages/library-legacy/src/account-data.ts | 39 - packages/library-legacy/src/account.ts | 55 - packages/library-legacy/src/blockhash.ts | 4 - .../src/bpf-loader-deprecated.ts | 5 - packages/library-legacy/src/bpf-loader.ts | 50 - packages/library-legacy/src/connection.ts | 6951 ----------------- packages/library-legacy/src/epoch-schedule.ts | 102 - packages/library-legacy/src/errors.ts | 133 - packages/library-legacy/src/fee-calculator.ts | 18 - packages/library-legacy/src/fetch-impl.ts | 16 - packages/library-legacy/src/index.ts | 24 - packages/library-legacy/src/instruction.ts | 58 - packages/library-legacy/src/keypair.ts | 102 - packages/library-legacy/src/layout.ts | 188 - packages/library-legacy/src/loader.ts | 267 - .../src/message/account-keys.ts | 79 - .../src/message/compiled-keys.ts | 165 - packages/library-legacy/src/message/index.ts | 47 - packages/library-legacy/src/message/legacy.ts | 323 - packages/library-legacy/src/message/v0.ts | 513 -- .../library-legacy/src/message/versioned.ts | 36 - packages/library-legacy/src/nonce-account.ts | 82 - .../programs/address-lookup-table/index.ts | 435 -- .../programs/address-lookup-table/state.ts | 84 - .../src/programs/compute-budget.ts | 281 - .../library-legacy/src/programs/ed25519.ts | 157 - packages/library-legacy/src/programs/index.ts | 7 - .../library-legacy/src/programs/secp256k1.ts | 228 - packages/library-legacy/src/programs/stake.ts | 952 --- .../library-legacy/src/programs/system.ts | 1048 --- packages/library-legacy/src/programs/vote.ts | 586 -- packages/library-legacy/src/publickey.ts | 259 - packages/library-legacy/src/rpc-websocket.ts | 75 - packages/library-legacy/src/sysvar.ts | 37 - packages/library-legacy/src/timing.ts | 23 - .../src/transaction/constants.ts | 12 - .../src/transaction/expiry-custom-errors.ts | 48 - .../library-legacy/src/transaction/index.ts | 5 - .../library-legacy/src/transaction/legacy.ts | 970 --- .../library-legacy/src/transaction/message.ts | 140 - .../src/transaction/versioned.ts | 127 - packages/library-legacy/src/utils/assert.ts | 8 - packages/library-legacy/src/utils/bigint.ts | 43 - .../library-legacy/src/utils/borsh-schema.ts | 38 - packages/library-legacy/src/utils/cluster.ts | 35 - packages/library-legacy/src/utils/ed25519.ts | 43 - .../src/utils/guarded-array-utils.ts | 34 - packages/library-legacy/src/utils/index.ts | 5 - .../src/utils/makeWebsocketUrl.ts | 26 - .../src/utils/promise-timeout.ts | 14 - .../library-legacy/src/utils/secp256k1.ts | 11 - .../utils/send-and-confirm-raw-transaction.ts | 110 - .../src/utils/send-and-confirm-transaction.ts | 106 - .../src/utils/shortvec-encoding.ts | 28 - packages/library-legacy/src/utils/sleep.ts | 4 - .../library-legacy/src/utils/to-buffer.ts | 11 - packages/library-legacy/src/validator-info.ts | 108 - packages/library-legacy/src/vote-account.ts | 236 - packages/library-legacy/test/.gitignore | 1 - .../test/__shadow-jest-types.d.ts | 1 - packages/library-legacy/test/account.test.ts | 24 - packages/library-legacy/test/cluster.test.ts | 22 - .../test/connection-subscriptions.test.ts | 958 --- .../library-legacy/test/connection.test.ts | 6523 ---------------- .../test/epoch-schedule.test.ts | 46 - .../test/fixtures/noop-program/.gitignore | 3 - .../test/fixtures/noop-program/Cargo.toml | 23 - .../test/fixtures/noop-program/build.sh | 7 - .../noop-program/solana_sbf_rust_noop.so | Bin 52328 -> 0 bytes .../test/fixtures/noop-program/src/lib.rs | 76 - .../test/guarded-array-utils.test.ts | 52 - packages/library-legacy/test/keypair.test.ts | 61 - .../test/makeWebsocketUrl.test.ts | 52 - .../test/message-tests/account-keys.test.ts | 180 - .../test/message-tests/compiled-keys.test.ts | 243 - .../test/message-tests/legacy.test.ts | 143 - .../test/message-tests/v0.test.ts | 387 - .../test/message-tests/versioned.test.ts | 28 - .../library-legacy/test/mocks/rpc-http.ts | 273 - .../test/mocks/rpc-websocket.ts | 138 - packages/library-legacy/test/nonce.test.ts | 179 - .../address-lookup-table.test.ts | 268 - .../test/program-tests/compute-budget.test.ts | 177 - .../test/program-tests/ed25519.test.ts | 54 - .../test/program-tests/secp256k1.test.ts | 120 - .../test/program-tests/stake.test.ts | 734 -- .../test/program-tests/system.test.ts | 625 -- .../test/program-tests/vote.test.ts | 405 - .../library-legacy/test/publickey.test.ts | 262 - .../test/shortvec-encoding.test.ts | 74 - .../test/transaction-payer.test.ts | 132 - .../test/transaction-tests/message.test.ts | 160 - .../library-legacy/test/transaction.test.ts | 1226 --- packages/library-legacy/test/url.ts | 29 - .../test/validator-info.test.ts | 38 - .../library-legacy/test/websocket.test.ts | 94 - packages/library-legacy/tsconfig.d.json | 15 - packages/library-legacy/tsconfig.json | 20 - packages/library-legacy/typedoc.json | 8 - packages/library/CHANGELOG.md | 2 +- packages/library/README.md | 1413 +--- packages/library/package.json | 6 +- packages/library/tsconfig.json | 4 +- packages/options/package.json | 2 +- packages/programs/package.json | 2 +- packages/react/package.json | 2 +- packages/rpc-api/package.json | 2 +- packages/rpc-graphql/package.json | 2 +- packages/rpc-parsed-types/package.json | 2 +- packages/rpc-spec-types/package.json | 2 +- packages/rpc-spec/package.json | 2 +- packages/rpc-subscriptions-api/package.json | 2 +- packages/rpc-subscriptions-spec/package.json | 2 +- .../package.json | 2 +- packages/rpc-subscriptions/package.json | 2 +- packages/rpc-transformers/package.json | 2 +- packages/rpc-transport-http/package.json | 2 +- packages/rpc-types/package.json | 2 +- packages/rpc/package.json | 2 +- packages/signers/package.json | 2 +- packages/sysvars/package.json | 2 +- .../transaction-confirmation/package.json | 2 +- packages/transaction-messages/package.json | 2 +- packages/transactions/package.json | 2 +- .../webcrypto-ed25519-polyfill/package.json | 2 +- pnpm-lock.yaml | 5462 +------------ .../legacy-token-test-mint-account.json | 14 - .../legacy-token-test-token-account.json | 14 - .../legacy-token-test-token-owner.json | 11 - turbo.json | 70 +- 187 files changed, 1707 insertions(+), 37336 deletions(-) delete mode 100644 .github/workflows/commit-lint.yml rename .github/workflows/{publish-prerelease-packages.yml => publish-canary-releases.yml} (83%) delete mode 100644 .github/workflows/publish-legacy-package.yml delete mode 100644 CONTRIBUTING.md delete mode 100755 commitlint.sh delete mode 100644 packages/library-legacy/.eslintignore delete mode 100644 packages/library-legacy/.eslintrc.js delete mode 100644 packages/library-legacy/.gitignore delete mode 100644 packages/library-legacy/.prettierignore delete mode 100644 packages/library-legacy/.prettierrc.yaml delete mode 100644 packages/library-legacy/.releaserc.json delete mode 100644 packages/library-legacy/.sgcrc delete mode 100644 packages/library-legacy/LICENSE delete mode 100644 packages/library-legacy/README.md delete mode 100644 packages/library-legacy/babel.config.json delete mode 100644 packages/library-legacy/commitlint.config.js delete mode 100644 packages/library-legacy/package.json delete mode 100644 packages/library-legacy/rollup.config.mjs delete mode 100644 packages/library-legacy/rollup.config.types.mjs delete mode 100755 packages/library-legacy/scripts/typegen.sh delete mode 100644 packages/library-legacy/src/__forks__/browser/fetch-impl.ts delete mode 100644 packages/library-legacy/src/__forks__/react-native/fetch-impl.ts delete mode 100644 packages/library-legacy/src/account-data.ts delete mode 100644 packages/library-legacy/src/account.ts delete mode 100644 packages/library-legacy/src/blockhash.ts delete mode 100644 packages/library-legacy/src/bpf-loader-deprecated.ts delete mode 100644 packages/library-legacy/src/bpf-loader.ts delete mode 100644 packages/library-legacy/src/connection.ts delete mode 100644 packages/library-legacy/src/epoch-schedule.ts delete mode 100644 packages/library-legacy/src/errors.ts delete mode 100644 packages/library-legacy/src/fee-calculator.ts delete mode 100644 packages/library-legacy/src/fetch-impl.ts delete mode 100644 packages/library-legacy/src/index.ts delete mode 100644 packages/library-legacy/src/instruction.ts delete mode 100644 packages/library-legacy/src/keypair.ts delete mode 100644 packages/library-legacy/src/layout.ts delete mode 100644 packages/library-legacy/src/loader.ts delete mode 100644 packages/library-legacy/src/message/account-keys.ts delete mode 100644 packages/library-legacy/src/message/compiled-keys.ts delete mode 100644 packages/library-legacy/src/message/index.ts delete mode 100644 packages/library-legacy/src/message/legacy.ts delete mode 100644 packages/library-legacy/src/message/v0.ts delete mode 100644 packages/library-legacy/src/message/versioned.ts delete mode 100644 packages/library-legacy/src/nonce-account.ts delete mode 100644 packages/library-legacy/src/programs/address-lookup-table/index.ts delete mode 100644 packages/library-legacy/src/programs/address-lookup-table/state.ts delete mode 100644 packages/library-legacy/src/programs/compute-budget.ts delete mode 100644 packages/library-legacy/src/programs/ed25519.ts delete mode 100644 packages/library-legacy/src/programs/index.ts delete mode 100644 packages/library-legacy/src/programs/secp256k1.ts delete mode 100644 packages/library-legacy/src/programs/stake.ts delete mode 100644 packages/library-legacy/src/programs/system.ts delete mode 100644 packages/library-legacy/src/programs/vote.ts delete mode 100644 packages/library-legacy/src/publickey.ts delete mode 100644 packages/library-legacy/src/rpc-websocket.ts delete mode 100644 packages/library-legacy/src/sysvar.ts delete mode 100644 packages/library-legacy/src/timing.ts delete mode 100644 packages/library-legacy/src/transaction/constants.ts delete mode 100644 packages/library-legacy/src/transaction/expiry-custom-errors.ts delete mode 100644 packages/library-legacy/src/transaction/index.ts delete mode 100644 packages/library-legacy/src/transaction/legacy.ts delete mode 100644 packages/library-legacy/src/transaction/message.ts delete mode 100644 packages/library-legacy/src/transaction/versioned.ts delete mode 100644 packages/library-legacy/src/utils/assert.ts delete mode 100644 packages/library-legacy/src/utils/bigint.ts delete mode 100644 packages/library-legacy/src/utils/borsh-schema.ts delete mode 100644 packages/library-legacy/src/utils/cluster.ts delete mode 100644 packages/library-legacy/src/utils/ed25519.ts delete mode 100644 packages/library-legacy/src/utils/guarded-array-utils.ts delete mode 100644 packages/library-legacy/src/utils/index.ts delete mode 100644 packages/library-legacy/src/utils/makeWebsocketUrl.ts delete mode 100644 packages/library-legacy/src/utils/promise-timeout.ts delete mode 100644 packages/library-legacy/src/utils/secp256k1.ts delete mode 100644 packages/library-legacy/src/utils/send-and-confirm-raw-transaction.ts delete mode 100644 packages/library-legacy/src/utils/send-and-confirm-transaction.ts delete mode 100644 packages/library-legacy/src/utils/shortvec-encoding.ts delete mode 100644 packages/library-legacy/src/utils/sleep.ts delete mode 100644 packages/library-legacy/src/utils/to-buffer.ts delete mode 100644 packages/library-legacy/src/validator-info.ts delete mode 100644 packages/library-legacy/src/vote-account.ts delete mode 100644 packages/library-legacy/test/.gitignore delete mode 100644 packages/library-legacy/test/__shadow-jest-types.d.ts delete mode 100644 packages/library-legacy/test/account.test.ts delete mode 100644 packages/library-legacy/test/cluster.test.ts delete mode 100644 packages/library-legacy/test/connection-subscriptions.test.ts delete mode 100644 packages/library-legacy/test/connection.test.ts delete mode 100644 packages/library-legacy/test/epoch-schedule.test.ts delete mode 100644 packages/library-legacy/test/fixtures/noop-program/.gitignore delete mode 100644 packages/library-legacy/test/fixtures/noop-program/Cargo.toml delete mode 100755 packages/library-legacy/test/fixtures/noop-program/build.sh delete mode 100755 packages/library-legacy/test/fixtures/noop-program/solana_sbf_rust_noop.so delete mode 100644 packages/library-legacy/test/fixtures/noop-program/src/lib.rs delete mode 100644 packages/library-legacy/test/guarded-array-utils.test.ts delete mode 100644 packages/library-legacy/test/keypair.test.ts delete mode 100644 packages/library-legacy/test/makeWebsocketUrl.test.ts delete mode 100644 packages/library-legacy/test/message-tests/account-keys.test.ts delete mode 100644 packages/library-legacy/test/message-tests/compiled-keys.test.ts delete mode 100644 packages/library-legacy/test/message-tests/legacy.test.ts delete mode 100644 packages/library-legacy/test/message-tests/v0.test.ts delete mode 100644 packages/library-legacy/test/message-tests/versioned.test.ts delete mode 100644 packages/library-legacy/test/mocks/rpc-http.ts delete mode 100644 packages/library-legacy/test/mocks/rpc-websocket.ts delete mode 100644 packages/library-legacy/test/nonce.test.ts delete mode 100644 packages/library-legacy/test/program-tests/address-lookup-table.test.ts delete mode 100644 packages/library-legacy/test/program-tests/compute-budget.test.ts delete mode 100644 packages/library-legacy/test/program-tests/ed25519.test.ts delete mode 100644 packages/library-legacy/test/program-tests/secp256k1.test.ts delete mode 100644 packages/library-legacy/test/program-tests/stake.test.ts delete mode 100644 packages/library-legacy/test/program-tests/system.test.ts delete mode 100644 packages/library-legacy/test/program-tests/vote.test.ts delete mode 100644 packages/library-legacy/test/publickey.test.ts delete mode 100644 packages/library-legacy/test/shortvec-encoding.test.ts delete mode 100644 packages/library-legacy/test/transaction-payer.test.ts delete mode 100644 packages/library-legacy/test/transaction-tests/message.test.ts delete mode 100644 packages/library-legacy/test/transaction.test.ts delete mode 100644 packages/library-legacy/test/url.ts delete mode 100644 packages/library-legacy/test/validator-info.test.ts delete mode 100644 packages/library-legacy/test/websocket.test.ts delete mode 100644 packages/library-legacy/tsconfig.d.json delete mode 100755 packages/library-legacy/tsconfig.json delete mode 100644 packages/library-legacy/typedoc.json delete mode 100644 scripts/fixtures/legacy-token-test-mint-account.json delete mode 100644 scripts/fixtures/legacy-token-test-token-account.json delete mode 100644 scripts/fixtures/legacy-token-test-token-owner.json diff --git a/.changeset/chilled-waves-lay.md b/.changeset/chilled-waves-lay.md index 94ca1677c26d..4fad8c93ed22 100644 --- a/.changeset/chilled-waves-lay.md +++ b/.changeset/chilled-waves-lay.md @@ -1,5 +1,5 @@ --- -'@solana/web3.js-experimental': major +'@solana/web3.js': major --- This version of the `@solana/web3.js` Technology Preview fixes a bug with the default RPC transport, adds a utility that you can use to get an estimate of a transaction message's compute unit cost, and introduces `@solana/react` hooks for interacting with Wallet Standard wallets. diff --git a/.changeset/chilly-seas-act.md b/.changeset/chilly-seas-act.md index b64541ae3039..6ca3b818d6fa 100644 --- a/.changeset/chilly-seas-act.md +++ b/.changeset/chilly-seas-act.md @@ -1,5 +1,5 @@ --- -"@solana/web3.js-experimental": patch +"@solana/web3.js": patch --- Simulate with the maximum quantity of compute units (1.4M) instead of `u32::MAX` diff --git a/.changeset/config.json b/.changeset/config.json index f7f5d0ac92f6..fc766e91233c 100644 --- a/.changeset/config.json +++ b/.changeset/config.json @@ -9,12 +9,9 @@ "repo": "solana-labs/solana-web3.js" } ], - "commit": false, "fixed": [["@solana/!({*-impl,build-scripts,test-*,tsconfig})"]], - "ignore": ["@solana/web3.js"], "linked": [], "snapshot": { - "prereleaseTemplate": "{tag}.4.{datetime}.{commit}", "useCalculatedVersion": true }, "privatePackages": { diff --git a/.changeset/pre.json b/.changeset/pre.json index 3860dfb93390..6847e2a31360 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -1,45 +1,44 @@ { "mode": "pre", - "tag": "preview", + "tag": "rc", "initialVersions": { - "@solana/accounts": "2.0.0-preview.3", - "@solana/addresses": "2.0.0-preview.3", - "@solana/assertions": "2.0.0-preview.3", - "@solana/codecs": "2.0.0-preview.3", - "@solana/codecs-core": "2.0.0-preview.3", - "@solana/codecs-data-structures": "2.0.0-preview.3", - "@solana/codecs-numbers": "2.0.0-preview.3", - "@solana/codecs-strings": "2.0.0-preview.3", - "@solana/compat": "2.0.0-preview.3", - "@solana/errors": "2.0.0-preview.3", - "@solana/fast-stable-stringify": "2.0.0-preview.3", - "@solana/functional": "2.0.0-preview.3", - "@solana/instructions": "2.0.0-preview.3", - "@solana/keys": "2.0.0-preview.3", - "@solana/web3.js-experimental": "2.0.0-preview.3", - "@solana/web3.js": "0.0.0-development", - "@solana/options": "2.0.0-preview.3", - "@solana/programs": "2.0.0-preview.3", - "@solana/react": "2.0.0-preview.3", - "@solana/rpc": "2.0.0-preview.3", - "@solana/rpc-api": "2.0.0-preview.3", - "@solana/rpc-graphql": "2.0.0-preview.3", - "@solana/rpc-parsed-types": "2.0.0-preview.3", - "@solana/rpc-spec": "2.0.0-preview.3", - "@solana/rpc-spec-types": "2.0.0-preview.3", - "@solana/rpc-subscriptions": "2.0.0-preview.3", - "@solana/rpc-subscriptions-api": "2.0.0-preview.3", - "@solana/rpc-subscriptions-spec": "2.0.0-preview.3", - "@solana/rpc-subscriptions-transport-websocket": "2.0.0-preview.3", - "@solana/rpc-transformers": "2.0.0-preview.3", - "@solana/rpc-transport-http": "2.0.0-preview.3", - "@solana/rpc-types": "2.0.0-preview.3", - "@solana/signers": "2.0.0-preview.3", - "@solana/sysvars": "2.0.0-preview.3", - "@solana/transaction-confirmation": "2.0.0-preview.3", - "@solana/transaction-messages": "2.0.0-preview.3", - "@solana/transactions": "2.0.0-preview.3", - "@solana/webcrypto-ed25519-polyfill": "2.0.0-preview.3", + "@solana/accounts": "2.0.0-preview.4", + "@solana/addresses": "2.0.0-preview.4", + "@solana/assertions": "2.0.0-preview.4", + "@solana/codecs": "2.0.0-preview.4", + "@solana/codecs-core": "2.0.0-preview.4", + "@solana/codecs-data-structures": "2.0.0-preview.4", + "@solana/codecs-numbers": "2.0.0-preview.4", + "@solana/codecs-strings": "2.0.0-preview.4", + "@solana/compat": "2.0.0-preview.4", + "@solana/errors": "2.0.0-preview.4", + "@solana/fast-stable-stringify": "2.0.0-preview.4", + "@solana/functional": "2.0.0-preview.4", + "@solana/instructions": "2.0.0-preview.4", + "@solana/keys": "2.0.0-preview.4", + "@solana/web3.js": "2.0.0-preview.4", + "@solana/options": "2.0.0-preview.4", + "@solana/programs": "2.0.0-preview.4", + "@solana/react": "2.0.0-preview.4", + "@solana/rpc": "2.0.0-preview.4", + "@solana/rpc-api": "2.0.0-preview.4", + "@solana/rpc-graphql": "2.0.0-preview.4", + "@solana/rpc-parsed-types": "2.0.0-preview.4", + "@solana/rpc-spec": "2.0.0-preview.4", + "@solana/rpc-spec-types": "2.0.0-preview.4", + "@solana/rpc-subscriptions": "2.0.0-preview.4", + "@solana/rpc-subscriptions-api": "2.0.0-preview.4", + "@solana/rpc-subscriptions-spec": "2.0.0-preview.4", + "@solana/rpc-subscriptions-transport-websocket": "2.0.0-preview.4", + "@solana/rpc-transformers": "2.0.0-preview.4", + "@solana/rpc-transport-http": "2.0.0-preview.4", + "@solana/rpc-types": "2.0.0-preview.4", + "@solana/signers": "2.0.0-preview.4", + "@solana/sysvars": "2.0.0-preview.4", + "@solana/transaction-confirmation": "2.0.0-preview.4", + "@solana/transaction-messages": "2.0.0-preview.4", + "@solana/transactions": "2.0.0-preview.4", + "@solana/webcrypto-ed25519-polyfill": "2.0.0-preview.4", "@solana/build-scripts": "0.0.0", "@solana/crypto-impl": "0.0.0", "@solana/test-config": "0.0.0", diff --git a/.changeset/rare-goats-sell.md b/.changeset/rare-goats-sell.md index e1c66ad0679a..1f43c8be0d8a 100644 --- a/.changeset/rare-goats-sell.md +++ b/.changeset/rare-goats-sell.md @@ -1,5 +1,5 @@ --- -'@solana/web3.js-experimental': patch +'@solana/web3.js': patch --- Fixed the type of `config` on `getComputeUnitEstimateForTransactionMessage`. It is now optional and does not include `transactionMessage`. diff --git a/.changeset/strong-pandas-marry.md b/.changeset/strong-pandas-marry.md index d01ba1df7b6d..e6fed7165adf 100644 --- a/.changeset/strong-pandas-marry.md +++ b/.changeset/strong-pandas-marry.md @@ -1,5 +1,5 @@ --- -"@solana/web3.js-experimental": patch +"@solana/web3.js": patch "@solana/rpc-subscriptions": patch "@solana/rpc": patch --- diff --git a/.changeset/tidy-wolves-share.md b/.changeset/tidy-wolves-share.md index 2059739aa6b4..95186ee46844 100644 --- a/.changeset/tidy-wolves-share.md +++ b/.changeset/tidy-wolves-share.md @@ -25,7 +25,7 @@ "@solana/accounts": patch "@solana/programs": patch "@solana/rpc-spec": patch -"@solana/web3.js-experimental": patch +"@solana/web3.js": patch "@solana/options": patch "@solana/rpc-api": patch "@solana/signers": patch diff --git a/.changeset/two-cougars-try.md b/.changeset/two-cougars-try.md index a2cebe28ac0e..9b0a6e891869 100644 --- a/.changeset/two-cougars-try.md +++ b/.changeset/two-cougars-try.md @@ -1,5 +1,5 @@ --- -"@solana/web3.js-experimental": patch +"@solana/web3.js": patch --- Created a utility function to estimate the compute unit consumption of a transaction message diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 9607c75facae..f46295647fb8 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -5,7 +5,8 @@ version: 2 updates: - - package-ecosystem: 'npm' + - target-branch: 'maintenance/v1.x' + package-ecosystem: 'npm' directory: '/' schedule: interval: daily @@ -15,4 +16,11 @@ updates: - 'automerge' commit-message: prefix: 'chore:' - open-pull-requests-limit: 3 + - package-ecosystem: 'npm' + directory: '/' + schedule: + interval: daily + time: '01:00' + timezone: America/Los_Angeles + labels: + - 'automerge' diff --git a/.github/workflows/bundlesize.yml b/.github/workflows/bundlesize.yml index 7a9ee535f05b..0f2c834ae5dc 100644 --- a/.github/workflows/bundlesize.yml +++ b/.github/workflows/bundlesize.yml @@ -23,7 +23,7 @@ jobs: version: 9.1.0 run_install: false - - name: Download Experimental Library Bundle + - name: Download Library Bundle uses: actions/download-artifact@v4 with: github-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/commit-lint.yml b/.github/workflows/commit-lint.yml deleted file mode 100644 index 9039bff22852..000000000000 --- a/.github/workflows/commit-lint.yml +++ /dev/null @@ -1,40 +0,0 @@ -name: Commit lint (legacy) - -on: - pull_request: - branches: [master] - paths: - - ./packages/library-legacy/ - -jobs: - web3-commit-lint: - name: Validate commit message - runs-on: ubuntu-latest - continue-on-error: true - - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - # Need to fetch the base SHA so that it can be compared with the head SHA. - fetch-depth: 0 - - - name: Install package manager - uses: pnpm/action-setup@v3 - with: - version: 9.1.0 - - - name: Setup Node - uses: actions/setup-node@v4 - with: - node-version: 16 - cache: 'pnpm' - - - name: Install dependencies - run: pnpm install - - - name: Check that commit message conforms to Semantic Release format - if: ${{ github.event_name == 'pull_request' }} - run: bash commitlint.sh ./packages/library-legacy/ - env: - COMMIT_RANGE: ${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }} diff --git a/.github/workflows/publish-prerelease-packages.yml b/.github/workflows/publish-canary-releases.yml similarity index 83% rename from .github/workflows/publish-prerelease-packages.yml rename to .github/workflows/publish-canary-releases.yml index ba4b7ae43b9c..1e922cd0b563 100644 --- a/.github/workflows/publish-prerelease-packages.yml +++ b/.github/workflows/publish-canary-releases.yml @@ -1,4 +1,4 @@ -name: Publish Package Snapshots +name: Publish Canary Releases on: workflow_dispatch: @@ -32,7 +32,7 @@ jobs: uses: ./.github/workflows/actions/setup-validator - name: Run Build Step (force) - run: pnpm turbo build --filter=\!@solana/web3.js --force=true + run: pnpm turbo build --force=true - name: Configure NPM token run: | @@ -40,19 +40,19 @@ jobs: env: NPM_TOKEN: ${{ secrets.NPM_TOKEN }} - - name: Publish Snapshots + - name: Publish Canary Releases run: | pnpm changeset pre exit find packages/* -maxdepth 0 -type d -print0 | \ xargs -t0 -n 1 -I {} \ sh -c 'cd {} && pnpm pkg delete devDependencies' - pnpm changeset version --snapshot preview - pnpm turbo publish-packages --concurrency=95.84% --filter=\!@solana/web3.js + pnpm changeset version --snapshot canary + pnpm turbo publish-packages --concurrency=95.84% env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} NPM_TOKEN: ${{ secrets.NPM_TOKEN }} - PUBLISH_TAG: experimental + PUBLISH_TAG: canary - name: Stop Test Validator if: always() && steps.start-test-validator.outcome == 'success' diff --git a/.github/workflows/publish-gh-pages.yml b/.github/workflows/publish-gh-pages.yml index 3f7074bf1e93..9225a488473a 100644 --- a/.github/workflows/publish-gh-pages.yml +++ b/.github/workflows/publish-gh-pages.yml @@ -4,9 +4,11 @@ on: workflow_dispatch: branches: - master + - maintenance/* push: branches: - master + - maintenance/* env: # Among other things, opts out of Turborepo telemetry @@ -18,7 +20,32 @@ env: TURBO_TEAM: ${{ secrets.TURBO_TEAM }} jobs: - compile-github-pages-and-publish: + compile-v1-docs: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + ref: maintenance/v1.x + + - name: Install Dependencies + uses: ./.github/workflows/actions/install-dependencies + + - name: Compile docs + run: pnpm compile:docs + + - name: Assemble Deploy Directory + run: | + mkdir -p .ghpages-deploy + mv ./docs/* .ghpages-deploy + + - uses: actions/upload-artifact@v4 + with: + name: ghpages-deploy-artifacts-v1-docs + path: .ghpages-deploy + retention-days: 1 + + compile-github-pages: runs-on: ubuntu-latest steps: - name: Checkout @@ -32,11 +59,31 @@ jobs: env: REACT_EXAMPLE_APP_BASE_PATH: /solana-web3.js/example/ - - name: Assemble deploy directory + - name: Assemble Deploy Directory run: | mkdir -p .ghpages-deploy - cp -r ./packages/library-legacy/doc/* .ghpages-deploy - cp -r ./examples/react-app/dist/ .ghpages-deploy/example/ + mv ./examples/react-app/dist/ .ghpages-deploy/example/ + + - uses: actions/upload-artifact@v4 + with: + name: ghpages-deploy-artifacts + path: .ghpages-deploy + retention-days: 1 + + publish: + runs-on: ubuntu-latest + needs: [compile-v1-docs, compile-github-pages] + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install Dependencies + uses: ./.github/workflows/actions/install-dependencies + + - uses: actions/download-artifact@v4 + with: + pattern: ghpages-deploy-artifacts* + merge-multiple: true - name: Deploy to Github Pages uses: peaceiris/actions-gh-pages@v3 diff --git a/.github/workflows/publish-legacy-package.yml b/.github/workflows/publish-legacy-package.yml deleted file mode 100644 index 486b5bdb425d..000000000000 --- a/.github/workflows/publish-legacy-package.yml +++ /dev/null @@ -1,48 +0,0 @@ -name: Publish Legacy Package - -on: - workflow_dispatch: - branches: - - master - push: - branches: - - master - -env: - # Among other things, opts out of Turborepo telemetry - # See https://consoledonottrack.com/ - DO_NOT_TRACK: '1' - # Enables Turborepo Remote Caching. - TURBO_REMOTE_CACHE_SIGNATURE_KEY: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }} - TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} - TURBO_TEAM: ${{ secrets.TURBO_TEAM }} - -jobs: - build-and-publish-to-npm: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Install Dependencies - uses: ./.github/workflows/actions/install-dependencies - - - name: Setup Solana Test Validator - id: start-test-validator - uses: ./.github/workflows/actions/setup-validator - - - name: Configure NPM token - run: | - pnpm config set '//registry.npmjs.org/:_authToken' "${NPM_TOKEN}" - env: - NPM_TOKEN: ${{ secrets.NPM_TOKEN }} - - - name: Build, Test, and Publish (force) - run: pnpm turbo run publish-packages-legacy --concurrency=95.84% --filter=@solana/web3.js --force=true - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - NPM_TOKEN: ${{ secrets.NPM_TOKEN }} - - - name: Stop Test Validator - if: always() && steps.start-test-validator.outcome == 'success' - run: kill ${{ steps.start-test-validator.outputs.pid }} diff --git a/.github/workflows/publish-packages.yml b/.github/workflows/publish-packages.yml index 72e50e017f2c..48e5f4e21aa8 100644 --- a/.github/workflows/publish-packages.yml +++ b/.github/workflows/publish-packages.yml @@ -48,7 +48,7 @@ jobs: run: echo "step-name=${{ steps.changesets.outputs.hasChangesets == 'false' && 'publish-packages --concurrency=95.84%' || 'build' }}" >> $GITHUB_OUTPUT - name: Run Build Step (force) - run: pnpm turbo ${{ steps.build-step-decider.outputs.step-name }} --filter=!\@solana/web3.js --force=true + run: pnpm turbo ${{ steps.build-step-decider.outputs.step-name }} --force=true env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} NPM_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/pull-requests.yml b/.github/workflows/pull-requests.yml index 9e0fb4abbf51..e672f8a67f2b 100644 --- a/.github/workflows/pull-requests.yml +++ b/.github/workflows/pull-requests.yml @@ -53,7 +53,7 @@ jobs: if: always() && steps.start-test-validator.outcome == 'success' run: kill ${{ steps.start-test-validator.outputs.pid }} - - name: Upload Experimental Library Bundle + - name: Upload Library Bundle if: matrix.node == 'current' uses: actions/upload-artifact@v4 with: diff --git a/.mergify.yml b/.mergify.yml index 99e5c1f2a285..1a4389464d69 100644 --- a/.mergify.yml +++ b/.mergify.yml @@ -35,10 +35,15 @@ pull_request_rules: - name: Automatic merge (squash) on CI success conditions: - and: - - status-success=all-web3-checks - or: - - -files~=^packages/library-legacy/ - - status-success="Validate commit message" + - and: + - base=maintenance/v1.x + - and: + - status-success=build-and-test + - status-success="Validate commit message" + - and: + - base!=maintenance/v1.x + - status-success=all-web3-checks - label=automerge - label!=no-automerge actions: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index d37a09ba7484..000000000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,33 +0,0 @@ -✨ Thanks for contributing to **solana-web3.js**! ✨ - -As a contributor, here are the guidelines we would like you to follow: - -- Ensure `npm run build` passes before submitting a Pull Request -- Features and bug fixes should be covered by new test cases -- Commits follow the [Angular commit convention](https://github.com/angular/angular.js/blob/master/DEVELOPERS.md#-git-commit-guidelines) - -## Creating releases - -We use [semantic-release](https://github.com/semantic-release/semantic-release) -to release new versions automatically from the `master` branch: - -- Commits of type `fix` will trigger bugfix releases, think `0.0.1` -- Commits of type `feat` will trigger feature releases, think `0.1.0` -- Commits with `BREAKING CHANGE` in body or footer will trigger breaking releases, think `1.0.0` - -All other commit types will trigger no new release. - -## Reference - -### Static Analysis - -eslint and TypeScript are used. - -### Testing Framework - -https://mochajs.org/ - -### API Documentation - -TypeDoc is used to document the public API. See -https://typedoc.org/ for details. diff --git a/README.md b/README.md index dd50df138198..ddd5fb515c2b 100644 --- a/README.md +++ b/README.md @@ -6,166 +6,1413 @@ [code-style-prettier-image]: https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square [code-style-prettier-url]: https://github.com/prettier/prettier -[npm-downloads-image]: https://img.shields.io/npm/dm/@solana/web3.js.svg?style=flat -[npm-image]: https://img.shields.io/npm/v/@solana/web3.js.svg?style=flat -[npm-url]: https://www.npmjs.com/package/@solana/web3.js +[npm-downloads-image]: https://img.shields.io/npm/dm/@solana/web3.js/preview.svg?style=flat +[npm-image]: https://img.shields.io/npm/v/@solana/web3.js/preview.svg?style=flat +[npm-url]: https://www.npmjs.com/package/@solana/web3.js/v/preview [semantic-release-image]: https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg [semantic-release-url]: https://github.com/semantic-release/semantic-release # Solana JavaScript SDK -Use this to interact with accounts and programs on the Solana network through the Solana [JSON RPC API](https://solana.com/docs/rpc). +This is the JavaScript SDK for building Solana apps for Node, web, and React Native. -## Installation +# Installation -### For use in Node.js or a web application +For use in a Node.js or web application: -``` -$ npm install --save @solana/web3.js +```shell +npm install --save @solana/web3.js@rc ``` -### For use in a browser, without a build system +For use in a browser, without a build system: ```html - - + + - + ``` -## Documentation and examples +# Examples -- [The Solana Cookbook](https://solanacookbook.com/) has extensive task-based documentation using this library. -- For more detail on individual functions, see the [latest API Documentation](https://solana-labs.github.io/solana-web3.js) +To get a feel for the API, run and modify the live examples in the `examples/` directory. There, you will find a series of single-purpose Node scripts that demonstrate a specific feature or use case. You will also find a React application that you can run in a browser, that demonstrates being able to create, sign, and send transactions using browser wallets. -## Getting help +# What's New in Version 2.0 -Have a question or a problem? Check the [Solana Stack Exchange](https://solana.stackexchange.com) to see if anyone else is having the same one. If not, [post a new question](https://solana.stackexchange.com/questions/ask). +Version 2.0 of the Solana JavaScript SDK is a response to many of the pain points you have communicated to us when developing Solana applications with web3.js. -Include: +## Tree-Shakability -- A detailed description of what you're trying to achieve -- Source code, if possible -- The text of any errors you encountered, with stacktraces if available +The object-oriented design of the web3.js (1.x) API prevents optimizing compilers from being able to ‘tree-shake’ unused code from your production builds. No matter how much of the web3.js API you use in your application, you have until now been forced to package all of it. -## Compatibility +Read more about tree-shaking here: -This library requires a JavaScript runtime that supports [`BigInt`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt) and the [exponentiation operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Exponentiation). Both are supported in the following runtimes: +- [Mozilla Developer Docs: Tree Shaking](https://developer.mozilla.org/en-US/docs/Glossary/Tree_shaking) +- [WebPack Docs: Tree Shaking](https://webpack.js.org/guides/tree-shaking/) +- [Web.Dev Blog Article: Reduce JavaScript Payloads with Tree Shaking](https://web.dev/articles/reduce-javascript-payloads-with-tree-shaking) -- Browsers, by [release date](https://caniuse.com/bigint): - - Chrome: May 2018 - - Firefox: July 2019 - - Safari: September 2020 - - Mobile Safari: September 2020 - - Edge: January 2020 - - Opera: June 2018 - - Samsung Internet: April 2019 -- Runtimes, [by version](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt): - - Deno: >=1.0 - - Node: >=10.4.0 -- React Native: - - \>=0.7.0 using the [Hermes](https://reactnative.dev/blog/2022/07/08/hermes-as-the-default) engine ([integration guide](https://solanacookbook.com/integrations/react-native.html#how-to-use-solana-web3-js-in-a-react-native-app)): +One example of an API that can’t be tree-shaken is the `Connection` class. It has dozens of methods, but because it’s a _class_ you have no choice but to include every method in your application’s final bundle, no matter how many you _actually_ use. -## Development environment setup +Needlessly large JavaScript bundles can cause issues with deployments to cloud compute providers like Cloudflare or AWS Lambda. They also impact webapp startup performance because of longer download and JavaScript parse times. -### Installing node modules +Version 2.0 is fully tree-shakable and will remain so, enforced by build-time checks. Optimizing compilers can now eliminate those parts of the library that your application does not use. -To install the modules locally, use `pnpm`. +The new library itself is comprised of several smaller, modular packages under the `@solana` organization, including: -If you don't have `pnpm` installed: +- `@solana/accounts`: For fetching and decoding accounts +- `@solana/codecs`: For composing data (de)serializers from a set of primitives or building custom ones +- `@solana/errors`: For identifying and refining coded errors thrown in the `@solana` namespace +- `@solana/rpc`: For sending RPC requests +- `@solana/rpc-subscriptions`: For subscribing to RPC notifications +- `@solana/signers`: For building message and/or transaction signer objects +- `@solana/sysvars`: For fetching and decoding sysvar accounts +- `@solana/transaction-messages`: For building and transforming Solana transaction message objects +- `@solana/transactions`: For compiling and signing transactions for submission to the network +- And many more! -```shell -$ npm install pnpm +Some of these packages are themselves composed of smaller packages. For instance, `@solana/rpc` is composed of `@solana/rpc-spec` (for core JSON RPC specification types), `@solana/rpc-api` (for the Solana-specific RPC methods), `@solana/rpc-transport-http` (for the default HTTP transport) and so on. + +Developers can use the default configurations within the main library (`@solana/web3.js@rc`) or import any of its subpackages where customization-through-composition is desired. + +## Composable Internals + +Depending on your use case and your tolerance for certain application behaviours, you may wish to configure your application to make a different set of tradeoffs than another developer. The web3.js (1.x) API imposed a rigid set of common-case defaults on _all_ developers, some of which were impossible to change. + +The inability to customize web3.js up until now has been a source of frustration: + +- The Mango team wanted to customize the transaction confirmation strategy, but all of that functionality is hidden away behind `confirmTransaction` – a static method of `Connection`. [Here’s the code for `confirmTransaction` on GitHub](https://github.com/solana-labs/solana-web3.js/blob/69a8ad25ef09f9e6d5bff1ffa8428d9be0bd32ac/packages/library-legacy/src/connection.ts#L3734). +- Solana developer ‘mPaella’ [wanted us to add a feature in the RPC](https://github.com/solana-labs/solana-web3.js/issues/1143#issuecomment-1435927152) that would failover to a set of backup URLs in case the primary one failed. +- Solana developer ‘epicfaace’ wanted first-class support for automatic time-windowed batching in the RPC transport. [Here’s their pull request](https://github.com/solana-labs/solana/pull/23628). +- Multiple folks have expressed the need for custom retry logic for failed requests or transactions. [Here’s a pull request from ‘dafyddd’](https://github.com/solana-labs/solana/pull/11811) and [another from ‘abrkn’](https://github.com/solana-labs/solana-web3.js/issues/1041) attempting to modify retry logic to suit their individual use cases. + +Version 2.0 exposes far more of its internals, particularly where communication with an RPC is concerned, and allows willing developers the ability to compose new implementations from the default ones that manifest a nearly limitless array of customizations. + +The individual modules that make up web3.js are assembled in a **default** configuration reminiscent of the legacy library as part of the npm package `@solana/web3.js@rc`, but those who wish to assemble them in different configurations may do so. + +Generic types are offered in numerous places, allowing you to specify new functionality, to make extensions to each API via composition and supertypes, and to encourage you to create higher-level opinionated abstractions of your own. + +In fact, we expect you to do so, and to open source some of those for use by others with similar needs. + +## Modern JavaScript; Zero-Dependency + +The advance of modern JavaScript features presents an opportunity to developers of crypto applications, such as the ability to use native Ed25519 keys and to express large values as native `bigint`. + +The Web Incubator Community Group has advocated for the addition of Ed25519 support to the [Web Crypto API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API), and support has already landed in _most_ modern JavaScript runtimes. + +Engine support for `bigint` values has also become commonplace. The older `number` primitive in JavaScript has a maximum value of 2^53 - 1, whereas Rust’s `u64` can represent values up to 2^64. + +Version 2.0 eliminates userspace implementations of Ed25519 cryptography, large number polyfills, and more, in favour of custom implementations or the use of native JavaScript features, reducing the size of the library. It has no third-party dependencies. + +## Functional Architecture + +The object oriented, class-based architecture of web3.js (1.x) causes unnecessary bundle bloat. Your application has no choice but to bundle _all_ of the functionality and dependencies of a class no matter how many methods you actually use at runtime. + +Class-based architecture also presents unique risks to developers who trigger the dual-package hazard. This describes a situation you can find yourself in if you build for both CommonJS and ES modules. It arises when two copies of the same class are present in the dependency tree, causing checks like `instanceof` to fail. This introduces aggravating and difficult to debug problems. + +Read more about dual-package hazard: + +- [NodeJS: Dual Package Hazard](https://nodejs.org/api/packages.html#dual-package-hazard) + +Version 2.0 implements no classes (with the notable exception of the `SolanaError` class) and implements the thinnest possible interfaces at function boundaries. + +## Statistics + +Consider these statistical comparisons between version 2.0 and the legacy 1.x. + +| | 1.x (Legacy) | 2.0 | +/- % | +| ------------------------------------------------------------------------------------------------------ | ------------ | ---------- | ----- | +| Total minified size of library | 81 KB | 57.5 KB | -29% | +| Total minified size of library (when runtime supports Ed25519) | 81 KB | 53 KB | -33% | +| Bundled size of a web application that executes a transfer of lamports | 111 KB | 23.9 KB | -78% | +| Bundled size of a web application that executes a transfer of lamports (when runtime supports Ed25519) | 111 KB | 18.2 KB | -83% | +| Performance of key generation, signing, and verifying signatures (Brave with Experimental API flag) | 700 ops/s | 7000 ops/s | +900% | +| First-load size for Solana Explorer | 311 KB | 228 KB | -26% | + +The re-engineered library achieves these speedups and reductions in bundle size in large part through use of modern JavaScript APIs. + +To validate our work, we replaced the legacy 1.x library with the new 2.0 library on the homepage of the Solana Explorer. Total first-load bundle size dropped by 26% without removing a single feature. [Here’s an X thread](https://twitter.com/callum_codes/status/1679124485218226176) by Callum McIntyre if you would like to dig deeper. + +# A Tour of the Version 2.0 API + +Here’s an overview of how to use the new library to interact with the RPC, configure network transports, work with Ed25519 keys, and to serialize data. + +## RPC + +Version 2.0 ships with an implementation of the [JSON RPC specification](https://www.jsonrpc.org/specification) and a type spec for the [Solana JSON RPC](https://docs.solana.com/api). + +The main package responsible for managing communication with an RPC is `@solana/rpc`. However, this package makes use of more granular packages to break down the RPC logic into smaller pieces. Namely, these packages are: + +- `@solana/rpc`: Contains all logic related to sending Solana RPC calls. +- `@solana/rpc-api`: Describes all Solana RPC methods using types. +- `@solana/rpc-transport-http`: Provides a concrete implementation of an RPC transport using HTTP requests. +- `@solana/rpc-spec`: Defines the JSON RPC spec for sending RPC requests. +- `@solana/rpc-spec-types`: Shared JSON RPC specifications types and helpers that are used by both `@solana/rpc` and `@solana/rpc-subscriptions` (described in the next section). +- `@solana/rpc-types`: Shared Solana RPC types and helpers that are used by both `@solana/rpc` and `@solana/rpc-subscriptions`. + +The main `@solana/web3.js` package re-exports the `@solana/rpc` package so, going forward, we will import RPC types and functions from the library directly. + +### RPC Calls + +You can use the `createSolanaRpc` function by providing the URL of a Solana JSON RPC server. This will create a default client for interacting with the Solana JSON RPC API. + +```ts +import { createSolanaRpc } from '@solana/web3.js'; + +// Create an RPC client. +const rpc = createSolanaRpc('http://127.0.0.1:8899'); +// ^? Rpc + +// Send a request. +const slot = await rpc.getSlot().send(); ``` -To install the node modules: +### Custom RPC Transports -```shell -$ pnpm install +The `createSolanaRpc` function communicates with the RPC server using a default HTTP transport that should satisfy most use cases. You can provide your own transport or wrap an existing one to communicate with RPC servers in any way you see fit. In the example below, we explicitly create a transport and use it to create a new RPC client via the `createSolanaRpcFromTransport` function. + +```ts +import { createSolanaRpcFromTransport, createDefaultRpcTransport } from '@solana/web3.js'; + +// Create an HTTP transport or any custom transport of your choice. +const transport = createDefaultRpcTransport({ url: 'https://api.devnet.solana.com' }); + +// Create an RPC client using that transport. +const rpc = createSolanaRpcFromTransport(transport); +// ^? Rpc + +// Send a request. +const slot = await rpc.getSlot().send(); ``` -### Testing +A custom transport can implement specialized functionality such as coordinating multiple transports, implementing retries, and more. Let's take a look at some concrete examples. -#### Unit tests +#### Round Robin -To run the full suite of unit tests, execute the following in the root: +A ‘round robin’ transport is one that distributes requests to a list of endpoints in sequence. -```shell -$ npm test +```ts +import { createDefaultRpcTransport, createSolanaRpcFromTransport, type RpcTransport } from '@solana/web3.js'; + +// Create an HTTP transport for each RPC server. +const transports = [ + createDefaultRpcTransport({ url: 'https://mainnet-beta.my-server-1.com' }), + createDefaultRpcTransport({ url: 'https://mainnet-beta.my-server-2.com' }), + createDefaultRpcTransport({ url: 'https://mainnet-beta.my-server-3.com' }), +]; + +// Set up the round-robin transport. +let nextTransport = 0; +async function roundRobinTransport(...args: Parameters): Promise { + const transport = transports[nextTransport]; + nextTransport = (nextTransport + 1) % transports.length; + return await transport(...args); +} + +// Create an RPC client using the round-robin transport. +const rpc = createSolanaRpcFromTransport(roundRobinTransport); ``` -#### Integration tests +#### Sharding -Integration tests require a validator client running on your machine. +A sharding transport is a kind of distributing transport that sends requests to a particular server based on something about the request itself. Here’s an example that sends requests to different servers depending on the name of the method: -To install a test validator: +```ts +import { createDefaultRpcTransport, createSolanaRpcFromTransport, type RpcTransport } from '@solana/web3.js'; -```shell -$ npm run test:live-with-test-validator:setup +// Create multiple transports. +const transportA = createDefaultRpcTransport({ url: 'https://mainnet-beta.my-server-1.com' }); +const transportB = createDefaultRpcTransport({ url: 'https://mainnet-beta.my-server-2.com' }); +const transportC = createDefaultRpcTransport({ url: 'https://mainnet-beta.my-server-3.com' }); +const transportD = createDefaultRpcTransport({ url: 'https://mainnet-beta.my-server-4.com' }); + +// Function to determine which shard to use based on the request method. +function selectShard(method: string): RpcTransport { + switch (method) { + case 'getAccountInfo': + case 'getBalance': + return transportA; + case 'getTransaction': + case 'getRecentBlockhash': + return transportB; + case 'sendTransaction': + return transportC; + default: + return transportD; + } +} + +// Create a transport that selects the correct transport given the request method name. +async function shardingTransport(...args: Parameters): Promise { + const payload = args[0].payload as { method: string }; + const selectedTransport = selectShard(payload.method); + return (await selectedTransport(...args)) as TResponse; +} + +// Create an RPC client using the sharding transport. +const rpc = createSolanaRpcFromTransport(shardingTransport); ``` -To start the test validator and run all of the integration tests in live mode: +#### Retry -```shell -$ cd packages/library-legacy -$ npm run test:live-with-test-validator -``` - -### Speed up build times with remote caching - -Cache build artifacts remotely so that you, others, and the CI server can take advantage of each others' build efforts. - -1. Log the Turborepo CLI into the Solana Vercel account - ```shell - pnpm turbo login - ``` -2. Link the repository to the remote cache - ```shell - pnpm turbo link - ``` - -## Contributing - -If you found a bug or would like to request a feature, please [file an issue](https://github.com/solana-labs/solana-web3.js/issues/new). If, based on the discussion on an issue you would like to offer a code change, please make a [pull request](https://github.com/solana-labs/solana-web3.js/compare). If neither of these describes what you would like to contribute, read the [getting help](#getting-help) section above. - -## Disclaimer - -All claims, content, designs, algorithms, estimates, roadmaps, -specifications, and performance measurements described in this project -are done with the Solana Foundation's ("SF") best efforts. It is up to -the reader to check and validate their accuracy and truthfulness. -Furthermore nothing in this project constitutes a solicitation for -investment. - -Any content produced by SF or developer resources that SF provides, are -for educational and inspiration purposes only. SF does not encourage, -induce or sanction the deployment, integration or use of any such -applications (including the code comprising the Solana blockchain -protocol) in violation of applicable laws or regulations and hereby -prohibits any such deployment, integration or use. This includes use of -any such applications by the reader (a) in violation of export control -or sanctions laws of the United States or any other applicable -jurisdiction, (b) if the reader is located in or ordinarily resident in -a country or territory subject to comprehensive sanctions administered -by the U.S. Office of Foreign Assets Control (OFAC), or (c) if the -reader is or is working on behalf of a Specially Designated National -(SDN) or a person subject to similar blocking or denied party -prohibitions. - -The reader should be aware that U.S. export control and sanctions laws -prohibit U.S. persons (and other persons that are subject to such laws) -from transacting with persons in certain countries and territories or -that are on the SDN list. As a project based primarily on open-source -software, it is possible that such sanctioned persons may nevertheless -bypass prohibitions, obtain the code comprising the Solana blockchain -protocol (or other project code or applications) and deploy, integrate, -or otherwise use it. Accordingly, there is a risk to individuals that -other persons using the Solana blockchain protocol may be sanctioned -persons and that transactions with such persons would be a violation of -U.S. export controls and sanctions law. This risk applies to -individuals, organizations, and other ecosystem participants that -deploy, integrate, or use the Solana blockchain protocol code directly -(e.g., as a node operator), and individuals that transact on the Solana -blockchain through light clients, third party interfaces, and/or wallet -software. +A custom transport is a good place to implement global retry logic for every request: + +```ts +import { createDefaultRpcTransport, createSolanaRpcFromTransport, type RpcTransport } from '@solana/web3.js'; + +// Set the maximum number of attempts to retry a request. +const MAX_ATTEMPTS = 4; + +// Create the default transport. +const defaultTransport = createDefaultRpcTransport({ url: 'https://mainnet-beta.my-server-1.com' }); + +// Sleep function to wait for a given number of milliseconds. +function sleep(ms: number): Promise { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +// Calculate the delay for a given attempt. +function calculateRetryDelay(attempt: number): number { + // Exponential backoff with a maximum of 1.5 seconds. + return Math.min(100 * Math.pow(2, attempt), 1500); +} + +// A retrying transport that will retry up to MAX_ATTEMPTS times before failing. +async function retryingTransport(...args: Parameters): Promise { + let requestError; + for (let attempts = 0; attempts < MAX_ATTEMPTS; attempts++) { + try { + return await defaultTransport(...args); + } catch (err) { + requestError = err; + // Only sleep if we have more attempts remaining. + if (attempts < MAX_ATTEMPTS - 1) { + const retryDelay = calculateRetryDelay(attempts); + await sleep(retryDelay); + } + } + } + throw requestError; +} + +// Create the RPC client using the retrying transport. +const rpc = createSolanaRpcFromTransport(retryingTransport); +``` + +#### Failover + +Support for handling network failures can be implemented in the transport itself. Here’s an example of some failover logic integrated into a transport: + +```ts +// TODO: Your turn; send us a pull request with an example. +``` + +### Augmenting/Constraining the RPC API + +Using the `createSolanaRpc` or `createSolanaRpcFromTransport` methods, we always get the same API that includes the Solana RPC API methods. Since the RPC API is described using types only, it is possible to augment those types to add your own methods. + +When constraining the API scope, keep in mind that types don’t affect bundle size. You may still like to constrain the type-spec for a variety of reasons, including reducing TypeScript noise. + +#### Constraining by Cluster + +If you're using a specific cluster, you may wrap your RPC URL inside a helper function like `mainnet` or `devnet` to inject that information into the RPC type system. + +```ts +import { createSolanaRpc, mainnet, devnet } from '@solana/web3.js'; + +const mainnetRpc = createSolanaRpc(mainnet('https://api.mainnet-beta.solana.com')); +// ^? RpcMainnet + +const devnetRpc = createSolanaRpc(devnet('https://api.devnet.solana.com')); +// ^? RpcDevnet +``` + +In the example above, `devnetRpc.requestAirdrop(..)` will work, but `mainnetRpc.requestAirdrop(..)` will raise a TypeScript error since `requestAirdrop` is not a valid method of the mainnet cluster. + +#### Cherry-Picking API Methods + +You can constrain the API’s type-spec even further so you are left only with the methods you need. The simplest way to do this is to cast the created RPC client to a type that only includes the required methods. + +```ts +import { createSolanaRpc, type Rpc, type GetAccountInfoApi, type GetMultipleAccountsApi } from '@solana/web3.js'; + +const rpc = createSolanaRpc('http://127.0.0.1:8899') as Rpc; +``` + +Alternatively, you can explicitly create the RPC API using the `createSolanaRpcApi` function. You will need to create your own transport and bind the two together using the `createRpc` function. + +```ts +import { + createDefaultRpcTransport, + createRpc, + createSolanaRpcApi, + DEFAULT_RPC_CONFIG, + type GetAccountInfoApi, + type GetMultipleAccountsApi, +} from '@solana/web3.js'; + +const api = createSolanaRpcApi(DEFAULT_RPC_CONFIG); +const transport = createDefaultRpcTransport({ url: 'http:127.0.0.1:8899' }); + +const rpc = createRpc({ api, transport }); +``` + +Note that the `createSolanaRpcApi` function is a wrapper on top of the `createRpcApi` function which adds some Solana-specific transformers such as setting a default commitment on all methods or throwing an error when an integer overflow is detected. + +#### Creating Your Own API Methods + +The new library’s RPC specification supports an _infinite_ number of JSON-RPC methods with **zero increase** in bundle size. + +This means the library can support future additions to the official [Solana JSON RPC](https://docs.solana.com/api), or [custom RPC methods](https://docs.helius.dev/compression-and-das-api/digital-asset-standard-das-api/get-asset) defined by some RPC provider. + +Here’s an example of how a developer at might build a custom RPC type-spec for an RPC provider's implementation of the Metaplex Digital Asset Standard's `getAsset` method: + +```ts +import { RpcApiMethods } from '@solana/web3.js'; + +// Define the method's response payload. +type GetAssetApiResponse = Readonly<{ + interface: DasApiAssetInterface; + id: Address; + content: Readonly<{ + files?: readonly { + mime?: string; + uri?: string; + [key: string]: unknown; + }[]; + json_uri: string; + links?: readonly { + [key: string]: unknown; + }[]; + metadata: DasApiMetadata; + }>; + /* ...etc... */ +}>; + +// Set up an interface for the request method. +interface GetAssetApi extends RpcApiMethods { + // Define the method's name, parameters and response type + getAsset(args: { id: Address }): GetAssetApiResponse; +} + +// Export the type spec for downstream users. +export type MetaplexDASApi = GetAssetApi; +``` + +Here’s how a developer might use it: + +```ts +import { createDefaultRpcTransport, createRpc, createRpcApi } from '@solana/web3.js'; + +// Create the custom API. +const api = createRpcApi(); + +// Set up an HTTP transport to a server that supports the custom API. +const transport = createDefaultRpcTransport({ + url: 'https://mainnet.helius-rpc.com/?api-key=', +}); + +// Create the RPC client. +const metaplexDASRpc = createRpc({ api, transport }); +// ^? Rpc +``` + +As long as a particular JSON RPC method adheres to the [official JSON RPC specification](https://www.jsonrpc.org/specification), it will be supported by version 2.0. + +### Aborting RPC Requests + +RPC requests are now abortable with modern `AbortControllers`. When calling an RPC method such as `getSlot`, it will return a `PendingRpcRequest` proxy object that contains a `send` method to send the request to the server. + +```ts +const pendingRequest: PendingRpcRequest = rpc.getSlot(); + +const slot: Slot = await pendingRequest.send(); +``` + +The arguments of the `getSlot` method are reserved for the request payload, but the `send` method is where additional arguments such as an `AbortSignal` can be accepted in the context of the request. + +Aborting RPC requests can be useful for a variety of things such as setting a timeout on a request or cancelling a request when a user navigates away from a page. + +```ts +import { createSolanaRpc } from '@solana/web3.js'; + +const rpc = createSolanaRpc('http://127.0.0.1:8900'); + +// Create a new AbortController. +const abortController = new AbortController(); + +// Abort the request when the user navigates away from the current page. +function onUserNavigateAway() { + abortController.abort(); +} + +// The request will be aborted if and only if the user navigates away from the page. +const slot = await rpc.getSlot().send({ abortSignal: abortController.signal }); +``` + +Read more about `AbortController` here: + +- [Mozilla Developer Docs: `AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController) +- [Mozilla Developer Docs: `AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) +- [JavaScript.info: Fetch: Abort](https://javascript.info/fetch-abort) + +## RPC Subscriptions + +Subscriptions in the legacy library do not allow custom retry logic and do not allow you to recover from potentially missed messages. The new version does away with silent retries, surfaces transport errors to your application, and gives you the opportunity to recover from gap events. + +The main package responsible for managing communication with RPC subscriptions is `@solana/rpc-subscriptions`. However, similarly to `@solana/rpc`, this package also makes use of more granular packages. These packages are: + +- `@solana/rpc-subscriptions`: Contains all logic related to subscribing to Solana RPC notifications. +- `@solana/rpc-subscriptions-api`: Describes all Solana RPC subscriptions using types. +- `@solana/rpc-subscriptions-transport-websocket`: Provides a concrete implementation of an RPC Subscriptions transport using WebSockets. +- `@solana/rpc-subscriptions-spec`: Defines the JSON RPC spec for subscribing to RPC notifications. +- `@solana/rpc-spec-types`: Shared JSON RPC specifications types and helpers that are used by both `@solana/rpc` and `@solana/rpc-subscriptions`. +- `@solana/rpc-types`: Shared Solana RPC types and helpers that are used by both `@solana/rpc` and `@solana/rpc-subscriptions`. + +Since the main `@solana/web3.js` library also re-exports the `@solana/rpc-subscriptions` package we will import RPC Subscriptions types and functions directly from the main library going forward. + +### Getting Started with RPC Subscriptions + +To get started with RPC Subscriptions, you may use the `createSolanaRpcSubscriptions` function by providing the WebSocket URL of a Solana JSON RPC server. This will create a default client for interacting with Solana RPC Subscriptions. + +```ts +import { createSolanaRpcSubscriptions } from '@solana/web3.js'; + +// Create an RPC Subscriptions client. +const rpcSubscriptions = createSolanaRpcSubscriptions('ws://127.0.0.1:8900'); +// ^? RpcSubscriptions +``` + +### Subscriptions as `AsyncIterators` + +The new subscriptions API vends subscription notifications as an `AsyncIterator`. The `AsyncIterator` conforms to the [async iterator protocol](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#the_async_iterator_and_async_iterable_protocols), which allows developers to consume messages using a `for await...of` loop. + +Here’s an example of working with a subscription in the new library: + +```ts +import { address, createSolanaRpcSubscriptions, createDefaultRpcSubscriptionsTransport } from '@solana/web3.js'; + +// Create the RPC Subscriptions client. +const rpcSubscriptions = createSolanaRpcSubscriptions('ws://127.0.0.1:8900'); + +// Set up an abort controller. +const abortController = new AbortController(); + +// Subscribe to account notifications. +const accountNotifications = await rpcSubscriptions + .accountNotifications(address('AxZfZWeqztBCL37Mkjkd4b8Hf6J13WCcfozrBY6vZzv3'), { commitment: 'confirmed' }) + .subscribe({ abortSignal: abortController.signal }); + +try { + // Consume messages. + for await (const notification of accountNotifications) { + console.log('New balance', notification.value.lamports); + } +} catch (e) { + // The subscription went down. + // Retry it and then recover from potentially having missed + // a balance update, here (eg. by making a `getBalance()` call). +} +``` + +You can read more about `AsyncIterator` at the following links: + +- [Mozilla Developer Docs: `AsyncIterator`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncIterator) +- [Luciano Mammino (Blog): JavaScript Async Iterators](https://www.nodejsdesignpatterns.com/blog/javascript-async-iterators/) + +### Aborting RPC Subscriptions + +Similarly to RPC calls, applications can terminate active subscriptions using an `AbortController` attribute on the `subscribe` method. In fact, this parameter is _required_ for subscriptions to encourage you to clean up subscriptions that your application no longer needs. + +Let's take a look at some concrete examples that demonstrate how to abort subscriptions. + +#### Subscription Timeout + +Here's an example of an `AbortController` used to abort a subscription after a 5-second timeout: + +```ts +import { createSolanaRpcSubscriptions } from '@solana/web3.js'; + +const rpcSubscriptions = createSolanaRpcSubscriptions('ws://127.0.0.1:8900'); + +// Subscribe for slot notifications using an AbortSignal that times out after 5 seconds. +const slotNotifications = await rpcSubscriptions + .slotNotifications() + .subscribe({ abortSignal: AbortSignal.timeout(5000) }); + +// Log slot notifications. +for await (const notification of slotNotifications) { + console.log('Slot notification', notification); +} + +console.log('Done.'); +``` + +Read more about `AbortController` at the following links: + +- [Mozilla Developer Docs: `AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController) +- [Mozilla Developer Docs: `AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) +- [JavaScript.info: Fetch: Abort](https://javascript.info/fetch-abort) + +#### Cancelling Subscriptions + +It is also possible to abort a subscription inside the `for await...of` loop. This enables us to cancel a subscription based on some condition, such as a change in the state of an account. For instance, the following example cancels a subscription when the owner of an account changes: + +```ts +// Subscribe to account notifications. +const accountNotifications = await rpc + .accountNotifications(address('AxZfZWeqztBCL37Mkjkd4b8Hf6J13WCcfozrBY6vZzv3'), { commitment: 'confirmed' }) + .subscribe({ abortSignal }); + +// Consume messages. +let previousOwner = null; +for await (const notification of accountNotifications) { + const { + value: { owner }, + } = notification; + // Check the owner to see if it has changed + if (previousOwner && owner !== previousOwner) { + // If so, abort the subscription + abortController.abort(); + } else { + console.log(notification); + } + previousOwner = owner; +} +``` + +### Failed vs. Aborted Subscriptions + +It is important to note that a subscription failure behaves differently from a subscription abort. A subscription failure occurs when the subscription goes down and will throw an error that can be intercepted in a `try/catch`. However, an aborted subscription will not throw an error, but will instead exit the `for await...of` loop. + +```ts +try { + for await (const notification of notifications) { + // Consume messages. + } + // [ABORTED] Reaching this line means the subscription was aborted — i.e. unsubscribed. +} catch (e) { + // [FAILED] Reaching this line means the subscription went down. + // Retry it, then recover from potential missed messages. +} finally { + // [ABORTED or FAILED] Whether the subscription failed or was aborted, you can run cleanup code here. +} +``` + +### Message Gap Recovery + +One of the most crucial aspects of any subscription API is managing potential missed messages. Missing messages, such as account state updates, could be catastrophic for an application. That’s why the new library provides native support for recovering missed messages using the `AsyncIterator`. + +When a connection fails unexpectedly, any messages you miss while disconnected can result in your UI falling behind or becoming corrupt. Because subscription failure is now made explicit in the new API, you can implement ‘catch-up’ logic after re-establishing the subscription. + +Here’s an example of such logic: + +```ts +try { + for await (const notif of accountNotifications) { + updateAccountBalance(notif.lamports); + } +} catch (e) { + // The subscription failed. + // First, re-establish the subscription. + await setupAccountBalanceSubscription(address); + // Then make a one-shot request to 'catch up' on any missed balance changes. + const { value: lamports } = await rpc.getBalance(address).send(); + updateAccountBalance(lamports); +} +``` + +### Using Custom RPC Subscriptions Transports + +The `createSolanaRpcSubscriptions` function communicates with the RPC server using a default WebSocket transport that should satisfy most use cases. However, you may here as well provide your own transport or decorate existing ones to communicate with RPC servers in any way you see fit. In the example below, we explicitly create a WebSocket transport and use it to create a new RPC Subscriptions client via the `createSolanaRpcSubscriptionsFromTransport` function. + +```ts +import { createDefaultRpcSubscriptionsTransport, createSolanaRpcSubscriptionsFromTransport } from '@solana/web3.js'; + +// Create a WebSocket transport or any custom transport of your choice. +const transport = createDefaultRpcSubscriptionsTransport({ url: 'ws://127.0.0.1:8900' }); + +// Create an RPC client using that transport. +const rpcSubscriptions = createSolanaRpcSubscriptionsFromTransport(transport); +// ^? RpcSubscriptions +``` + +### Augmenting/Constraining the RPC Subscriptions API + +Using the `createSolanaRpcSubscriptions` or `createSolanaRpcSubscriptionsFromTransport` functions, we always get the same RPC Subscriptions API, including all Solana RPC stable subscriptions. However, since the RPC Subscriptions API is described using types only, it is possible to constrain the API to a specific set of subscriptions or even add your own custom subscriptions. + +#### Constraining by Cluster + +If you're using a specific cluster, you may wrap your RPC URL inside a helper function like `mainnet` or `devnet` to inject that information into the RPC type system. + +```ts +import { createSolanaRpcSubscriptions, mainnet, devnet } from '@solana/web3.js'; + +const mainnetRpc = createSolanaRpcSubscriptions(mainnet('https://api.mainnet-beta.solana.com')); +// ^? RpcSubscriptionsMainnet + +const devnetRpc = createSolanaRpcSubscriptions(devnet('https://api.devnet.solana.com')); +// ^? RpcSubscriptionsDevnet +``` + +#### Including Unstable Subscriptions + +If your app needs access to [unstable RPC Subscriptions](https://docs.solana.com/api/websocket#blocksubscribe) — e.g. `BlockNotificationsApi` or `SlotsUpdatesNotificationsApi` — and your RPC server supports them, you may use the `createSolanaRpcSubscriptions_UNSTABLE` and `createSolanaRpcSubscriptionsFromTransport_UNSTABLE` functions to create an RPC Subscriptions client that includes those subscriptions. + +```ts +import { + createSolanaRpcSubscriptions_UNSTABLE, + createSolanaRpcSubscriptionsFromTransport_UNSTABLE, +} from '@solana/web3.js'; + +// Using the default WebSocket transport. +const rpcSubscriptions = createSolanaRpcSubscriptions_UNSTABLE('ws://127.0.0.1:8900'); +// ^? RpcSubscriptions + +// Using a custom transport. +const transport = createDefaultRpcSubscriptionsTransport({ url: 'ws://127.0.0.1:8900' }); +const rpcSubscriptions = createSolanaRpcSubscriptionsFromTransport_UNSTABLE(transport); +// ^? RpcSubscriptions +``` + +#### Cherry-Picking API Methods + +You may constrain the scope of the Subscription API even further so you are left only with the subscriptions you need. The simplest way to do this is to cast the created RPC client to a type that only includes the methods you need. + +```ts +import { + createSolanaRpcSubscriptions, + type RpcSubscriptions, + type AccountNotificationsApi, + type SlotNotificationsApi, +} from '@solana/web3.js'; + +const rpc = createSolanaRpcSubscriptions('ws://127.0.0.1:8900') as RpcSubscriptions< + AccountNotificationsApi & SlotNotificationsApi +>; +``` + +Alternatively, you may explicitly create the RPC Subscriptions API using the `createSolanaRpcSubscriptionsApi` function. You will then need to create your own transport explicitly and bind the two together using the `createSubscriptionRpc` function. + +```ts +import { + createDefaultRpcSubscriptionsTransport, + createSubscriptionRpc, + createSolanaRpcSubscriptionsApi, + DEFAULT_RPC_CONFIG, + type AccountNotificationsApi, + type SlotNotificationsApi, +} from '@solana/web3.js'; + +const api = createSolanaRpcSubscriptionsApi(DEFAULT_RPC_CONFIG); +const transport = createDefaultRpcSubscriptionsTransport({ url: 'ws://127.0.0.1:8900' }); +const rpcSubscriptions = createSubscriptionRpc({ api, transport }); +``` + +Note that the `createSolanaRpcSubscriptionsApi` function is a wrapper on top of the `createRpcSubscriptionsApi` function which adds some Solana-specific transformers such as setting a default commitment on all methods or throwing an error when an integer overflow is detected. + +## Keys + +The new library takes a brand-new approach to Solana key pairs and addresses, which will feel quite different from the classes `PublicKey` and `Keypair` from version 1.x. + +### Web Crypto API + +All key operations now use the native Ed25519 implementation in JavaScript’s Web Crypto API. + +The API itself is designed to be a more reliably secure way to manage highly sensitive secret key information, but **developers should still use extreme caution when dealing with secret key bytes in their applications**. + +One thing to note is that many operations from Web Crypto – such as importing, generating, signing, and verifying are now **asynchronous**. + +Here’s an example of generating a `CryptoKeyPair` using the Web Crypto API and signing a message: + +```ts +import { generateKeyPair, signBytes, verifySignature } from '@solana/web3.js'; + +const keyPair: CryptoKeyPair = await generateKeyPair(); + +const message = new Uint8Array(8).fill(0); + +const signedMessage = await signBytes(keyPair.privateKey, message); +// ^? Signature + +const verified = await verifySignature(keyPair.publicKey, signedMessage, message); +``` + +### Web Crypto Polyfill + +Wherever Ed25519 is not supported, we offer a polyfill for Web Crypto’s Ed25519 API. + +This polyfill can be found at `@solana/webcrypto-ed25519-polyfill` and mimics the functionality of the Web Crypto API for Ed25519 key pairs using the same userspace implementation we used in web3.js 1.x. It does not polyfill other algorithms. + +Determine if your target runtime supports Ed25519, and install the polyfill if it does not: + +```ts +import install from '@solana/webcrypto-ed25519-polyfill'; +import { generateKeyPair, signBytes, verifySignature } from '@solana/web3.js'; + +install(); +const keyPair: CryptoKeyPair = await generateKeyPair(); + +/* Remaining logic */ +``` + +You can see where Ed25519 is currently supported in [this GitHub issue](https://github.com/WICG/webcrypto-secure-curves/issues/20) on the Web Crypto repository. Consider sniffing the user-agent when deciding whether or not to deliver the polyfill to browsers. + +Operations on `CryptoKey` objects using the Web Crypto API _or_ the polyfill are mostly handled by the `@solana/keys` package. + +### String Addresses + +All addresses are now JavaScript strings. They are represented by the opaque type `Address`, which describes exactly what a Solana address actually is. + +Consequently, that means no more `PublicKey`. + +Here’s what they look like in development: + +```ts +import { Address, address, getAddressFromPublicKey, generateKeyPair } from '@solana/web3.js'; + +// Coerce a string to an `Address` +const myOtherAddress = address('AxZfZWeqztBCL37Mkjkd4b8Hf6J13WCcfozrBY6vZzv3'); + +// Typecast it instead +const myAddress = + 'AxZfZWeqztBCL37Mkjkd4b8Hf6J13WCcfozrBY6vZzv3' as Address<'AxZfZWeqztBCL37Mkjkd4b8Hf6J13WCcfozrBY6vZzv3'>; + +// From CryptoKey +const keyPair = await generateKeyPair(); +const myPublicKeyAsAddress = await getAddressFromPublicKey(keyPair.publicKey); +``` + +Some tooling for working with base58-encoded addresses can be found in the `@solana/addresses` package. + +## Transactions + +### Creating Transaction Messages + +Like many other familiar aspects of the 1.0 library, transactions have received a makeover. + +For starters, all transaction messages are now version-aware, so there’s no longer a need to juggle two different types (eg. `Transaction` vs. `VersionedTransaction`). + +Address lookups are now completely described inside transaction message instructions, so you don’t have to materialize `addressTableLookups` anymore. + +Here’s a simple example of creating a transaction message – notice how its type is refined at each step of the process: + +```ts +import { + address, + createTransactionMessage, + setTransactionMessageFeePayer, + setTransactionMessageLifetimeUsingBlockhash, + Blockhash, +} from '@solana/web3.js'; + +const recentBlockhash = { + blockhash: '4uhcVJyU9pJkvQyS88uRDiswHXSCkY3zQawwpjk2NsNY' as Blockhash, + lastValidBlockHeight: 196055492n, +}; +const feePayer = address('AxZfZWeqztBCL37Mkjkd4b8Hf6J13WCcfozrBY6vZzv3'); + +// Create a new transaction message +const transactionMessage = createTransactionMessage({ version: 0 }); +// ^? V0TransactionMessage + +// Set the fee payer +const transactionMessageWithFeePayer = setTransactionMessageFeePayer(feePayer, transactionMessage); +// ^? V0TransactionMessage & ITransactionMessageWithFeePayer + +const transactionMessageWithFeePayerAndLifetime = setTransactionMessageLifetimeUsingBlockhash( + // ^? V0TransactionMessage & ITransactionMessageWithFeePayer & TransactionMessageWithBlockhashLifetime + recentBlockhash, + transactionMessageWithFeePayer, +); +``` + +As you can see, each time a transaction message is modified, the type reflects its new shape. If you add a fee payer, you’ll get a type representing a transaction message with a fee payer, and so on. + +Transaction message objects are also **frozen by these functions** to prevent them from being mutated in place. + +### Signing Transaction Messages + +The `signTransaction(..)` function will raise a type error if your transaction message is not already equipped with a fee payer and a lifetime. This helps you catch errors at author-time instead of runtime. + +```ts +const feePayer = address('AxZfZWeqztBCL37Mkjkd4b8Hf6J13WCcfozrBY6vZzv3'); +const signer = await generateKeyPair(); + +const transactionMessage = createTransactionMessage({ version: 'legacy' }); +const transactionMessageWithFeePayer = setTransactionMessageFeePayer(feePayer, transactionMessage); + +// Attempting to sign the transaction message without a lifetime will throw a type error +const signedTransaction = await signTransaction([signer], transactionMessageWithFeePayer); +// => "Property 'lifetimeConstraint' is missing in type" +``` + +### Calibrating a Transaction Message's Compute Unit Budget + +Correctly budgeting a compute unit limit for your transaction message can increase the probability that your transaction will be accepted for processing. If you don't declare a compute unit limit on your transaction, validators will assume an upper limit of 200K compute units (CU) per instruction. + +Since validators have an incentive to pack as many transactions into each block as possible, they may choose to include transactions that they know will fit into the remaining compute budget for the current block over transactions that might not. For this reason, you should set a compute unit limit on each of your transaction messages, whenever possible. + +Use this utility to estimate the actual compute unit cost of a given transaction message. + +```ts +import { getSetComputeUnitLimitInstruction } from '@solana-program/compute-budget'; +import { createSolanaRpc, getComputeUnitEstimateForTransactionMessageFactory, pipe } from '@solana/web3.js'; + +// Create an estimator function. +const rpc = createSolanaRpc('http://127.0.0.1:8899'); +const getComputeUnitEstimateForTransactionMessage = getComputeUnitEstimateForTransactionMessageFactory({ + rpc, +}); + +// Create your transaction message. +const transactionMessage = pipe( + createTransactionMessage({ version: 'legacy' }), + /* ... */ +); + +// Request an estimate of the actual compute units this message will consume. +const computeUnitsEstimate = await getComputeUnitEstimateForTransactionMessage(transactionMessage); + +// Set the transaction message's compute unit budget. +const transactionMessageWithComputeUnitLimit = prependTransactionMessageInstruction( + getSetComputeUnitLimitInstruction({ units: computeUnitsEstimate }), + transactionMessage, +); +``` + +> [!WARNING] +> The compute unit estimate is just that – an estimate. The compute unit consumption of the actual transaction might be higher or lower than what was observed in simulation. Unless you are confident that your particular transaction message will consume the same or fewer compute units as was estimated, you might like to augment the estimate by either a fixed number of CUs or a multiplier. + +> [!NOTE] +> If you are preparing an _unsigned_ transaction, destined to be signed and submitted to the network by a wallet, you might like to leave it up to the wallet to determine the compute unit limit. Consider that the wallet might have a more global view of how many compute units certain types of transactions consume, and might be able to make better estimates of an appropriate compute unit budget. + +### Helpers For Building Transaction Messages + +Building transaction messages in this manner might feel different from what you’re used to. Also, we certainly wouldn’t want you to have to bind transformed transaction messages to a new variable at each step, so we have released a functional programming library dubbed `@solana/functional` that lets you build transaction messages in **pipelines**. Here’s how it can be used: + +```ts +import { pipe } from '@solana/functional'; +import { + address, + createTransactionMessage, + setTransactionMessageFeePayer, + setTransactionMessageLifetimeUsingBlockhash, + Blockhash, +} from '@solana/web3.js'; + +// Use `pipe(..)` to create a pipeline of transaction message transformation operations +const transactionMessage = pipe( + createTransactionMessage({ version: 0 }), + tx => setTransactionMessageFeePayer(feePayer, tx), + tx => setTransactionMessageLifetimeUsingBlockhash(recentBlockhash, tx), +); +``` + +Note that `pipe(..)` is general-purpose, so it can be used to pipeline any functional transforms. + +## Codecs + +We have taken steps to make it easier to write data (de)serializers, especially as they pertain to Rust datatypes and byte buffers. + +Solana’s codecs libraries are broken up into modular components so you only need to import the ones you need. They are: + +- `@solana/codecs-core`: The core codecs library for working with codecs serializers and creating custom ones +- `@solana/codecs-numbers`: Used for serialization of numbers (little-endian and big-endian bytes, etc.) +- `@solana/codecs-strings`: Used for serialization of strings +- `@solana/codecs-data-structures`: Codecs and serializers for structs +- `@solana/options`: Designed to build codecs and serializers for types that mimic Rust’s enums, which can include embedded data within their variants such as values, tuples, and structs + +These packages are included in the main `@solana/web3.js` library but you may also import them from `@solana/codecs` if you only need the codecs. + +Here’s an example of encoding and decoding a custom struct with some strings and numbers: + +```ts +import { addCodecSizePrefix } from '@solana/codecs-core'; +import { getStructCodec } from '@solana/codecs-data-structures'; +import { getU32Codec, getU64Codec, getU8Codec } from '@solana/codecs-numbers'; +import { getUtf8Codec } from '@solana/codecs-strings'; + +// Equivalent in Rust: +// struct { +// amount: u64, +// decimals: u8, +// name: String, +// } +const structCodec = getStructCodec([ + ['amount', getU64Codec()], + ['decimals', getU8Codec()], + ['name', addCodecSizePrefix(getUtf8Codec(), getU32Codec())], +]); + +const myToken = { + amount: 1000000000000000n, // `bigint` or `number` is supported + decimals: 2, + name: 'My Token', +}; + +const myEncodedToken: Uint8Array = structCodec.encode(myToken); +const myDecodedToken = structCodec.decode(myEncodedToken); + +myDecodedToken satisfies { + amount: bigint; + decimals: number; + name: string; +}; +``` + +You may only need to encode or decode data, but not both. Importing one or the other allows your optimizing compiler to tree-shake the other implementation away: + +```ts +import { Codec, combineCodec, Decoder, Encoder, addDecoderSizePrefix, addEncoderSizePrefix } from '@solana/codecs-core'; +import { getStructDecoder, getStructEncoder } from '@solana/codecs-data-structures'; +import { + getU8Decoder, + getU8Encoder, + getU32Decoder, + getU32Encoder, + getU64Decoder, + getU64Encoder, +} from '@solana/codecs-numbers'; +import { getUtf8Decoder, getUtf8Encoder } from '@solana/codecs-strings'; + +export type MyToken = { + amount: bigint; + decimals: number; + name: string; +}; + +export type MyTokenArgs = { + amount: number | bigint; + decimals: number; + name: string; +}; + +export const getMyTokenEncoder = (): Encoder => + getStructEncoder([ + ['amount', getU64Encoder()], + ['decimals', getU8Encoder()], + ['name', addEncoderSizePrefix(getUtf8Encoder(), getU32Encoder())], + ]); + +export const getMyTokenDecoder = (): Decoder => + getStructDecoder([ + ['amount', getU64Decoder()], + ['decimals', getU8Decoder()], + ['name', addDecoderSizePrefix(getUtf8Decoder(), getU32Decoder())], + ]); + +export const getMyTokenCodec = (): Codec => + combineCodec(getMyTokenEncoder(), getMyTokenDecoder()); +``` + +You can read me about codecs in [the official Codec documentation](https://github.com/solana-labs/solana-web3.js/blob/master/packages/codecs/README.md). + +## Type-Safety + +The new library makes use of some advanced TypeScript features, including generic types, conditional types, `Parameters<..>`, `ReturnType<..>` and more. + +We’ve described the RPC API in detail so that TypeScript can determine the _exact_ type of the result you will receive from the server given a particular input. Change the type of the input, and you will see the return type reflect that change. + +### RPC Types + +The RPC methods – both HTTP and subscriptions – are built with multiple overloads and conditional types. The expected HTTP response payload or subscription message format will be reflected in the return type of the function you’re working with when you provide the inputs in your code. + +Here’s an example of this in action: + +```ts +// Provide one set of parameters, get a certain type +// These parameters resolve to return type: +// { +// blockhash: Blockhash; +// blockHeight: bigint; +// blockTime: UnixTimestamp; +// parentSlot: bigint; +// previousBlockhash: Blockhash; +// } +const blockResponse = await rpc + .getBlock(0n, { + rewards: false, + transactionDetails: 'none', + }) + .send(); + +// Switch `rewards` to `true`, get `rewards` in the return type +// { +// /* ... Previous response */ +// rewards: Reward[]; +// } +const blockWithRewardsResponse = await rpc + .getBlock(0n, { + rewards: true, + transactionDetails: 'none', + }) + .send(); + +// Switch `transactionDetails` to `full`, get `transactions` in the return type +// { +// /* ... Previous response */ +// transactions: TransactionResponse[]; +// } +const blockWithRewardsAndTransactionsResponse = await rpc + .getBlock(0n, { + rewards: true, + transactionDetails: 'full', + }) + .send(); +``` + +### Catching Compile-Time Bugs with TypeScript + +As previously mentioned, the type coverage in version 2.0 allows developers to catch common bugs at compile time, rather than runtime. + +In the example below, a transaction message is created and then attempted to be signed without setting the fee payer. This would result in a runtime error from the RPC, but instead you will see a type error from TypeScript as you type: + +```ts +const transactionMessage = pipe(createTransactionMessage({ version: 0 }), tx => + setTransactionMessageLifetimeUsingBlockhash(recentBlockhash, tx), +); +const signedTransaction = await signTransaction([keyPair], transactionMessage); // ERROR: Property 'feePayer' is missing in type +``` + +Consider another example where a developer is attempting to send a transaction that has not been fully signed. Again, the TypeScript compiler will throw a type error: + +```ts +const transactionMessage = pipe( + createTransactionMessage({ version: 0 }), + tx => setTransactionMessageFeePayer(feePayerAddress, tx), + tx => setTransactionMessageLifetimeUsingBlockhash(recentBlockhash, tx), +); + +const signedTransaction = await signTransaction([], transactionMessage); + +// Asserts the transaction is a `FullySignedTransaction` +// Throws an error if any signatures are missing! +assertTransactionIsFullySigned(signedTransaction); + +await sendAndConfirmTransaction(signedTransaction); +``` + +Are you building a nonce transaction and forgot to make `AdvanceNonce` the first instruction? That’s a type error: + +```ts +const feePayer = await generateKeyPair(); +const feePayerAddress = await getAddressFromPublicKey(feePayer.publicKey); + +const notNonceTransactionMessage = pipe(createTransactionMessage({ version: 0 }), tx => + setTransactionMessageFeePayer(feePayerAddress, tx), +); + +notNonceTransactionMessage satisfies TransactionMessageWithDurableNonceLifetime; +// => Property 'lifetimeConstraint' is missing in type + +const nonceConfig = { + nonce: 'nonce' as Nonce, + nonceAccountAddress: address('5tLU66bxQ35so2bReGcyf3GfMMAAauZdNA1N4uRnKQu4'), + nonceAuthorityAddress: address('GDhj8paPg8woUzp9n8fj7eAMocN5P7Ej3A7T9F5gotTX'), +}; + +const stillNotNonceTransactionMessage = { + lifetimeConstraint: nonceConfig, + ...notNonceTransactionMessage, +}; + +stillNotNonceTransactionMessage satisfies TransactionMessageWithDurableNonceLifetime; +// => 'readonly IInstruction[]' is not assignable to type 'readonly [AdvanceNonceAccountInstruction, ...IInstruction[]]' + +const validNonceTransactionMessage = pipe( + createTransactionMessage({ version: 0 }), + tx => setTransactionMessageFeePayer(feePayerAddress, tx), + tx => setTransactionMessageLifetimeUsingDurableNonce(nonceConfig, tx), // Adds the instruction! +); + +validNonceTransactionMessage satisfies TransactionMessageWithDurableNonceLifetime; // OK +``` + +The library’s type-checking can even catch you using lamports instead of SOL for a value: + +```ts +const airdropAmount = 1n; // SOL +const signature = rpc.requestAirdrop(myAddress, airdropAmount).send(); +``` + +It will force you to cast the numerical value for your airdrop (or transfer, etc.) amount using `lamports()`, which should be a good reminder! + +```ts +const airdropAmount = lamports(1000000000n); +const signature = rpc.requestAirdrop(myAddress, airdropAmount).send(); +``` + +## Compatibility Layer + +You will have noticed by now that web3.js is a complete and total breaking change from the 1.x line. We want to provide you with a strategy for interacting with 1.x APIs while building your application using 2.0. You need a tool for commuting between 1.x and 2.0 data types. + +The `@solana/compat` library allows for interoperability between functions and class objects from the legacy library - such as `VersionedTransaction`, `PublicKey`, and `Keypair` - and functions and types of the new library - such as `Address`, `Transaction`, and `CryptoKeyPair`. + +Here’s how you can use `@solana/compat` to convert from a legacy `PublicKey` to an `Address`: + +```ts +import { fromLegacyPublicKey } from '@solana/compat'; + +const publicKey = new PublicKey('B3piXWBQLLRuk56XG5VihxR4oe2PSsDM8nTF6s1DeVF5'); +const address: Address = fromLegacyPublicKey(publicKey); +``` + +Here’s how to convert from a legacy `Keypair` to a `CryptoKeyPair`: + +```ts +import { fromLegacyKeypair } from '@solana/compat'; + +const keypairLegacy = Keypair.generate(); +const cryptoKeyPair: CryptoKeyPair = fromLegacyKeypair(keypair); +``` + +Here’s how to convert legacy transaction objects to the new library’s transaction types: + +```ts +// Note that you can only convert `VersionedTransaction` objects +const modernTransaction = fromVersionedTransaction(classicTransaction); +``` + +To see more conversions supported by `@solana/compat`, you can check out the package’s [README on GitHub](https://github.com/solana-labs/solana-web3.js/blob/master/packages/compat/README.md). + +## Program Clients + +Writing JavaScript clients for on-chain programs has been done manually up until now. Without an IDL for some of the native programs, this process has been necessarily manual and has resulted in clients that lag behind the actual capabilities of the programs themselves. + +We think that program clients should be _generated_ rather than written. Developers should be able to write Rust programs, compile the program code, and generate all of the JavaScript client-side code to interact with the program. + +We use [Kinobi](https://github.com/metaplex-foundation/kinobi) to represent Solana programs and generate clients for them. This includes a JavaScript client compatible with this library. For instance, here is how you’d construct a transaction message composed of instructions from three different core programs. + +```ts +import { appendTransactionMessageInstructions, createTransactionMessage, pipe } from '@solana/web3.js'; +import { getAddMemoInstruction } from '@solana-program/memo'; +import { getSetComputeUnitLimitInstruction } from '@solana-program/compute-budget'; +import { getTransferSolInstruction } from '@solana-program/system'; + +const instructions = [ + getSetComputeUnitLimitInstruction({ units: 600_000 }), + getTransferSolInstruction({ source, destination, amount: 1_000_000_000 }), + getAddMemoInstruction({ memo: "I'm transferring some SOL!" }), +]; + +// Creates a V0 transaction message with 3 instructions inside. +const transactionMessage = pipe(createTransactionMessage({ version: 0 }), tx => + appendTransactionMessageInstructions(instructions, tx), +); +``` + +As you can see, each program now generates its own library allowing you to cherry-pick your dependencies. + +Note that asynchronous versions may be available for some instructions which allows them to resolve more inputs on your behalf — such as PDA derivation. For instance, the `CreateLookupTable` instruction offers an asynchronous builder that derives the `address` account and the `bump` argument for us. + +```ts +const rpc = createSolanaRpc('http://127.0.0.1:8899'); +const [authority, recentSlot] = await Promise.all([ + generateKeyPairSigner(), + rpc.getSlot({ commitment: 'finalized' }).send(), +]); + +const instruction = await getCreateLookupTableInstructionAsync({ + authority, + recentSlot, +}); +``` + +Alternatively, you may use the synchronous builder if you already have all the required inputs at hand. + +```ts +const [address, bump] = await findAddressLookupTablePda({ + authority: authority.address, + recentSlot, +}); + +const instruction = getCreateLookupTableInstruction({ + address, + authority, + bump, + recentSlot, +}); +``` + +On top of instruction builders, these clients offer a variety of utilities such as: + +- Instruction codecs — e.g. `getTransferSolInstructionDataCodec`. +- Account types — e.g. `AddressLookupTable`. +- Account codecs — e.g. `getAddressLookupTableAccountDataCodec`. +- Account helpers — e.g. `fetchAddressLookupTable`. +- PDA helpers — e.g. `findAddressLookupTablePda`, `fetchAddressLookupTableFromSeeds`. +- Defined types and their codecs — e.g. `NonceState`, `getNonceStateCodec`. +- Program helpers — e.g. `SYSTEM_PROGRAM_ADDRESS`, `SystemAccount` enum, `SystemAccount` enum, `identifySystemInstruction`. +- And much more! + +Here’s another example that fetches an `AddressLookupTable` PDA from its seeds. + +```ts +const account = await fetchAddressLookupTableFromSeeds(rpc, { + authority: authority.address, + recentSlot, +}); + +account.address; // Address +account.lamports; // LamportsUnsafeBeyond2Pow53Minus1 +account.data.addresses; // Address[] +account.data.authority; // Some
+account.data.deactivationSlot; // Slot +account.data.lastExtendedSlot; // Slot +account.data.lastExtendedSlotStartIndex; // number +``` + +### How Does This Work? + +All of this code is 100% auto-generated by Kinobi from a tree of standardized nodes that represent our programs. It contains obvious nodes such as `AccountNode` but also more specified nodes such as `ConditionalValueNode` that allows us to resolve account or argument default values conditionally. + +Kinobi allows us to hydrate our tree of nodes from IDLs which are typically generated by program frameworks such as [Anchor](https://github.com/coral-xyz/anchor) or [Shank](https://github.com/metaplex-foundation/shank). Additionally, visitors can be used on our nodes to expand the knowledge of our programs since the IDL itself doesn’t yet contain that level of information. Finally, special visitors called ‘renderers’ visit our tree to generate clients such as this JavaScript client. + +Currently, there is one other renderer that generates Rust clients but this is only the beginning. In the future, you can expect renderers for auto-generated Python clients, documentation, CLIs, etc. + +## Create Solana Program + +We believe the whole ecosystem could benefit from generated program clients. That’s why we introduced a new NPM binary that allows you to create your Solana program — and generate clients for it — in no time. Simply run the following and follow the prompts to get started. + +```sh +pnpm create solana-program +``` + +This [`create-solana-program`](https://github.com/solana-program/create-solana-program) installer will create a new repository including: + +- An example program using the framework of your choice (Anchor coming soon). +- Generated clients for any of the selected clients. +- A set of scripts that allows you to: + - Start a local validator including all programs and accounts you depend on. + - Build, lint and test your programs. + - Generate IDLs from your programs. + - Generate clients from the generated IDLs. + - Build and test each of your clients. +- GitHub Actions pipelines to test your program, test your clients, and even manually publish new packages or crates for your clients. (Coming soon). + +When selecting the JavaScript client, you will get a fully generated library compatible with the new web3.js much like the `@solana-program` packages showcased above. + +## GraphQL + +Though not directly related to web3.js, we wanted to hijack your attention to show you something else that we’re working on, of particular interest to frontend developers. It’s a new API for interacting with the RPC: a GraphQL API. + +The `@solana/rpc-graphql` package can be used to make GraphQL queries to Solana RPC endpoints, using the same transports described above (including any customizations). + +Here’s an example of retrieving account data with GraphQL: + +```ts +const source = ` + query myQuery($address: String!) { + account(address: $address) { + dataBase58: data(encoding: BASE_58) + dataBase64: data(encoding: BASE_64) + lamports + } + } +`; + +const variableValues = { + address: 'AyGCwnwxQMCqaU4ixReHt8h5W4dwmxU7eM3BEQBdWVca', +}; + +const result = await rpcGraphQL.query(source, variableValues); + +expect(result).toMatchObject({ + data: { + account: { + dataBase58: '2Uw1bpnsXxu3e', + dataBase64: 'dGVzdCBkYXRh', + lamports: 10290815n, + }, + }, +}); +``` + +Using GraphQL allows developers to only specify which fields they _actually_ need, and do away with the rest of the response. + +However, GraphQL is also extremely powerful for **nesting queries**, which can be particularly useful if you want to, say, get the **sum** of every lamports balance of every **owner of the owner** of each token account, while discarding any mint accounts. + +```ts +const source = ` + query getLamportsOfOwnersOfOwnersOfTokenAccounts { + programAccounts(programAddress: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA") { + ... on TokenAccount { + owner { + ownerProgram { + lamports + } + } + } + } + } +`; + +const result = await rpcGraphQL.query(source); + +const sumOfAllLamportsOfOwnersOfOwnersOfTokenAccounts = result + .map(o => o.account.owner.ownerProgram.lamports) + .reduce((acc, lamports) => acc + lamports, 0); +``` + +The new GraphQL package supports this same style of nested querying on transactions and blocks. + +```ts +const source = ` + query myQuery($signature: String!, $commitment: Commitment) { + transaction(signature: $signature, commitment: $commitment) { + message { + instructions { + ... on CreateAccountInstruction { + lamports + programId + space + } + } + } + } + } +`; + +const variableValues = { + signature: '63zkpxATgAwXRGFQZPDESTw2m4uZQ99sX338ibgKtTcgG6v34E3MSS3zckCwJHrimS71cvei6h1Bn1K1De53BNWC', + commitment: 'confirmed', +}; + +const result = await rpcGraphQL.query(source, variableValues); + +expect(result).toMatchObject({ + data: { + transaction: { + message: { + instructions: expect.arrayContaining([ + { + lamports: expect.any(BigInt), + programId: '11111111111111111111111111111111', + space: expect.any(BigInt), + }, + ]), + }, + }, + }, +}); +``` + +See more in the package’s [README on GitHub](https://github.com/solana-labs/solana-web3.js/tree/master/packages/rpc-graphql). + +## Development + +You can see all development of this library and associated GraphQL tooling in the web3.js repository on GitHub. + +- https://github.com/solana-labs/solana-web3.js + +You can follow along with program client generator development in the `@solana-program` org and the `@kinobi-so/kinobi` repository. + +- https://github.com/solana-program/ +- https://github.com/kinobi-so/kinobi + +Solana Labs develops these tools in public, as open source. We encourage any and all developers who would like to work on these tools to contribute to the codebase. + +## Thank you + +We’re grateful that you have read this far. If you are interested in migrating an existing application to the new web3.js to take advantage of some of the benefits we’ve demonstrated, we want to give you some direct support. Reach out to [@steveluscher](https://t.me/steveluscher/) on Telegram to start a conversation. diff --git a/commitlint.sh b/commitlint.sh deleted file mode 100755 index 5737efec7a00..000000000000 --- a/commitlint.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env bash -# -# Runs commitlint in the provided subdirectory -# - -set -e - -basedir=$1 -if [[ -z "$basedir" ]]; then - basedir=. -fi - -if [[ ! -d "$basedir" ]]; then - echo "Error: not a directory: $basedir" - exit 1 -fi - -if [[ ! -f "$basedir"/commitlint.config.js ]]; then - echo "Error: No commitlint configuration found" - exit 1 -fi - -if [[ -z $COMMIT_RANGE ]]; then - echo "Error: COMMIT_RANGE not defined" - exit 1 -fi - -cd "$basedir" -echo "Checking commits in COMMIT_RANGE: $COMMIT_RANGE" -while IFS= read -r line; do - echo "$line" | pnpm commitlint -done < <(git log "$COMMIT_RANGE" --format=%s -- .) diff --git a/examples/README.md b/examples/README.md index f5aab66af44a..19a14da9fd69 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,7 +1,5 @@ # Examples -These examples pertain to the 2.0 line of `@solana/web3.js`. Follow these steps to run them. - ## One-time setup Start by installing all dependencies. diff --git a/examples/deserialize-transaction/package.json b/examples/deserialize-transaction/package.json index fb1e44b865c1..5377aef3e801 100644 --- a/examples/deserialize-transaction/package.json +++ b/examples/deserialize-transaction/package.json @@ -15,7 +15,7 @@ "@solana-program/memo": "^0.4.0", "@solana-program/system": "^0.4.0", "@solana/example-utils": "workspace:*", - "@solana/web3.js": "workspace:@solana/web3.js-experimental@*" + "@solana/web3.js": "workspace:*" }, "devDependencies": { "start-server-and-test": "^2.0.4", diff --git a/examples/react-app/package.json b/examples/react-app/package.json index 7018b776c2d4..7483a0fcf9e8 100644 --- a/examples/react-app/package.json +++ b/examples/react-app/package.json @@ -18,7 +18,7 @@ "@radix-ui/themes": "^3.0.5", "@solana-program/system": "^0.4.0", "@solana/react": "workspace:*", - "@solana/web3.js": "workspace:@solana/web3.js-experimental@*", + "@solana/web3.js": "workspace:*", "@wallet-standard/core": "pre", "@wallet-standard/react": "pre", "react": "^18.3.0", diff --git a/examples/rpc-custom-api/package.json b/examples/rpc-custom-api/package.json index 24328da925f9..4098739bc3fd 100644 --- a/examples/rpc-custom-api/package.json +++ b/examples/rpc-custom-api/package.json @@ -12,7 +12,7 @@ }, "dependencies": { "@solana/example-utils": "workspace:*", - "@solana/web3.js": "workspace:@solana/web3.js-experimental@*" + "@solana/web3.js": "workspace:*" }, "devDependencies": { "tsx": "^4.16.2" diff --git a/examples/rpc-transport-throttled/package.json b/examples/rpc-transport-throttled/package.json index 80c06ae56ed3..e9abd67d9f02 100644 --- a/examples/rpc-transport-throttled/package.json +++ b/examples/rpc-transport-throttled/package.json @@ -13,7 +13,7 @@ }, "dependencies": { "@solana/example-utils": "workspace:*", - "@solana/web3.js": "workspace:@solana/web3.js-experimental@*" + "@solana/web3.js": "workspace:*" }, "devDependencies": { "start-server-and-test": "^2.0.4", diff --git a/examples/transfer-lamports/package.json b/examples/transfer-lamports/package.json index b300c9561d75..5931f507bede 100644 --- a/examples/transfer-lamports/package.json +++ b/examples/transfer-lamports/package.json @@ -14,7 +14,7 @@ "dependencies": { "@solana-program/system": "^0.4.1", "@solana/example-utils": "workspace:*", - "@solana/web3.js": "workspace:@solana/web3.js-experimental@*" + "@solana/web3.js": "workspace:*" }, "devDependencies": { "start-server-and-test": "^2.0.4", diff --git a/packages/accounts/package.json b/packages/accounts/package.json index e960768e0fbd..41ee4e44bf81 100644 --- a/packages/accounts/package.json +++ b/packages/accounts/package.json @@ -37,7 +37,7 @@ "compile:typedefs": "tsc -p ./tsconfig.declarations.json", "dev": "jest -c ../../node_modules/@solana/test-config/jest-dev.config.ts --rootDir . --watch", "prepublishOnly": "pnpm pkg delete devDependencies", - "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-preview} --access public --no-git-checks", + "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-canary} --access public --no-git-checks", "publish-packages": "pnpm prepublishOnly && pnpm publish-impl", "style:fix": "pnpm eslint --fix src/* && pnpm prettier --log-level warn --ignore-unknown --write ./*", "test:lint": "TERM_OVERRIDE=\"${TURBO_HASH:+dumb}\" TERM=${TERM_OVERRIDE:-$TERM} jest -c ../../node_modules/@solana/test-config/jest-lint.config.ts --rootDir . --silent", diff --git a/packages/addresses/package.json b/packages/addresses/package.json index b0a7144b0647..8ecb19601bd9 100644 --- a/packages/addresses/package.json +++ b/packages/addresses/package.json @@ -37,7 +37,7 @@ "compile:typedefs": "tsc -p ./tsconfig.declarations.json", "dev": "jest -c ../../node_modules/@solana/test-config/jest-dev.config.ts --rootDir . --watch", "prepublishOnly": "pnpm pkg delete devDependencies", - "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-preview} --access public --no-git-checks", + "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-canary} --access public --no-git-checks", "publish-packages": "pnpm prepublishOnly && pnpm publish-impl", "style:fix": "pnpm eslint --fix src/* && pnpm prettier --log-level warn --ignore-unknown --write ./*", "test:lint": "TERM_OVERRIDE=\"${TURBO_HASH:+dumb}\" TERM=${TERM_OVERRIDE:-$TERM} jest -c ../../node_modules/@solana/test-config/jest-lint.config.ts --rootDir . --silent", diff --git a/packages/assertions/package.json b/packages/assertions/package.json index ae6b1770aebc..8beedee9d588 100644 --- a/packages/assertions/package.json +++ b/packages/assertions/package.json @@ -37,7 +37,7 @@ "compile:typedefs": "tsc -p ./tsconfig.declarations.json", "dev": "jest -c ../../node_modules/@solana/test-config/jest-dev.config.ts --rootDir . --watch", "prepublishOnly": "pnpm pkg delete devDependencies", - "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-preview} --access public --no-git-checks", + "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-canary} --access public --no-git-checks", "publish-packages": "pnpm prepublishOnly && pnpm publish-impl", "style:fix": "pnpm eslint --fix src/* && pnpm prettier --log-level warn --ignore-unknown --write ./*", "test:lint": "TERM_OVERRIDE=\"${TURBO_HASH:+dumb}\" TERM=${TERM_OVERRIDE:-$TERM} jest -c ../../node_modules/@solana/test-config/jest-lint.config.ts --rootDir . --silent", diff --git a/packages/codecs-core/package.json b/packages/codecs-core/package.json index e6abd135960c..ed0345f59240 100644 --- a/packages/codecs-core/package.json +++ b/packages/codecs-core/package.json @@ -38,7 +38,7 @@ "compile:typedefs": "tsc -p ./tsconfig.declarations.json", "dev": "jest -c ../../node_modules/@solana/test-config/jest-dev.config.ts --rootDir . --watch", "prepublishOnly": "pnpm pkg delete devDependencies", - "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-preview} --access public --no-git-checks", + "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-canary} --access public --no-git-checks", "publish-packages": "pnpm prepublishOnly && pnpm publish-impl", "style:fix": "pnpm eslint --fix src/* && pnpm prettier --log-level warn --ignore-unknown --write ./*", "test:lint": "TERM_OVERRIDE=\"${TURBO_HASH:+dumb}\" TERM=${TERM_OVERRIDE:-$TERM} jest -c ../../node_modules/@solana/test-config/jest-lint.config.ts --rootDir . --silent", diff --git a/packages/codecs-data-structures/package.json b/packages/codecs-data-structures/package.json index 10bcad2160c1..452c8dd2c089 100644 --- a/packages/codecs-data-structures/package.json +++ b/packages/codecs-data-structures/package.json @@ -37,7 +37,7 @@ "compile:typedefs": "tsc -p ./tsconfig.declarations.json", "dev": "jest -c ../../node_modules/@solana/test-config/jest-dev.config.ts --rootDir . --watch", "prepublishOnly": "pnpm pkg delete devDependencies", - "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-preview} --access public --no-git-checks", + "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-canary} --access public --no-git-checks", "publish-packages": "pnpm prepublishOnly && pnpm publish-impl", "style:fix": "pnpm eslint --fix src/* && pnpm prettier --log-level warn --ignore-unknown --write ./*", "test:lint": "TERM_OVERRIDE=\"${TURBO_HASH:+dumb}\" TERM=${TERM_OVERRIDE:-$TERM} jest -c ../../node_modules/@solana/test-config/jest-lint.config.ts --rootDir . --silent", diff --git a/packages/codecs-numbers/package.json b/packages/codecs-numbers/package.json index c640322b89a4..b5014ee649ff 100644 --- a/packages/codecs-numbers/package.json +++ b/packages/codecs-numbers/package.json @@ -37,7 +37,7 @@ "compile:typedefs": "tsc -p ./tsconfig.declarations.json", "dev": "jest -c ../../node_modules/@solana/test-config/jest-dev.config.ts --rootDir . --watch", "prepublishOnly": "pnpm pkg delete devDependencies", - "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-preview} --access public --no-git-checks", + "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-canary} --access public --no-git-checks", "publish-packages": "pnpm prepublishOnly && pnpm publish-impl", "style:fix": "pnpm eslint --fix src/* && pnpm prettier --log-level warn --ignore-unknown --write ./*", "test:lint": "TERM_OVERRIDE=\"${TURBO_HASH:+dumb}\" TERM=${TERM_OVERRIDE:-$TERM} jest -c ../../node_modules/@solana/test-config/jest-lint.config.ts --rootDir . --silent", diff --git a/packages/codecs-strings/package.json b/packages/codecs-strings/package.json index 614cdf5127cc..7501bdd5d6fb 100644 --- a/packages/codecs-strings/package.json +++ b/packages/codecs-strings/package.json @@ -38,7 +38,7 @@ "compile:typedefs": "tsc -p ./tsconfig.declarations.json", "dev": "jest -c ../../node_modules/@solana/test-config/jest-dev.config.ts --rootDir . --watch", "prepublishOnly": "pnpm pkg delete devDependencies", - "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-preview} --access public --no-git-checks", + "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-canary} --access public --no-git-checks", "publish-packages": "pnpm prepublishOnly && pnpm publish-impl", "style:fix": "pnpm eslint --fix src/* && pnpm prettier --log-level warn --ignore-unknown --write ./*", "test:lint": "TERM_OVERRIDE=\"${TURBO_HASH:+dumb}\" TERM=${TERM_OVERRIDE:-$TERM} jest -c ../../node_modules/@solana/test-config/jest-lint.config.ts --rootDir . --silent", diff --git a/packages/codecs/package.json b/packages/codecs/package.json index cd2ebab257c6..488123dfe793 100644 --- a/packages/codecs/package.json +++ b/packages/codecs/package.json @@ -37,7 +37,7 @@ "compile:typedefs": "tsc -p ./tsconfig.declarations.json", "dev": "jest -c ../../node_modules/@solana/test-config/jest-dev.config.ts --rootDir . --watch", "prepublishOnly": "pnpm pkg delete devDependencies", - "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-preview} --access public --no-git-checks", + "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-canary} --access public --no-git-checks", "publish-packages": "pnpm prepublishOnly && pnpm publish-impl", "style:fix": "pnpm eslint --fix src/* && pnpm prettier --log-level warn --ignore-unknown --write ./*", "test:lint": "TERM_OVERRIDE=\"${TURBO_HASH:+dumb}\" TERM=${TERM_OVERRIDE:-$TERM} jest -c ../../node_modules/@solana/test-config/jest-lint.config.ts --rootDir . --silent", diff --git a/packages/compat/package.json b/packages/compat/package.json index 10d4dbf694f7..8cc6cbae3f9a 100644 --- a/packages/compat/package.json +++ b/packages/compat/package.json @@ -37,7 +37,7 @@ "compile:typedefs": "tsc -p ./tsconfig.declarations.json", "dev": "jest -c ../../node_modules/@solana/test-config/jest-dev.config.ts --rootDir . --watch", "prepublishOnly": "pnpm pkg delete devDependencies", - "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-preview} --access public --no-git-checks", + "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-canary} --access public --no-git-checks", "publish-packages": "pnpm prepublishOnly && pnpm publish-impl", "style:fix": "pnpm eslint --fix src/* && pnpm prettier --log-level warn --ignore-unknown --write ./*", "test:lint": "TERM_OVERRIDE=\"${TURBO_HASH:+dumb}\" TERM=${TERM_OVERRIDE:-$TERM} jest -c ../../node_modules/@solana/test-config/jest-lint.config.ts --rootDir . --silent", @@ -74,7 +74,7 @@ }, "devDependencies": { "@solana/keys": "workspace:*", - "@solana/web3.js": "workspace:../library-legacy" + "@solana/web3.js": "^1" }, "peerDependencies": { "typescript": ">=5" diff --git a/packages/errors/package.json b/packages/errors/package.json index 08818afc6e49..0a34593ffe63 100644 --- a/packages/errors/package.json +++ b/packages/errors/package.json @@ -38,7 +38,7 @@ "compile:typedefs": "tsc -p ./tsconfig.declarations.json", "dev": "jest -c ../../node_modules/@solana/test-config/jest-dev.config.ts --rootDir . --watch", "prepublishOnly": "pnpm pkg delete devDependencies", - "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-preview} --access public --no-git-checks", + "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-canary} --access public --no-git-checks", "publish-packages": "pnpm prepublishOnly && pnpm publish-impl", "style:fix": "pnpm eslint --fix src/* && pnpm prettier --log-level warn --ignore-unknown --write ./*", "test:lint": "TERM_OVERRIDE=\"${TURBO_HASH:+dumb}\" TERM=${TERM_OVERRIDE:-$TERM} jest -c ../../node_modules/@solana/test-config/jest-lint.config.ts --rootDir . --silent", diff --git a/packages/fast-stable-stringify/package.json b/packages/fast-stable-stringify/package.json index f23afcc464ee..1f8d427f5c0a 100644 --- a/packages/fast-stable-stringify/package.json +++ b/packages/fast-stable-stringify/package.json @@ -40,7 +40,7 @@ "compile:typedefs": "tsc -p ./tsconfig.declarations.json", "dev": "jest -c ../../node_modules/@solana/test-config/jest-dev.config.ts --rootDir . --watch", "prepublishOnly": "pnpm pkg delete devDependencies", - "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-preview} --access public --no-git-checks", + "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-canary} --access public --no-git-checks", "publish-packages": "pnpm prepublishOnly && pnpm publish-impl", "style:fix": "pnpm eslint --fix src/* && pnpm prettier --log-level warn --ignore-unknown --write ./*", "test:lint": "TERM_OVERRIDE=\"${TURBO_HASH:+dumb}\" TERM=${TERM_OVERRIDE:-$TERM} jest -c ../../node_modules/@solana/test-config/jest-lint.config.ts --rootDir . --silent", diff --git a/packages/functional/package.json b/packages/functional/package.json index eeb71292c7f4..14d85e5123a5 100644 --- a/packages/functional/package.json +++ b/packages/functional/package.json @@ -37,7 +37,7 @@ "compile:typedefs": "tsc -p ./tsconfig.declarations.json", "dev": "jest -c ../../node_modules/@solana/test-config/jest-dev.config.ts --rootDir . --watch", "prepublishOnly": "pnpm pkg delete devDependencies", - "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-preview} --access public --no-git-checks", + "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-canary} --access public --no-git-checks", "publish-packages": "pnpm prepublishOnly && pnpm publish-impl", "style:fix": "pnpm eslint --fix src/* && pnpm prettier --log-level warn --ignore-unknown --write ./*", "test:lint": "TERM_OVERRIDE=\"${TURBO_HASH:+dumb}\" TERM=${TERM_OVERRIDE:-$TERM} jest -c ../../node_modules/@solana/test-config/jest-lint.config.ts --rootDir . --silent", diff --git a/packages/instructions/package.json b/packages/instructions/package.json index 37e636cb403e..d81eee03e3af 100644 --- a/packages/instructions/package.json +++ b/packages/instructions/package.json @@ -37,7 +37,7 @@ "compile:typedefs": "tsc -p ./tsconfig.declarations.json", "dev": "jest -c ../../node_modules/@solana/test-config/jest-dev.config.ts --rootDir . --watch", "prepublishOnly": "pnpm pkg delete devDependencies", - "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-preview} --access public --no-git-checks", + "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-canary} --access public --no-git-checks", "publish-packages": "pnpm prepublishOnly && pnpm publish-impl", "style:fix": "pnpm eslint --fix src/* && pnpm prettier --log-level warn --ignore-unknown --write ./*", "test:lint": "TERM_OVERRIDE=\"${TURBO_HASH:+dumb}\" TERM=${TERM_OVERRIDE:-$TERM} jest -c ../../node_modules/@solana/test-config/jest-lint.config.ts --rootDir . --silent", diff --git a/packages/keys/package.json b/packages/keys/package.json index 917ee51ed43a..ba02dba576e4 100644 --- a/packages/keys/package.json +++ b/packages/keys/package.json @@ -38,7 +38,7 @@ "compile:typedefs": "tsc -p ./tsconfig.declarations.json", "dev": "jest -c ../../node_modules/@solana/test-config/jest-dev.config.ts --rootDir . --watch", "prepublishOnly": "pnpm pkg delete devDependencies", - "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-preview} --access public --no-git-checks", + "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-canary} --access public --no-git-checks", "publish-packages": "pnpm prepublishOnly && pnpm publish-impl", "style:fix": "pnpm eslint --fix src/* && pnpm prettier --log-level warn --ignore-unknown --write ./*", "test:lint": "TERM_OVERRIDE=\"${TURBO_HASH:+dumb}\" TERM=${TERM_OVERRIDE:-$TERM} jest -c ../../node_modules/@solana/test-config/jest-lint.config.ts --rootDir . --silent", diff --git a/packages/library-legacy/.eslintignore b/packages/library-legacy/.eslintignore deleted file mode 100644 index 55c77553897b..000000000000 --- a/packages/library-legacy/.eslintignore +++ /dev/null @@ -1,10 +0,0 @@ -.eslintrc.js -commitlint.config.js -declarations/ -deploy/ -doc/ -lib/ -rollup.config.mjs -rollup.config.types.mjs -test/.eslintrc.js -test/dist/ diff --git a/packages/library-legacy/.eslintrc.js b/packages/library-legacy/.eslintrc.js deleted file mode 100644 index e618d12f5ce8..000000000000 --- a/packages/library-legacy/.eslintrc.js +++ /dev/null @@ -1,48 +0,0 @@ -module.exports = { - env: { - browser: true, - es6: true, - node: true, - mocha: true, - }, - extends: [ - 'eslint:recommended', - 'plugin:import/errors', - 'plugin:import/warnings', - 'plugin:import/typescript', - ], - parser: '@typescript-eslint/parser', - parserOptions: { - sourceType: 'module', - ecmaVersion: 8, - }, - plugins: ['@typescript-eslint'], - root: true, - rules: { - '@typescript-eslint/no-unused-vars': ['error'], - 'import/first': ['error'], - 'import/no-commonjs': ['error'], - 'import/order': [ - 'error', - { - groups: [ - ['internal', 'external', 'builtin'], - ['index', 'sibling', 'parent'], - ], - 'newlines-between': 'always', - }, - ], - 'linebreak-style': ['error', 'unix'], - 'no-console': [0], - 'no-trailing-spaces': ['error'], - 'no-undef': 'off', - 'no-unused-vars': 'off', - quotes: [ - 'error', - 'single', - {avoidEscape: true, allowTemplateLiterals: true}, - ], - 'require-await': ['error'], - semi: ['error', 'always'], - }, -}; diff --git a/packages/library-legacy/.gitignore b/packages/library-legacy/.gitignore deleted file mode 100644 index cb4d42ac77ab..000000000000 --- a/packages/library-legacy/.gitignore +++ /dev/null @@ -1,22 +0,0 @@ -# IDE & OS specific -.DS_Store -.idea - -# Logs -logs -*.log - -# Dependencies -node_modules - -# Release -lib - -# Generated docs -doc - -# VIM swap files -*.sw* - -# TypeScript -declarations diff --git a/packages/library-legacy/.prettierignore b/packages/library-legacy/.prettierignore deleted file mode 100644 index 5fcad2e715fa..000000000000 --- a/packages/library-legacy/.prettierignore +++ /dev/null @@ -1,2 +0,0 @@ -declarations/ -lib/ diff --git a/packages/library-legacy/.prettierrc.yaml b/packages/library-legacy/.prettierrc.yaml deleted file mode 100644 index 6b4506c02499..000000000000 --- a/packages/library-legacy/.prettierrc.yaml +++ /dev/null @@ -1,6 +0,0 @@ -arrowParens: 'avoid' -bracketSpacing: false -semi: true -singleQuote: true -tabWidth: 2 -trailingComma: 'all' diff --git a/packages/library-legacy/.releaserc.json b/packages/library-legacy/.releaserc.json deleted file mode 100644 index 909539489747..000000000000 --- a/packages/library-legacy/.releaserc.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "commitPaths": ["."], - "repositoryUrl": "git@github.com:solana-labs/solana-web3.js.git", - "preset": "conventionalcommits", - "presetConfig": { - "issueUrlFormat": "{{host}}/{{owner}}/solana-web3.js/issues/{{id}}" - } -} diff --git a/packages/library-legacy/.sgcrc b/packages/library-legacy/.sgcrc deleted file mode 100644 index 05c5e7ebf8e5..000000000000 --- a/packages/library-legacy/.sgcrc +++ /dev/null @@ -1,11 +0,0 @@ -{ - "scope": true, - "body": true, - "emoji": false, - "lowercaseTypes": true, - "rules": { - "maxChar": 72, - "minChar": 10, - "endWithDot": false - } -} diff --git a/packages/library-legacy/LICENSE b/packages/library-legacy/LICENSE deleted file mode 100644 index ec09953d3c23..000000000000 --- a/packages/library-legacy/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2023 Solana Labs, Inc - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/packages/library-legacy/README.md b/packages/library-legacy/README.md deleted file mode 100644 index cecc18709178..000000000000 --- a/packages/library-legacy/README.md +++ /dev/null @@ -1,155 +0,0 @@ -[![npm][npm-image]][npm-url] -[![npm-downloads][npm-downloads-image]][npm-url] -[![semantic-release][semantic-release-image]][semantic-release-url] -
-[![code-style-prettier][code-style-prettier-image]][code-style-prettier-url] - -[code-style-prettier-image]: https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square -[code-style-prettier-url]: https://github.com/prettier/prettier -[npm-downloads-image]: https://img.shields.io/npm/dm/@solana/web3.js.svg?style=flat -[npm-image]: https://img.shields.io/npm/v/@solana/web3.js.svg?style=flat -[npm-url]: https://www.npmjs.com/package/@solana/web3.js -[semantic-release-image]: https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg -[semantic-release-url]: https://github.com/semantic-release/semantic-release - -# Solana JavaScript SDK - -Use this to interact with accounts and programs on the Solana network through the Solana [JSON RPC API](https://solana.com/docs/rpc). - -## Installation - -### For use in Node.js or a web application - -``` -$ npm install --save @solana/web3.js -``` - -### For use in a browser, without a build system - -```html - - - - - -``` - -## Documentation and examples - -- [The Solana Cookbook](https://solanacookbook.com/) has extensive task-based documentation using this library. -- For more detail on individual functions, see the [latest API Documentation](https://solana-labs.github.io/solana-web3.js) - -## Getting help - -Have a question or a problem? Check the [Solana Stack Exchange](https://solana.stackexchange.com) to see if anyone else is having the same one. If not, [post a new question](https://solana.stackexchange.com/questions/ask). - -Include: - -- A detailed description of what you're trying to achieve -- Source code, if possible -- The text of any errors you encountered, with stacktraces if available - -## Compatibility - -This library requires a JavaScript runtime that supports [`BigInt`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt) and the [exponentiation operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Exponentiation). Both are supported in the following runtimes: - -- Browsers, by [release date](https://caniuse.com/bigint): - - Chrome: May 2018 - - Firefox: July 2019 - - Safari: September 2020 - - Mobile Safari: September 2020 - - Edge: January 2020 - - Opera: June 2018 - - Samsung Internet: April 2019 -- Runtimes, [by version](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt): - - Deno: >=1.0 - - Node: >=10.4.0 -- React Native: - - \>=0.7.0 using the [Hermes](https://reactnative.dev/blog/2022/07/08/hermes-as-the-default) engine ([integration guide](https://solanacookbook.com/integrations/react-native.html#how-to-use-solana-web3-js-in-a-react-native-app)): - -## Development environment setup - -### Testing - -#### Unit tests - -To run the full suite of unit tests, execute the following in the root: - -```shell -$ npm test -``` - -#### Integration tests - -Integration tests require a validator client running on your machine. - -To install a test validator: - -```shell -$ npm run test:live-with-test-validator:setup -``` - -To start the test validator and run all of the integration tests in live mode: - -```shell -$ cd packages/library-legacy -$ npm run test:live-with-test-validator -``` - -### Speed up build times with remote caching - -Cache build artifacts remotely so that you, others, and the CI server can take advantage of each others' build efforts. - -1. Log the Turborepo CLI into the Solana Vercel account - ```shell - pnpm turbo login - ``` -2. Link the repository to the remote cache - ```shell - pnpm turbo link - ``` - -## Contributing - -If you found a bug or would like to request a feature, please [file an issue](https://github.com/solana-labs/solana-web3.js/issues/new). If, based on the discussion on an issue you would like to offer a code change, please make a [pull request](https://github.com/solana-labs/solana-web3.js/compare). If neither of these describes what you would like to contribute, read the [getting help](#getting-help) section above. - -## Disclaimer - -All claims, content, designs, algorithms, estimates, roadmaps, -specifications, and performance measurements described in this project -are done with the Solana Foundation's ("SF") best efforts. It is up to -the reader to check and validate their accuracy and truthfulness. -Furthermore nothing in this project constitutes a solicitation for -investment. - -Any content produced by SF or developer resources that SF provides, are -for educational and inspiration purposes only. SF does not encourage, -induce or sanction the deployment, integration or use of any such -applications (including the code comprising the Solana blockchain -protocol) in violation of applicable laws or regulations and hereby -prohibits any such deployment, integration or use. This includes use of -any such applications by the reader (a) in violation of export control -or sanctions laws of the United States or any other applicable -jurisdiction, (b) if the reader is located in or ordinarily resident in -a country or territory subject to comprehensive sanctions administered -by the U.S. Office of Foreign Assets Control (OFAC), or (c) if the -reader is or is working on behalf of a Specially Designated National -(SDN) or a person subject to similar blocking or denied party -prohibitions. - -The reader should be aware that U.S. export control and sanctions laws -prohibit U.S. persons (and other persons that are subject to such laws) -from transacting with persons in certain countries and territories or -that are on the SDN list. As a project based primarily on open-source -software, it is possible that such sanctioned persons may nevertheless -bypass prohibitions, obtain the code comprising the Solana blockchain -protocol (or other project code or applications) and deploy, integrate, -or otherwise use it. Accordingly, there is a risk to individuals that -other persons using the Solana blockchain protocol may be sanctioned -persons and that transactions with such persons would be a violation of -U.S. export controls and sanctions law. This risk applies to -individuals, organizations, and other ecosystem participants that -deploy, integrate, or use the Solana blockchain protocol code directly -(e.g., as a node operator), and individuals that transact on the Solana -blockchain through light clients, third party interfaces, and/or wallet -software. diff --git a/packages/library-legacy/babel.config.json b/packages/library-legacy/babel.config.json deleted file mode 100644 index 98ea5c2cafad..000000000000 --- a/packages/library-legacy/babel.config.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "presets": [ - [ - "@babel/preset-env", - { - "bugfixes": true - } - ], - ["@babel/preset-typescript"] - ], - "plugins": [ - [ - "@babel/plugin-transform-class-properties", - { - "loose": true - } - ], - [ - "@babel/plugin-transform-private-methods", - { - "loose": true - } - ], - [ - "@babel/plugin-transform-private-property-in-object", - { - "loose": true - } - ] - ] -} diff --git a/packages/library-legacy/commitlint.config.js b/packages/library-legacy/commitlint.config.js deleted file mode 100644 index 0256ca499a66..000000000000 --- a/packages/library-legacy/commitlint.config.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - extends: ['@commitlint/config-conventional'], - rules: { - 'header-max-length': [0, 'always', Infinity], - }, -}; diff --git a/packages/library-legacy/package.json b/packages/library-legacy/package.json deleted file mode 100644 index 8ffd5b581661..000000000000 --- a/packages/library-legacy/package.json +++ /dev/null @@ -1,125 +0,0 @@ -{ - "name": "@solana/web3.js", - "version": "0.0.0-development", - "description": "Solana Javascript API", - "keywords": [ - "api", - "blockchain" - ], - "license": "MIT", - "author": "Solana Labs Maintainers ", - "homepage": "https://solana.com/", - "repository": { - "type": "git", - "url": "https://github.com/solana-labs/solana-web3.js.git" - }, - "bugs": { - "url": "http://github.com/solana-labs/solana-web3.js.git/issues" - }, - "publishConfig": { - "access": "public" - }, - "browser": { - "./lib/index.cjs.js": "./lib/index.browser.cjs.js", - "./lib/index.esm.js": "./lib/index.browser.esm.js" - }, - "react-native": "lib/index.native.js", - "main": "lib/index.cjs.js", - "module": "lib/index.esm.js", - "types": "lib/index.d.ts", - "browserslist": [ - "defaults", - "not IE 11", - "maintained node versions" - ], - "files": [ - "/lib", - "/src" - ], - "scripts": { - "compile:docs": "typedoc --treatWarningsAsErrors", - "compile:js": "cross-env NODE_ENV=production rollup -c", - "compile:typedefs": "./scripts/typegen.sh", - "build:fixtures": "set -ex; ./test/fixtures/noop-program/build.sh", - "clean": "rimraf ./doc ./declarations ./lib", - "dev": "cross-env NODE_ENV=development rollup -c --watch", - "prepublishOnly": "pnpm pkg delete devDependencies", - "publish-packages-legacy": "semantic-release --repository-url git@github.com:solana-labs/solana-web3.js.git", - "test:lint": "eslint src/ test/ --ext .js,.ts", - "test:lint:fix": "eslint src/ test/ --fix --ext .js,.ts", - "test:live": "TEST_LIVE=1 pnpm run test:unit:node", - "test:live-with-test-validator": "start-server-and-test '../../scripts/start-shared-test-validator.sh' http://127.0.0.1:8899/health test:live", - "test:prettier": "prettier --check '{,{src,test}/**/}*.{j,t}s'", - "test:prettier:fix": "pnpm prettier --write '{,{src,test}/**/}*.{j,t}s'", - "test:typecheck": "tsc --noEmit", - "test:unit:node": "cross-env NODE_ENV=test NODE_OPTIONS='--import tsx' mocha './test/**/*.test.ts'" - }, - "dependencies": { - "@babel/runtime": "^7.25.0", - "@noble/curves": "^1.4.2", - "@noble/hashes": "^1.4.0", - "@solana/buffer-layout": "^4.0.1", - "agentkeepalive": "^4.5.0", - "bigint-buffer": "^1.1.5", - "bn.js": "^5.2.1", - "borsh": "^0.7.0", - "bs58": "^4.0.1", - "buffer": "6.0.3", - "fast-stable-stringify": "^1.0.0", - "jayson": "^4.1.1", - "node-fetch": "^2.7.0", - "rpc-websockets": "^9.0.2", - "superstruct": "^2.0.2" - }, - "devDependencies": { - "@babel/core": "^7.24.9", - "@babel/plugin-transform-class-properties": "^7.24.7", - "@babel/plugin-transform-private-methods": "^7.24.7", - "@babel/plugin-transform-private-property-in-object": "^7.24.7", - "@babel/plugin-transform-runtime": "^7.24.7", - "@babel/preset-env": "^7.25.0", - "@babel/preset-typescript": "^7.24.7", - "@commitlint/config-conventional": "^19.2.2", - "@rollup/plugin-alias": "^5.1.0", - "@rollup/plugin-babel": "^6.0.4", - "@rollup/plugin-commonjs": "^26.0.1", - "@rollup/plugin-json": "^6.1.0", - "@rollup/plugin-node-resolve": "^15.2.3", - "@rollup/plugin-replace": "^5.0.7", - "@rollup/plugin-terser": "^0.4.4", - "@types/bn.js": "^5.1.5", - "@types/bs58": "^4.0.1", - "@types/chai-as-promised": "^7.1.8", - "@types/express-serve-static-core": "^4.19.5", - "@types/mocha": "^10.0.6", - "@types/mz": "^2.7.4", - "@types/node-fetch": "2", - "@types/sinon": "^17.0.3", - "@types/sinon-chai": "^3.2.12", - "chai": "^5.1.1", - "chai-as-promised": "^8.0.0", - "commitlint": "^19.3.0", - "cross-env": "7.0.3", - "eslint-config-prettier": "^9.1.0", - "eslint-plugin-import": "^2.29.0", - "eslint-plugin-mocha": "^10.4.3", - "eslint-plugin-prettier": "^5.2.1", - "esm": "^3.2.25", - "mocha": "^10.4.0", - "mockttp": "^3.15.0", - "mz": "^2.7.0", - "node-abort-controller": "^3.0.1", - "prettier": "^3.3", - "rimraf": "6.0.1", - "rollup": "^4.19.0", - "rollup-plugin-dts": "^6.1.1", - "rollup-plugin-node-polyfills": "^0.2.1", - "semantic-release": "^24.0.0", - "sinon": "^18.0.0", - "sinon-chai": "^4.0.0", - "start-server-and-test": "^2.0.4", - "tslib": "^2.6.3", - "tsx": "^4.16.2", - "typedoc": "^0.26.5" - } -} diff --git a/packages/library-legacy/rollup.config.mjs b/packages/library-legacy/rollup.config.mjs deleted file mode 100644 index d00b589ab7f6..000000000000 --- a/packages/library-legacy/rollup.config.mjs +++ /dev/null @@ -1,215 +0,0 @@ -import alias from '@rollup/plugin-alias'; -import babel from '@rollup/plugin-babel'; -import commonjs from '@rollup/plugin-commonjs'; -import * as fs from 'fs'; -import path from 'path'; -import nodeResolve from '@rollup/plugin-node-resolve'; -import replace from '@rollup/plugin-replace'; -import terser from '@rollup/plugin-terser'; - -const env = process.env.NODE_ENV; -const extensions = ['.js', '.ts']; - -function generateConfig(configType, format) { - const browser = configType === 'browser' || configType === 'react-native'; - const bundle = format === 'iife'; - - const config = { - input: 'src/index.ts', - plugins: [ - alias({ - entries: [ - { - find: /^\./, // Relative paths. - replacement: '.', - async customResolver(source, importer, options) { - const resolved = await this.resolve(source, importer, { - skipSelf: true, - ...options, - }); - if (resolved == null) { - return; - } - const {id: resolvedId} = resolved; - const directory = path.dirname(resolvedId); - const moduleFilename = path.basename(resolvedId); - const forkPath = path.join( - directory, - '__forks__', - configType, - moduleFilename, - ); - const hasForkCacheKey = `has_fork:${forkPath}`; - let hasFork = this.cache.get(hasForkCacheKey); - if (hasFork === undefined) { - hasFork = fs.existsSync(forkPath); - this.cache.set(hasForkCacheKey, hasFork); - } - if (hasFork) { - return forkPath; - } - }, - }, - ], - }), - commonjs(), - nodeResolve({ - browser, - dedupe: ['bn.js', 'buffer'], - extensions, - preferBuiltins: !browser, - }), - babel({ - exclude: '**/node_modules/**', - extensions, - babelHelpers: bundle ? 'bundled' : 'runtime', - plugins: bundle ? [] : ['@babel/plugin-transform-runtime'], - }), - replace({ - preventAssignment: true, - values: { - 'process.env.NODE_ENV': JSON.stringify(env), - 'process.env.BROWSER': JSON.stringify(browser), - 'process.env.TEST_LIVE': JSON.stringify(false), - 'process.env.npm_package_version': JSON.stringify( - process.env.npm_package_version, - ), - }, - }), - ], - onwarn: function (warning, rollupWarn) { - rollupWarn(warning); - if (warning.code === 'CIRCULAR_DEPENDENCY') { - throw new Error( - 'Please eliminate the circular dependencies listed ' + - 'above and retry the build', - ); - } - }, - treeshake: { - moduleSideEffects: false, - }, - }; - - if (!browser) { - // Prevent dependencies from being bundled - config.external = [ - /@babel\/runtime/, - '@noble/curves/secp256k1', - '@noble/curves/ed25519', - '@noble/hashes/sha256', - '@noble/hashes/sha3', - '@noble/secp256k1', - '@solana/buffer-layout', - 'bigint-buffer', - 'bn.js', - 'borsh', - 'bs58', - 'buffer', - 'crypto-hash', - 'jayson/lib/client/browser', - 'node-fetch', - 'rpc-websockets', - 'superstruct', - ]; - } - - switch (configType) { - case 'browser': - case 'react-native': - switch (format) { - case 'iife': { - config.external = ['http', 'https', 'node-fetch']; - - config.output = [ - { - file: 'lib/index.iife.js', - format: 'iife', - name: 'solanaWeb3', - sourcemap: true, - }, - { - file: 'lib/index.iife.min.js', - format: 'iife', - name: 'solanaWeb3', - sourcemap: true, - plugins: [terser({mangle: false, compress: false})], - }, - ]; - - break; - } - default: { - config.output = [ - { - file: `lib/index.${ - configType === 'react-native' ? 'native' : 'browser.cjs' - }.js`, - format: 'cjs', - interop: 'compat', - sourcemap: true, - }, - configType === 'browser' - ? { - file: 'lib/index.browser.esm.js', - format: 'es', - sourcemap: true, - } - : null, - ].filter(Boolean); - - // Prevent dependencies from being bundled - config.external = [ - /@babel\/runtime/, - '@solana/buffer-layout', - '@noble/curves/secp256k1', - '@noble/curves/ed25519', - '@noble/hashes/sha256', - '@noble/hashes/sha3', - 'bigint-buffer', - 'bn.js', - 'borsh', - 'bs58', - 'buffer', - 'crypto-hash', - 'http', - 'https', - 'jayson/lib/client/browser', - 'node-fetch', - 'react-native-url-polyfill', - 'rpc-websockets', - 'superstruct', - ]; - - break; - } - } - break; - case 'node': - config.output = [ - { - file: 'lib/index.cjs.js', - format: 'cjs', - interop: 'compat', - sourcemap: true, - }, - { - file: 'lib/index.esm.js', - format: 'es', - sourcemap: true, - }, - ]; - break; - default: - throw new Error(`Unknown configType: ${configType}`); - } - - return config; -} - -export default [ - generateConfig('node'), - generateConfig('browser'), - generateConfig('browser', 'iife'), - generateConfig('react-native'), -]; diff --git a/packages/library-legacy/rollup.config.types.mjs b/packages/library-legacy/rollup.config.types.mjs deleted file mode 100644 index e1cb2d567e8f..000000000000 --- a/packages/library-legacy/rollup.config.types.mjs +++ /dev/null @@ -1,8 +0,0 @@ -import dts from 'rollup-plugin-dts'; - -export default { - input: './declarations/index.d.ts', - output: [{file: 'lib/index.d.ts', format: 'es'}], - plugins: [dts()], - external: ['http', 'https'], -}; diff --git a/packages/library-legacy/scripts/typegen.sh b/packages/library-legacy/scripts/typegen.sh deleted file mode 100755 index 59383a536e29..000000000000 --- a/packages/library-legacy/scripts/typegen.sh +++ /dev/null @@ -1,10 +0,0 @@ -set -e - -# Generate typescript declarations -pnpm tsc -p tsconfig.d.json -d - -# Flatten typescript declarations -pnpm rollup -c rollup.config.types.mjs - -# Run prettier -pnpm prettier --write lib/index.d.ts diff --git a/packages/library-legacy/src/__forks__/browser/fetch-impl.ts b/packages/library-legacy/src/__forks__/browser/fetch-impl.ts deleted file mode 100644 index 4eb813f237e8..000000000000 --- a/packages/library-legacy/src/__forks__/browser/fetch-impl.ts +++ /dev/null @@ -1,4 +0,0 @@ -export const Headers: typeof globalThis.Headers = globalThis.Headers; -export const Request: typeof globalThis.Request = globalThis.Request; -export const Response: typeof globalThis.Response = globalThis.Response; -export default globalThis.fetch; diff --git a/packages/library-legacy/src/__forks__/react-native/fetch-impl.ts b/packages/library-legacy/src/__forks__/react-native/fetch-impl.ts deleted file mode 100644 index 4eb813f237e8..000000000000 --- a/packages/library-legacy/src/__forks__/react-native/fetch-impl.ts +++ /dev/null @@ -1,4 +0,0 @@ -export const Headers: typeof globalThis.Headers = globalThis.Headers; -export const Request: typeof globalThis.Request = globalThis.Request; -export const Response: typeof globalThis.Response = globalThis.Response; -export default globalThis.fetch; diff --git a/packages/library-legacy/src/account-data.ts b/packages/library-legacy/src/account-data.ts deleted file mode 100644 index a61d695c6418..000000000000 --- a/packages/library-legacy/src/account-data.ts +++ /dev/null @@ -1,39 +0,0 @@ -import * as BufferLayout from '@solana/buffer-layout'; - -export interface IAccountStateData { - readonly typeIndex: number; -} - -/** - * @internal - */ -export type AccountType = { - /** The account type index (from solana upstream program) */ - index: number; - /** The BufferLayout to use to build data */ - layout: BufferLayout.Layout; -}; - -/** - * Decode account data buffer using an AccountType - * @internal - */ -export function decodeData( - type: AccountType, - data: Uint8Array, -): TAccountStateData { - let decoded: TAccountStateData; - try { - decoded = type.layout.decode(data); - } catch (err) { - throw new Error('invalid instruction; ' + err); - } - - if (decoded.typeIndex !== type.index) { - throw new Error( - `invalid account data; account type mismatch ${decoded.typeIndex} != ${type.index}`, - ); - } - - return decoded; -} diff --git a/packages/library-legacy/src/account.ts b/packages/library-legacy/src/account.ts deleted file mode 100644 index c2a4e02fe7e6..000000000000 --- a/packages/library-legacy/src/account.ts +++ /dev/null @@ -1,55 +0,0 @@ -import {Buffer} from 'buffer'; - -import {generatePrivateKey, getPublicKey} from './utils/ed25519'; -import {toBuffer} from './utils/to-buffer'; -import {PublicKey} from './publickey'; - -/** - * An account key pair (public and secret keys). - * - * @deprecated since v1.10.0, please use {@link Keypair} instead. - */ -export class Account { - /** @internal */ - private _publicKey: Buffer; - /** @internal */ - private _secretKey: Buffer; - - /** - * Create a new Account object - * - * If the secretKey parameter is not provided a new key pair is randomly - * created for the account - * - * @param secretKey Secret key for the account - */ - constructor(secretKey?: Uint8Array | Array) { - if (secretKey) { - const secretKeyBuffer = toBuffer(secretKey); - if (secretKey.length !== 64) { - throw new Error('bad secret key size'); - } - this._publicKey = secretKeyBuffer.slice(32, 64); - this._secretKey = secretKeyBuffer.slice(0, 32); - } else { - this._secretKey = toBuffer(generatePrivateKey()); - this._publicKey = toBuffer(getPublicKey(this._secretKey)); - } - } - - /** - * The public key for this account - */ - get publicKey(): PublicKey { - return new PublicKey(this._publicKey); - } - - /** - * The **unencrypted** secret key for this account. The first 32 bytes - * is the private scalar and the last 32 bytes is the public key. - * Read more: https://blog.mozilla.org/warner/2011/11/29/ed25519-keys/ - */ - get secretKey(): Buffer { - return Buffer.concat([this._secretKey, this._publicKey], 64); - } -} diff --git a/packages/library-legacy/src/blockhash.ts b/packages/library-legacy/src/blockhash.ts deleted file mode 100644 index 40ee40667c16..000000000000 --- a/packages/library-legacy/src/blockhash.ts +++ /dev/null @@ -1,4 +0,0 @@ -/** - * Blockhash as Base58 string. - */ -export type Blockhash = string; diff --git a/packages/library-legacy/src/bpf-loader-deprecated.ts b/packages/library-legacy/src/bpf-loader-deprecated.ts deleted file mode 100644 index b1735dd495b0..000000000000 --- a/packages/library-legacy/src/bpf-loader-deprecated.ts +++ /dev/null @@ -1,5 +0,0 @@ -import {PublicKey} from './publickey'; - -export const BPF_LOADER_DEPRECATED_PROGRAM_ID = new PublicKey( - 'BPFLoader1111111111111111111111111111111111', -); diff --git a/packages/library-legacy/src/bpf-loader.ts b/packages/library-legacy/src/bpf-loader.ts deleted file mode 100644 index 972d08657cce..000000000000 --- a/packages/library-legacy/src/bpf-loader.ts +++ /dev/null @@ -1,50 +0,0 @@ -import type {Buffer} from 'buffer'; - -import {PublicKey} from './publickey'; -import {Loader} from './loader'; -import type {Connection} from './connection'; -import type {Signer} from './keypair'; - -/** - * @deprecated Deprecated since Solana v1.17.20. - */ -export const BPF_LOADER_PROGRAM_ID = new PublicKey( - 'BPFLoader2111111111111111111111111111111111', -); - -/** - * Factory class for transactions to interact with a program loader - * - * @deprecated Deprecated since Solana v1.17.20. - */ -export class BpfLoader { - /** - * Minimum number of signatures required to load a program not including - * retries - * - * Can be used to calculate transaction fees - */ - static getMinNumSignatures(dataLength: number): number { - return Loader.getMinNumSignatures(dataLength); - } - - /** - * Load a SBF program - * - * @param connection The connection to use - * @param payer Account that will pay program loading fees - * @param program Account to load the program into - * @param elf The entire ELF containing the SBF program - * @param loaderProgramId The program id of the BPF loader to use - * @return true if program was loaded successfully, false if program was already loaded - */ - static load( - connection: Connection, - payer: Signer, - program: Signer, - elf: Buffer | Uint8Array | Array, - loaderProgramId: PublicKey, - ): Promise { - return Loader.load(connection, payer, program, loaderProgramId, elf); - } -} diff --git a/packages/library-legacy/src/connection.ts b/packages/library-legacy/src/connection.ts deleted file mode 100644 index 1f97a19322dd..000000000000 --- a/packages/library-legacy/src/connection.ts +++ /dev/null @@ -1,6951 +0,0 @@ -import HttpKeepAliveAgent, { - HttpsAgent as HttpsKeepAliveAgent, -} from 'agentkeepalive'; -import bs58 from 'bs58'; -import {Buffer} from 'buffer'; -// @ts-ignore -import fastStableStringify from 'fast-stable-stringify'; -import type {Agent as NodeHttpAgent} from 'http'; -import {Agent as NodeHttpsAgent} from 'https'; -import { - type as pick, - number, - string, - array, - boolean, - literal, - record, - union, - optional, - nullable, - coerce, - instance, - create, - tuple, - unknown, - any, -} from 'superstruct'; -import type {Struct} from 'superstruct'; -import RpcClient from 'jayson/lib/client/browser'; -import {JSONRPCError} from 'jayson'; - -import {EpochSchedule} from './epoch-schedule'; -import {SendTransactionError, SolanaJSONRPCError} from './errors'; -import fetchImpl from './fetch-impl'; -import {DurableNonce, NonceAccount} from './nonce-account'; -import {PublicKey} from './publickey'; -import {Signer} from './keypair'; -import RpcWebSocketClient from './rpc-websocket'; -import {MS_PER_SLOT} from './timing'; -import { - Transaction, - TransactionStatus, - TransactionVersion, - VersionedTransaction, -} from './transaction'; -import {Message, MessageHeader, MessageV0, VersionedMessage} from './message'; -import {AddressLookupTableAccount} from './programs/address-lookup-table/state'; -import assert from './utils/assert'; -import {sleep} from './utils/sleep'; -import {toBuffer} from './utils/to-buffer'; -import { - TransactionExpiredBlockheightExceededError, - TransactionExpiredNonceInvalidError, - TransactionExpiredTimeoutError, -} from './transaction/expiry-custom-errors'; -import {makeWebsocketUrl} from './utils/makeWebsocketUrl'; -import type {Blockhash} from './blockhash'; -import type {FeeCalculator} from './fee-calculator'; -import type {TransactionSignature} from './transaction'; -import type {CompiledInstruction} from './message'; - -const PublicKeyFromString = coerce( - instance(PublicKey), - string(), - value => new PublicKey(value), -); - -const RawAccountDataResult = tuple([string(), literal('base64')]); - -const BufferFromRawAccountData = coerce( - instance(Buffer), - RawAccountDataResult, - value => Buffer.from(value[0], 'base64'), -); - -/** - * Attempt to use a recent blockhash for up to 30 seconds - * @internal - */ -export const BLOCKHASH_CACHE_TIMEOUT_MS = 30 * 1000; - -/** - * HACK. - * Copied from rpc-websockets/dist/lib/client. - * Otherwise, `yarn build` fails with: - * https://gist.github.com/steveluscher/c057eca81d479ef705cdb53162f9971d - */ -interface IWSRequestParams { - [x: string]: any; - [x: number]: any; -} - -type ClientSubscriptionId = number; -/** @internal */ type ServerSubscriptionId = number; -/** @internal */ type SubscriptionConfigHash = string; -/** @internal */ type SubscriptionDisposeFn = () => Promise; -/** @internal */ type SubscriptionStateChangeCallback = ( - nextState: StatefulSubscription['state'], -) => void; -/** @internal */ type SubscriptionStateChangeDisposeFn = () => void; -/** - * @internal - * Every subscription contains the args used to open the subscription with - * the server, and a list of callers interested in notifications. - */ -type BaseSubscription = Readonly<{ - args: IWSRequestParams; - callbacks: Set['callback']>; -}>; -/** - * @internal - * A subscription may be in various states of connectedness. Only when it is - * fully connected will it have a server subscription id associated with it. - * This id can be returned to the server to unsubscribe the client entirely. - */ -type StatefulSubscription = Readonly< - // New subscriptions that have not yet been - // sent to the server start in this state. - | { - state: 'pending'; - } - // These subscriptions have been sent to the server - // and are waiting for the server to acknowledge them. - | { - state: 'subscribing'; - } - // These subscriptions have been acknowledged by the - // server and have been assigned server subscription ids. - | { - serverSubscriptionId: ServerSubscriptionId; - state: 'subscribed'; - } - // These subscriptions are intended to be torn down and - // are waiting on an acknowledgement from the server. - | { - serverSubscriptionId: ServerSubscriptionId; - state: 'unsubscribing'; - } - // The request to tear down these subscriptions has been - // acknowledged by the server. The `serverSubscriptionId` - // is the id of the now-dead subscription. - | { - serverSubscriptionId: ServerSubscriptionId; - state: 'unsubscribed'; - } ->; -/** - * A type that encapsulates a subscription's RPC method - * names and notification (callback) signature. - */ -type SubscriptionConfig = Readonly< - | { - callback: AccountChangeCallback; - method: 'accountSubscribe'; - unsubscribeMethod: 'accountUnsubscribe'; - } - | { - callback: LogsCallback; - method: 'logsSubscribe'; - unsubscribeMethod: 'logsUnsubscribe'; - } - | { - callback: ProgramAccountChangeCallback; - method: 'programSubscribe'; - unsubscribeMethod: 'programUnsubscribe'; - } - | { - callback: RootChangeCallback; - method: 'rootSubscribe'; - unsubscribeMethod: 'rootUnsubscribe'; - } - | { - callback: SignatureSubscriptionCallback; - method: 'signatureSubscribe'; - unsubscribeMethod: 'signatureUnsubscribe'; - } - | { - callback: SlotChangeCallback; - method: 'slotSubscribe'; - unsubscribeMethod: 'slotUnsubscribe'; - } - | { - callback: SlotUpdateCallback; - method: 'slotsUpdatesSubscribe'; - unsubscribeMethod: 'slotsUpdatesUnsubscribe'; - } ->; -/** - * @internal - * Utility type that keeps tagged unions intact while omitting properties. - */ -type DistributiveOmit = T extends unknown - ? Omit - : never; -/** - * @internal - * This type represents a single subscribable 'topic.' It's made up of: - * - * - The args used to open the subscription with the server, - * - The state of the subscription, in terms of its connectedness, and - * - The set of callbacks to call when the server publishes notifications - * - * This record gets indexed by `SubscriptionConfigHash` and is used to - * set up subscriptions, fan out notifications, and track subscription state. - */ -type Subscription = BaseSubscription & - StatefulSubscription & - DistributiveOmit; - -type RpcRequest = (methodName: string, args: Array) => Promise; - -type RpcBatchRequest = (requests: RpcParams[]) => Promise; - -/** - * @internal - */ -export type RpcParams = { - methodName: string; - args: Array; -}; - -export type TokenAccountsFilter = - | { - mint: PublicKey; - } - | { - programId: PublicKey; - }; - -/** - * Extra contextual information for RPC responses - */ -export type Context = { - slot: number; -}; - -/** - * Options for sending transactions - */ -export type SendOptions = { - /** disable transaction verification step */ - skipPreflight?: boolean; - /** preflight commitment level */ - preflightCommitment?: Commitment; - /** Maximum number of times for the RPC node to retry sending the transaction to the leader. */ - maxRetries?: number; - /** The minimum slot that the request can be evaluated at */ - minContextSlot?: number; -}; - -/** - * Options for confirming transactions - */ -export type ConfirmOptions = { - /** disable transaction verification step */ - skipPreflight?: boolean; - /** desired commitment level */ - commitment?: Commitment; - /** preflight commitment level */ - preflightCommitment?: Commitment; - /** Maximum number of times for the RPC node to retry sending the transaction to the leader. */ - maxRetries?: number; - /** The minimum slot that the request can be evaluated at */ - minContextSlot?: number; -}; - -/** - * Options for getConfirmedSignaturesForAddress2 - */ -export type ConfirmedSignaturesForAddress2Options = { - /** - * Start searching backwards from this transaction signature. - * @remarks If not provided the search starts from the highest max confirmed block. - */ - before?: TransactionSignature; - /** Search until this transaction signature is reached, if found before `limit`. */ - until?: TransactionSignature; - /** Maximum transaction signatures to return (between 1 and 1,000, default: 1,000). */ - limit?: number; -}; - -/** - * Options for getSignaturesForAddress - */ -export type SignaturesForAddressOptions = { - /** - * Start searching backwards from this transaction signature. - * @remarks If not provided the search starts from the highest max confirmed block. - */ - before?: TransactionSignature; - /** Search until this transaction signature is reached, if found before `limit`. */ - until?: TransactionSignature; - /** Maximum transaction signatures to return (between 1 and 1,000, default: 1,000). */ - limit?: number; - /** The minimum slot that the request can be evaluated at */ - minContextSlot?: number; -}; - -/** - * RPC Response with extra contextual information - */ -export type RpcResponseAndContext = { - /** response context */ - context: Context; - /** response value */ - value: T; -}; - -export type BlockhashWithExpiryBlockHeight = Readonly<{ - blockhash: Blockhash; - lastValidBlockHeight: number; -}>; - -/** - * A strategy for confirming transactions that uses the last valid - * block height for a given blockhash to check for transaction expiration. - */ -export type BlockheightBasedTransactionConfirmationStrategy = - BaseTransactionConfirmationStrategy & BlockhashWithExpiryBlockHeight; - -/** - * A strategy for confirming durable nonce transactions. - */ -export type DurableNonceTransactionConfirmationStrategy = - BaseTransactionConfirmationStrategy & { - /** - * The lowest slot at which to fetch the nonce value from the - * nonce account. This should be no lower than the slot at - * which the last-known value of the nonce was fetched. - */ - minContextSlot: number; - /** - * The account where the current value of the nonce is stored. - */ - nonceAccountPubkey: PublicKey; - /** - * The nonce value that was used to sign the transaction - * for which confirmation is being sought. - */ - nonceValue: DurableNonce; - }; - -/** - * Properties shared by all transaction confirmation strategies - */ -export type BaseTransactionConfirmationStrategy = Readonly<{ - /** A signal that, when aborted, cancels any outstanding transaction confirmation operations */ - abortSignal?: AbortSignal; - signature: TransactionSignature; -}>; - -/** - * This type represents all transaction confirmation strategies - */ -export type TransactionConfirmationStrategy = - | BlockheightBasedTransactionConfirmationStrategy - | DurableNonceTransactionConfirmationStrategy; - -/* @internal */ -function assertEndpointUrl(putativeUrl: string) { - if (/^https?:/.test(putativeUrl) === false) { - throw new TypeError('Endpoint URL must start with `http:` or `https:`.'); - } - return putativeUrl; -} - -/** @internal */ -function extractCommitmentFromConfig( - commitmentOrConfig?: Commitment | ({commitment?: Commitment} & TConfig), -) { - let commitment: Commitment | undefined; - let config: Omit | undefined; - if (typeof commitmentOrConfig === 'string') { - commitment = commitmentOrConfig; - } else if (commitmentOrConfig) { - const {commitment: specifiedCommitment, ...specifiedConfig} = - commitmentOrConfig; - commitment = specifiedCommitment; - config = specifiedConfig; - } - return {commitment, config}; -} - -/** - * @internal - */ -function applyDefaultMemcmpEncodingToFilters( - filters: GetProgramAccountsFilter[], -): GetProgramAccountsFilter[] { - return filters.map(filter => - 'memcmp' in filter - ? { - ...filter, - memcmp: { - ...filter.memcmp, - encoding: filter.memcmp.encoding ?? 'base58', - }, - } - : filter, - ); -} - -/** - * @internal - */ -function createRpcResult(result: Struct) { - return union([ - pick({ - jsonrpc: literal('2.0'), - id: string(), - result, - }), - pick({ - jsonrpc: literal('2.0'), - id: string(), - error: pick({ - code: unknown(), - message: string(), - data: optional(any()), - }), - }), - ]); -} - -const UnknownRpcResult = createRpcResult(unknown()); - -/** - * @internal - */ -function jsonRpcResult(schema: Struct) { - return coerce(createRpcResult(schema), UnknownRpcResult, value => { - if ('error' in value) { - return value; - } else { - return { - ...value, - result: create(value.result, schema), - }; - } - }); -} - -/** - * @internal - */ -function jsonRpcResultAndContext(value: Struct) { - return jsonRpcResult( - pick({ - context: pick({ - slot: number(), - }), - value, - }), - ); -} - -/** - * @internal - */ -function notificationResultAndContext(value: Struct) { - return pick({ - context: pick({ - slot: number(), - }), - value, - }); -} - -/** - * @internal - */ -function versionedMessageFromResponse( - version: TransactionVersion | undefined, - response: MessageResponse, -): VersionedMessage { - if (version === 0) { - return new MessageV0({ - header: response.header, - staticAccountKeys: response.accountKeys.map( - accountKey => new PublicKey(accountKey), - ), - recentBlockhash: response.recentBlockhash, - compiledInstructions: response.instructions.map(ix => ({ - programIdIndex: ix.programIdIndex, - accountKeyIndexes: ix.accounts, - data: bs58.decode(ix.data), - })), - addressTableLookups: response.addressTableLookups!, - }); - } else { - return new Message(response); - } -} - -/** - * The level of commitment desired when querying state - *
- *   'processed': Query the most recent block which has reached 1 confirmation by the connected node
- *   'confirmed': Query the most recent block which has reached 1 confirmation by the cluster
- *   'finalized': Query the most recent block which has been finalized by the cluster
- * 
- */ -export type Commitment = - | 'processed' - | 'confirmed' - | 'finalized' - | 'recent' // Deprecated as of v1.5.5 - | 'single' // Deprecated as of v1.5.5 - | 'singleGossip' // Deprecated as of v1.5.5 - | 'root' // Deprecated as of v1.5.5 - | 'max'; // Deprecated as of v1.5.5 - -/** - * A subset of Commitment levels, which are at least optimistically confirmed - *
- *   'confirmed': Query the most recent block which has reached 1 confirmation by the cluster
- *   'finalized': Query the most recent block which has been finalized by the cluster
- * 
- */ -export type Finality = 'confirmed' | 'finalized'; - -/** - * Filter for largest accounts query - *
- *   'circulating':    Return the largest accounts that are part of the circulating supply
- *   'nonCirculating': Return the largest accounts that are not part of the circulating supply
- * 
- */ -export type LargestAccountsFilter = 'circulating' | 'nonCirculating'; - -/** - * Configuration object for changing `getAccountInfo` query behavior - */ -export type GetAccountInfoConfig = { - /** The level of commitment desired */ - commitment?: Commitment; - /** The minimum slot that the request can be evaluated at */ - minContextSlot?: number; - /** Optional data slice to limit the returned account data */ - dataSlice?: DataSlice; -}; - -/** - * Configuration object for changing `getBalance` query behavior - */ -export type GetBalanceConfig = { - /** The level of commitment desired */ - commitment?: Commitment; - /** The minimum slot that the request can be evaluated at */ - minContextSlot?: number; -}; - -/** - * Configuration object for changing `getBlock` query behavior - */ -export type GetBlockConfig = { - /** The level of finality desired */ - commitment?: Finality; - /** - * Whether to populate the rewards array. If parameter not provided, the default includes rewards. - */ - rewards?: boolean; - /** - * Level of transaction detail to return, either "full", "accounts", "signatures", or "none". If - * parameter not provided, the default detail level is "full". If "accounts" are requested, - * transaction details only include signatures and an annotated list of accounts in each - * transaction. Transaction metadata is limited to only: fee, err, pre_balances, post_balances, - * pre_token_balances, and post_token_balances. - */ - transactionDetails?: 'accounts' | 'full' | 'none' | 'signatures'; -}; - -/** - * Configuration object for changing `getBlock` query behavior - */ -export type GetVersionedBlockConfig = { - /** The level of finality desired */ - commitment?: Finality; - /** The max transaction version to return in responses. If the requested transaction is a higher version, an error will be returned */ - maxSupportedTransactionVersion?: number; - /** - * Whether to populate the rewards array. If parameter not provided, the default includes rewards. - */ - rewards?: boolean; - /** - * Level of transaction detail to return, either "full", "accounts", "signatures", or "none". If - * parameter not provided, the default detail level is "full". If "accounts" are requested, - * transaction details only include signatures and an annotated list of accounts in each - * transaction. Transaction metadata is limited to only: fee, err, pre_balances, post_balances, - * pre_token_balances, and post_token_balances. - */ - transactionDetails?: 'accounts' | 'full' | 'none' | 'signatures'; -}; - -/** - * Configuration object for changing `getStakeMinimumDelegation` query behavior - */ -export type GetStakeMinimumDelegationConfig = { - /** The level of commitment desired */ - commitment?: Commitment; -}; - -/** - * Configuration object for changing `getBlockHeight` query behavior - */ -export type GetBlockHeightConfig = { - /** The level of commitment desired */ - commitment?: Commitment; - /** The minimum slot that the request can be evaluated at */ - minContextSlot?: number; -}; - -/** - * Configuration object for changing `getEpochInfo` query behavior - */ -export type GetEpochInfoConfig = { - /** The level of commitment desired */ - commitment?: Commitment; - /** The minimum slot that the request can be evaluated at */ - minContextSlot?: number; -}; - -/** - * Configuration object for changing `getInflationReward` query behavior - */ -export type GetInflationRewardConfig = { - /** The level of commitment desired */ - commitment?: Commitment; - /** An epoch for which the reward occurs. If omitted, the previous epoch will be used */ - epoch?: number; - /** The minimum slot that the request can be evaluated at */ - minContextSlot?: number; -}; - -/** - * Configuration object for changing `getLatestBlockhash` query behavior - */ -export type GetLatestBlockhashConfig = { - /** The level of commitment desired */ - commitment?: Commitment; - /** The minimum slot that the request can be evaluated at */ - minContextSlot?: number; -}; - -/** - * Configuration object for changing `isBlockhashValid` query behavior - */ -export type IsBlockhashValidConfig = { - /** The level of commitment desired */ - commitment?: Commitment; - /** The minimum slot that the request can be evaluated at */ - minContextSlot?: number; -}; - -/** - * Configuration object for changing `getSlot` query behavior - */ -export type GetSlotConfig = { - /** The level of commitment desired */ - commitment?: Commitment; - /** The minimum slot that the request can be evaluated at */ - minContextSlot?: number; -}; - -/** - * Configuration object for changing `getSlotLeader` query behavior - */ -export type GetSlotLeaderConfig = { - /** The level of commitment desired */ - commitment?: Commitment; - /** The minimum slot that the request can be evaluated at */ - minContextSlot?: number; -}; - -/** - * Configuration object for changing `getTransaction` query behavior - */ -export type GetTransactionConfig = { - /** The level of finality desired */ - commitment?: Finality; -}; - -/** - * Configuration object for changing `getTransaction` query behavior - */ -export type GetVersionedTransactionConfig = { - /** The level of finality desired */ - commitment?: Finality; - /** The max transaction version to return in responses. If the requested transaction is a higher version, an error will be returned */ - maxSupportedTransactionVersion?: number; -}; - -/** - * Configuration object for changing `getLargestAccounts` query behavior - */ -export type GetLargestAccountsConfig = { - /** The level of commitment desired */ - commitment?: Commitment; - /** Filter largest accounts by whether they are part of the circulating supply */ - filter?: LargestAccountsFilter; -}; - -/** - * Configuration object for changing `getSupply` request behavior - */ -export type GetSupplyConfig = { - /** The level of commitment desired */ - commitment?: Commitment; - /** Exclude non circulating accounts list from response */ - excludeNonCirculatingAccountsList?: boolean; -}; - -/** - * Configuration object for changing query behavior - */ -export type SignatureStatusConfig = { - /** enable searching status history, not needed for recent transactions */ - searchTransactionHistory: boolean; -}; - -/** - * Information describing a cluster node - */ -export type ContactInfo = { - /** Identity public key of the node */ - pubkey: string; - /** Gossip network address for the node */ - gossip: string | null; - /** TPU network address for the node (null if not available) */ - tpu: string | null; - /** JSON RPC network address for the node (null if not available) */ - rpc: string | null; - /** Software version of the node (null if not available) */ - version: string | null; -}; - -/** - * Information describing a vote account - */ -export type VoteAccountInfo = { - /** Public key of the vote account */ - votePubkey: string; - /** Identity public key of the node voting with this account */ - nodePubkey: string; - /** The stake, in lamports, delegated to this vote account and activated */ - activatedStake: number; - /** Whether the vote account is staked for this epoch */ - epochVoteAccount: boolean; - /** Recent epoch voting credit history for this voter */ - epochCredits: Array<[number, number, number]>; - /** A percentage (0-100) of rewards payout owed to the voter */ - commission: number; - /** Most recent slot voted on by this vote account */ - lastVote: number; -}; - -/** - * A collection of cluster vote accounts - */ -export type VoteAccountStatus = { - /** Active vote accounts */ - current: Array; - /** Inactive vote accounts */ - delinquent: Array; -}; - -/** - * Network Inflation - * (see https://docs.solana.com/implemented-proposals/ed_overview) - */ -export type InflationGovernor = { - foundation: number; - foundationTerm: number; - initial: number; - taper: number; - terminal: number; -}; - -const GetInflationGovernorResult = pick({ - foundation: number(), - foundationTerm: number(), - initial: number(), - taper: number(), - terminal: number(), -}); - -/** - * The inflation reward for an epoch - */ -export type InflationReward = { - /** epoch for which the reward occurs */ - epoch: number; - /** the slot in which the rewards are effective */ - effectiveSlot: number; - /** reward amount in lamports */ - amount: number; - /** post balance of the account in lamports */ - postBalance: number; - /** vote account commission when the reward was credited */ - commission?: number | null; -}; - -/** - * Expected JSON RPC response for the "getInflationReward" message - */ -const GetInflationRewardResult = jsonRpcResult( - array( - nullable( - pick({ - epoch: number(), - effectiveSlot: number(), - amount: number(), - postBalance: number(), - commission: optional(nullable(number())), - }), - ), - ), -); - -export type RecentPrioritizationFees = { - /** slot in which the fee was observed */ - slot: number; - /** the per-compute-unit fee paid by at least one successfully landed transaction, specified in increments of 0.000001 lamports*/ - prioritizationFee: number; -}; - -/** - * Configuration object for changing `getRecentPrioritizationFees` query behavior - */ -export type GetRecentPrioritizationFeesConfig = { - /** - * If this parameter is provided, the response will reflect a fee to land a transaction locking - * all of the provided accounts as writable. - */ - lockedWritableAccounts?: PublicKey[]; -}; - -/** - * Expected JSON RPC response for the "getRecentPrioritizationFees" message - */ -const GetRecentPrioritizationFeesResult = array( - pick({ - slot: number(), - prioritizationFee: number(), - }), -); - -export type InflationRate = { - /** total inflation */ - total: number; - /** inflation allocated to validators */ - validator: number; - /** inflation allocated to the foundation */ - foundation: number; - /** epoch for which these values are valid */ - epoch: number; -}; - -/** - * Expected JSON RPC response for the "getInflationRate" message - */ -const GetInflationRateResult = pick({ - total: number(), - validator: number(), - foundation: number(), - epoch: number(), -}); - -/** - * Information about the current epoch - */ -export type EpochInfo = { - epoch: number; - slotIndex: number; - slotsInEpoch: number; - absoluteSlot: number; - blockHeight?: number; - transactionCount?: number; -}; - -const GetEpochInfoResult = pick({ - epoch: number(), - slotIndex: number(), - slotsInEpoch: number(), - absoluteSlot: number(), - blockHeight: optional(number()), - transactionCount: optional(number()), -}); - -const GetEpochScheduleResult = pick({ - slotsPerEpoch: number(), - leaderScheduleSlotOffset: number(), - warmup: boolean(), - firstNormalEpoch: number(), - firstNormalSlot: number(), -}); - -/** - * Leader schedule - * (see https://docs.solana.com/terminology#leader-schedule) - */ -export type LeaderSchedule = { - [address: string]: number[]; -}; - -const GetLeaderScheduleResult = record(string(), array(number())); - -/** - * Transaction error or null - */ -const TransactionErrorResult = nullable(union([pick({}), string()])); - -/** - * Signature status for a transaction - */ -const SignatureStatusResult = pick({ - err: TransactionErrorResult, -}); - -/** - * Transaction signature received notification - */ -const SignatureReceivedResult = literal('receivedSignature'); - -/** - * Version info for a node - */ -export type Version = { - /** Version of solana-core */ - 'solana-core': string; - 'feature-set'?: number; -}; - -const VersionResult = pick({ - 'solana-core': string(), - 'feature-set': optional(number()), -}); - -export type SimulatedTransactionAccountInfo = { - /** `true` if this account's data contains a loaded program */ - executable: boolean; - /** Identifier of the program that owns the account */ - owner: string; - /** Number of lamports assigned to the account */ - lamports: number; - /** Optional data assigned to the account */ - data: string[]; - /** Optional rent epoch info for account */ - rentEpoch?: number; -}; - -export type TransactionReturnDataEncoding = 'base64'; - -export type TransactionReturnData = { - programId: string; - data: [string, TransactionReturnDataEncoding]; -}; - -export type SimulateTransactionConfig = { - /** Optional parameter used to enable signature verification before simulation */ - sigVerify?: boolean; - /** Optional parameter used to replace the simulated transaction's recent blockhash with the latest blockhash */ - replaceRecentBlockhash?: boolean; - /** Optional parameter used to set the commitment level when selecting the latest block */ - commitment?: Commitment; - /** Optional parameter used to specify a list of base58-encoded account addresses to return post simulation state for */ - accounts?: { - /** The encoding of the returned account's data */ - encoding: 'base64'; - addresses: string[]; - }; - /** Optional parameter used to specify the minimum block slot that can be used for simulation */ - minContextSlot?: number; - /** Optional parameter used to include inner instructions in the simulation */ - innerInstructions?: boolean; -}; - -export type SimulatedTransactionResponse = { - err: TransactionError | string | null; - logs: Array | null; - accounts?: (SimulatedTransactionAccountInfo | null)[] | null; - unitsConsumed?: number; - returnData?: TransactionReturnData | null; - innerInstructions?: ParsedInnerInstruction[] | null; -}; -const ParsedInstructionStruct = pick({ - program: string(), - programId: PublicKeyFromString, - parsed: unknown(), -}); - -const PartiallyDecodedInstructionStruct = pick({ - programId: PublicKeyFromString, - accounts: array(PublicKeyFromString), - data: string(), -}); - -const SimulatedTransactionResponseStruct = jsonRpcResultAndContext( - pick({ - err: nullable(union([pick({}), string()])), - logs: nullable(array(string())), - accounts: optional( - nullable( - array( - nullable( - pick({ - executable: boolean(), - owner: string(), - lamports: number(), - data: array(string()), - rentEpoch: optional(number()), - }), - ), - ), - ), - ), - unitsConsumed: optional(number()), - returnData: optional( - nullable( - pick({ - programId: string(), - data: tuple([string(), literal('base64')]), - }), - ), - ), - innerInstructions: optional( - nullable( - array( - pick({ - index: number(), - instructions: array( - union([ - ParsedInstructionStruct, - PartiallyDecodedInstructionStruct, - ]), - ), - }), - ), - ), - ), - }), -); - -export type ParsedInnerInstruction = { - index: number; - instructions: (ParsedInstruction | PartiallyDecodedInstruction)[]; -}; - -export type TokenBalance = { - accountIndex: number; - mint: string; - owner?: string; - uiTokenAmount: TokenAmount; -}; - -/** - * Metadata for a parsed confirmed transaction on the ledger - * - * @deprecated Deprecated since RPC v1.8.0. Please use {@link ParsedTransactionMeta} instead. - */ -export type ParsedConfirmedTransactionMeta = ParsedTransactionMeta; - -/** - * Collection of addresses loaded by a transaction using address table lookups - */ -export type LoadedAddresses = { - writable: Array; - readonly: Array; -}; - -/** - * Metadata for a parsed transaction on the ledger - */ -export type ParsedTransactionMeta = { - /** The fee charged for processing the transaction */ - fee: number; - /** An array of cross program invoked parsed instructions */ - innerInstructions?: ParsedInnerInstruction[] | null; - /** The balances of the transaction accounts before processing */ - preBalances: Array; - /** The balances of the transaction accounts after processing */ - postBalances: Array; - /** An array of program log messages emitted during a transaction */ - logMessages?: Array | null; - /** The token balances of the transaction accounts before processing */ - preTokenBalances?: Array | null; - /** The token balances of the transaction accounts after processing */ - postTokenBalances?: Array | null; - /** The error result of transaction processing */ - err: TransactionError | null; - /** The collection of addresses loaded using address lookup tables */ - loadedAddresses?: LoadedAddresses; - /** The compute units consumed after processing the transaction */ - computeUnitsConsumed?: number; -}; - -export type CompiledInnerInstruction = { - index: number; - instructions: CompiledInstruction[]; -}; - -/** - * Metadata for a confirmed transaction on the ledger - */ -export type ConfirmedTransactionMeta = { - /** The fee charged for processing the transaction */ - fee: number; - /** An array of cross program invoked instructions */ - innerInstructions?: CompiledInnerInstruction[] | null; - /** The balances of the transaction accounts before processing */ - preBalances: Array; - /** The balances of the transaction accounts after processing */ - postBalances: Array; - /** An array of program log messages emitted during a transaction */ - logMessages?: Array | null; - /** The token balances of the transaction accounts before processing */ - preTokenBalances?: Array | null; - /** The token balances of the transaction accounts after processing */ - postTokenBalances?: Array | null; - /** The error result of transaction processing */ - err: TransactionError | null; - /** The collection of addresses loaded using address lookup tables */ - loadedAddresses?: LoadedAddresses; - /** The compute units consumed after processing the transaction */ - computeUnitsConsumed?: number; -}; - -/** - * A processed transaction from the RPC API - */ -export type TransactionResponse = { - /** The slot during which the transaction was processed */ - slot: number; - /** The transaction */ - transaction: { - /** The transaction message */ - message: Message; - /** The transaction signatures */ - signatures: string[]; - }; - /** Metadata produced from the transaction */ - meta: ConfirmedTransactionMeta | null; - /** The unix timestamp of when the transaction was processed */ - blockTime?: number | null; -}; - -/** - * A processed transaction from the RPC API - */ -export type VersionedTransactionResponse = { - /** The slot during which the transaction was processed */ - slot: number; - /** The transaction */ - transaction: { - /** The transaction message */ - message: VersionedMessage; - /** The transaction signatures */ - signatures: string[]; - }; - /** Metadata produced from the transaction */ - meta: ConfirmedTransactionMeta | null; - /** The unix timestamp of when the transaction was processed */ - blockTime?: number | null; - /** The transaction version */ - version?: TransactionVersion; -}; - -/** - * A processed transaction message from the RPC API - */ -type MessageResponse = { - accountKeys: string[]; - header: MessageHeader; - instructions: CompiledInstruction[]; - recentBlockhash: string; - addressTableLookups?: ParsedAddressTableLookup[]; -}; - -/** - * A confirmed transaction on the ledger - * - * @deprecated Deprecated since RPC v1.8.0. - */ -export type ConfirmedTransaction = { - /** The slot during which the transaction was processed */ - slot: number; - /** The details of the transaction */ - transaction: Transaction; - /** Metadata produced from the transaction */ - meta: ConfirmedTransactionMeta | null; - /** The unix timestamp of when the transaction was processed */ - blockTime?: number | null; -}; - -/** - * A partially decoded transaction instruction - */ -export type PartiallyDecodedInstruction = { - /** Program id called by this instruction */ - programId: PublicKey; - /** Public keys of accounts passed to this instruction */ - accounts: Array; - /** Raw base-58 instruction data */ - data: string; -}; - -/** - * A parsed transaction message account - */ -export type ParsedMessageAccount = { - /** Public key of the account */ - pubkey: PublicKey; - /** Indicates if the account signed the transaction */ - signer: boolean; - /** Indicates if the account is writable for this transaction */ - writable: boolean; - /** Indicates if the account key came from the transaction or a lookup table */ - source?: 'transaction' | 'lookupTable'; -}; - -/** - * A parsed transaction instruction - */ -export type ParsedInstruction = { - /** Name of the program for this instruction */ - program: string; - /** ID of the program for this instruction */ - programId: PublicKey; - /** Parsed instruction info */ - parsed: any; -}; - -/** - * A parsed address table lookup - */ -export type ParsedAddressTableLookup = { - /** Address lookup table account key */ - accountKey: PublicKey; - /** Parsed instruction info */ - writableIndexes: number[]; - /** Parsed instruction info */ - readonlyIndexes: number[]; -}; - -/** - * A parsed transaction message - */ -export type ParsedMessage = { - /** Accounts used in the instructions */ - accountKeys: ParsedMessageAccount[]; - /** The atomically executed instructions for the transaction */ - instructions: (ParsedInstruction | PartiallyDecodedInstruction)[]; - /** Recent blockhash */ - recentBlockhash: string; - /** Address table lookups used to load additional accounts */ - addressTableLookups?: ParsedAddressTableLookup[] | null; -}; - -/** - * A parsed transaction - */ -export type ParsedTransaction = { - /** Signatures for the transaction */ - signatures: Array; - /** Message of the transaction */ - message: ParsedMessage; -}; - -/** - * A parsed and confirmed transaction on the ledger - * - * @deprecated Deprecated since RPC v1.8.0. Please use {@link ParsedTransactionWithMeta} instead. - */ -export type ParsedConfirmedTransaction = ParsedTransactionWithMeta; - -/** - * A parsed transaction on the ledger with meta - */ -export type ParsedTransactionWithMeta = { - /** The slot during which the transaction was processed */ - slot: number; - /** The details of the transaction */ - transaction: ParsedTransaction; - /** Metadata produced from the transaction */ - meta: ParsedTransactionMeta | null; - /** The unix timestamp of when the transaction was processed */ - blockTime?: number | null; - /** The version of the transaction message */ - version?: TransactionVersion; -}; - -/** - * A processed block fetched from the RPC API - */ -export type BlockResponse = { - /** Blockhash of this block */ - blockhash: Blockhash; - /** Blockhash of this block's parent */ - previousBlockhash: Blockhash; - /** Slot index of this block's parent */ - parentSlot: number; - /** Vector of transactions with status meta and original message */ - transactions: Array<{ - /** The transaction */ - transaction: { - /** The transaction message */ - message: Message; - /** The transaction signatures */ - signatures: string[]; - }; - /** Metadata produced from the transaction */ - meta: ConfirmedTransactionMeta | null; - /** The transaction version */ - version?: TransactionVersion; - }>; - /** Vector of block rewards */ - rewards?: Array<{ - /** Public key of reward recipient */ - pubkey: string; - /** Reward value in lamports */ - lamports: number; - /** Account balance after reward is applied */ - postBalance: number | null; - /** Type of reward received */ - rewardType: string | null; - /** Vote account commission when the reward was credited, only present for voting and staking rewards */ - commission?: number | null; - }>; - /** The unix timestamp of when the block was processed */ - blockTime: number | null; -}; - -/** - * A processed block fetched from the RPC API where the `transactionDetails` mode is `accounts` - */ -export type AccountsModeBlockResponse = VersionedAccountsModeBlockResponse; - -/** - * A processed block fetched from the RPC API where the `transactionDetails` mode is `none` - */ -export type NoneModeBlockResponse = VersionedNoneModeBlockResponse; - -/** - * A block with parsed transactions - */ -export type ParsedBlockResponse = { - /** Blockhash of this block */ - blockhash: Blockhash; - /** Blockhash of this block's parent */ - previousBlockhash: Blockhash; - /** Slot index of this block's parent */ - parentSlot: number; - /** Vector of transactions with status meta and original message */ - transactions: Array<{ - /** The details of the transaction */ - transaction: ParsedTransaction; - /** Metadata produced from the transaction */ - meta: ParsedTransactionMeta | null; - /** The transaction version */ - version?: TransactionVersion; - }>; - /** Vector of block rewards */ - rewards?: Array<{ - /** Public key of reward recipient */ - pubkey: string; - /** Reward value in lamports */ - lamports: number; - /** Account balance after reward is applied */ - postBalance: number | null; - /** Type of reward received */ - rewardType: string | null; - /** Vote account commission when the reward was credited, only present for voting and staking rewards */ - commission?: number | null; - }>; - /** The unix timestamp of when the block was processed */ - blockTime: number | null; - /** The number of blocks beneath this block */ - blockHeight: number | null; -}; - -/** - * A block with parsed transactions where the `transactionDetails` mode is `accounts` - */ -export type ParsedAccountsModeBlockResponse = Omit< - ParsedBlockResponse, - 'transactions' -> & { - transactions: Array< - Omit & { - transaction: Pick< - ParsedBlockResponse['transactions'][number]['transaction'], - 'signatures' - > & { - accountKeys: ParsedMessageAccount[]; - }; - } - >; -}; - -/** - * A block with parsed transactions where the `transactionDetails` mode is `none` - */ -export type ParsedNoneModeBlockResponse = Omit< - ParsedBlockResponse, - 'transactions' ->; - -/** - * A processed block fetched from the RPC API - */ -export type VersionedBlockResponse = { - /** Blockhash of this block */ - blockhash: Blockhash; - /** Blockhash of this block's parent */ - previousBlockhash: Blockhash; - /** Slot index of this block's parent */ - parentSlot: number; - /** Vector of transactions with status meta and original message */ - transactions: Array<{ - /** The transaction */ - transaction: { - /** The transaction message */ - message: VersionedMessage; - /** The transaction signatures */ - signatures: string[]; - }; - /** Metadata produced from the transaction */ - meta: ConfirmedTransactionMeta | null; - /** The transaction version */ - version?: TransactionVersion; - }>; - /** Vector of block rewards */ - rewards?: Array<{ - /** Public key of reward recipient */ - pubkey: string; - /** Reward value in lamports */ - lamports: number; - /** Account balance after reward is applied */ - postBalance: number | null; - /** Type of reward received */ - rewardType: string | null; - /** Vote account commission when the reward was credited, only present for voting and staking rewards */ - commission?: number | null; - }>; - /** The unix timestamp of when the block was processed */ - blockTime: number | null; -}; - -/** - * A processed block fetched from the RPC API where the `transactionDetails` mode is `accounts` - */ -export type VersionedAccountsModeBlockResponse = Omit< - VersionedBlockResponse, - 'transactions' -> & { - transactions: Array< - Omit & { - transaction: Pick< - VersionedBlockResponse['transactions'][number]['transaction'], - 'signatures' - > & { - accountKeys: ParsedMessageAccount[]; - }; - } - >; -}; - -/** - * A processed block fetched from the RPC API where the `transactionDetails` mode is `none` - */ -export type VersionedNoneModeBlockResponse = Omit< - VersionedBlockResponse, - 'transactions' ->; - -/** - * A confirmed block on the ledger - * - * @deprecated Deprecated since RPC v1.8.0. - */ -export type ConfirmedBlock = { - /** Blockhash of this block */ - blockhash: Blockhash; - /** Blockhash of this block's parent */ - previousBlockhash: Blockhash; - /** Slot index of this block's parent */ - parentSlot: number; - /** Vector of transactions and status metas */ - transactions: Array<{ - transaction: Transaction; - meta: ConfirmedTransactionMeta | null; - }>; - /** Vector of block rewards */ - rewards?: Array<{ - pubkey: string; - lamports: number; - postBalance: number | null; - rewardType: string | null; - commission?: number | null; - }>; - /** The unix timestamp of when the block was processed */ - blockTime: number | null; -}; - -/** - * A Block on the ledger with signatures only - */ -export type BlockSignatures = { - /** Blockhash of this block */ - blockhash: Blockhash; - /** Blockhash of this block's parent */ - previousBlockhash: Blockhash; - /** Slot index of this block's parent */ - parentSlot: number; - /** Vector of signatures */ - signatures: Array; - /** The unix timestamp of when the block was processed */ - blockTime: number | null; -}; - -/** - * recent block production information - */ -export type BlockProduction = Readonly<{ - /** a dictionary of validator identities, as base-58 encoded strings. Value is a two element array containing the number of leader slots and the number of blocks produced */ - byIdentity: Readonly>>; - /** Block production slot range */ - range: Readonly<{ - /** first slot of the block production information (inclusive) */ - firstSlot: number; - /** last slot of block production information (inclusive) */ - lastSlot: number; - }>; -}>; - -export type GetBlockProductionConfig = { - /** Optional commitment level */ - commitment?: Commitment; - /** Slot range to return block production for. If parameter not provided, defaults to current epoch. */ - range?: { - /** first slot to return block production information for (inclusive) */ - firstSlot: number; - /** last slot to return block production information for (inclusive). If parameter not provided, defaults to the highest slot */ - lastSlot?: number; - }; - /** Only return results for this validator identity (base-58 encoded) */ - identity?: string; -}; - -/** - * Expected JSON RPC response for the "getBlockProduction" message - */ -const BlockProductionResponseStruct = jsonRpcResultAndContext( - pick({ - byIdentity: record(string(), array(number())), - range: pick({ - firstSlot: number(), - lastSlot: number(), - }), - }), -); - -/** - * A performance sample - */ -export type PerfSample = { - /** Slot number of sample */ - slot: number; - /** Number of transactions in a sample window */ - numTransactions: number; - /** Number of slots in a sample window */ - numSlots: number; - /** Sample window in seconds */ - samplePeriodSecs: number; -}; - -function createRpcClient( - url: string, - httpHeaders?: HttpHeaders, - customFetch?: FetchFn, - fetchMiddleware?: FetchMiddleware, - disableRetryOnRateLimit?: boolean, - httpAgent?: NodeHttpAgent | NodeHttpsAgent | false, -): RpcClient { - const fetch = customFetch ? customFetch : fetchImpl; - let agent: NodeHttpAgent | NodeHttpsAgent | undefined; - if (process.env.BROWSER) { - if (httpAgent != null) { - console.warn( - 'You have supplied an `httpAgent` when creating a `Connection` in a browser environment.' + - 'It has been ignored; `httpAgent` is only used in Node environments.', - ); - } - } else { - if (httpAgent == null) { - if (process.env.NODE_ENV !== 'test') { - const agentOptions = { - // One second fewer than the Solana RPC's keepalive timeout. - // Read more: https://github.com/solana-labs/solana/issues/27859#issuecomment-1340097889 - freeSocketTimeout: 19000, - keepAlive: true, - maxSockets: 25, - }; - if (url.startsWith('https:')) { - agent = new HttpsKeepAliveAgent(agentOptions); - } else { - agent = new HttpKeepAliveAgent(agentOptions); - } - } - } else { - if (httpAgent !== false) { - const isHttps = url.startsWith('https:'); - if (isHttps && !(httpAgent instanceof NodeHttpsAgent)) { - throw new Error( - 'The endpoint `' + - url + - '` can only be paired with an `https.Agent`. You have, instead, supplied an ' + - '`http.Agent` through `httpAgent`.', - ); - } else if (!isHttps && httpAgent instanceof NodeHttpsAgent) { - throw new Error( - 'The endpoint `' + - url + - '` can only be paired with an `http.Agent`. You have, instead, supplied an ' + - '`https.Agent` through `httpAgent`.', - ); - } - agent = httpAgent; - } - } - } - - let fetchWithMiddleware: FetchFn | undefined; - - if (fetchMiddleware) { - fetchWithMiddleware = async (info, init) => { - const modifiedFetchArgs = await new Promise>( - (resolve, reject) => { - try { - fetchMiddleware(info, init, (modifiedInfo, modifiedInit) => - resolve([modifiedInfo, modifiedInit]), - ); - } catch (error) { - reject(error); - } - }, - ); - return await fetch(...modifiedFetchArgs); - }; - } - - const clientBrowser = new RpcClient(async (request, callback) => { - const options = { - method: 'POST', - body: request, - agent, - headers: Object.assign( - { - 'Content-Type': 'application/json', - }, - httpHeaders || {}, - COMMON_HTTP_HEADERS, - ), - }; - - try { - let too_many_requests_retries = 5; - let res: Response; - let waitTime = 500; - for (;;) { - if (fetchWithMiddleware) { - res = await fetchWithMiddleware(url, options); - } else { - res = await fetch(url, options); - } - - if (res.status !== 429 /* Too many requests */) { - break; - } - if (disableRetryOnRateLimit === true) { - break; - } - too_many_requests_retries -= 1; - if (too_many_requests_retries === 0) { - break; - } - console.error( - `Server responded with ${res.status} ${res.statusText}. Retrying after ${waitTime}ms delay...`, - ); - await sleep(waitTime); - waitTime *= 2; - } - - const text = await res.text(); - if (res.ok) { - callback(null, text); - } else { - callback(new Error(`${res.status} ${res.statusText}: ${text}`)); - } - } catch (err) { - if (err instanceof Error) callback(err); - } - }, {}); - - return clientBrowser; -} - -function createRpcRequest(client: RpcClient): RpcRequest { - return (method, args) => { - return new Promise((resolve, reject) => { - client.request(method, args, (err: any, response: any) => { - if (err) { - reject(err); - return; - } - resolve(response); - }); - }); - }; -} - -function createRpcBatchRequest(client: RpcClient): RpcBatchRequest { - return (requests: RpcParams[]) => { - return new Promise((resolve, reject) => { - // Do nothing if requests is empty - if (requests.length === 0) resolve([]); - - const batch = requests.map((params: RpcParams) => { - return client.request(params.methodName, params.args); - }); - - client.request(batch, (err: any, response: any) => { - if (err) { - reject(err); - return; - } - resolve(response); - }); - }); - }; -} - -/** - * Expected JSON RPC response for the "getInflationGovernor" message - */ -const GetInflationGovernorRpcResult = jsonRpcResult(GetInflationGovernorResult); - -/** - * Expected JSON RPC response for the "getInflationRate" message - */ -const GetInflationRateRpcResult = jsonRpcResult(GetInflationRateResult); - -/** - * Expected JSON RPC response for the "getRecentPrioritizationFees" message - */ -const GetRecentPrioritizationFeesRpcResult = jsonRpcResult( - GetRecentPrioritizationFeesResult, -); - -/** - * Expected JSON RPC response for the "getEpochInfo" message - */ -const GetEpochInfoRpcResult = jsonRpcResult(GetEpochInfoResult); - -/** - * Expected JSON RPC response for the "getEpochSchedule" message - */ -const GetEpochScheduleRpcResult = jsonRpcResult(GetEpochScheduleResult); - -/** - * Expected JSON RPC response for the "getLeaderSchedule" message - */ -const GetLeaderScheduleRpcResult = jsonRpcResult(GetLeaderScheduleResult); - -/** - * Expected JSON RPC response for the "minimumLedgerSlot" and "getFirstAvailableBlock" messages - */ -const SlotRpcResult = jsonRpcResult(number()); - -/** - * Supply - */ -export type Supply = { - /** Total supply in lamports */ - total: number; - /** Circulating supply in lamports */ - circulating: number; - /** Non-circulating supply in lamports */ - nonCirculating: number; - /** List of non-circulating account addresses */ - nonCirculatingAccounts: Array; -}; - -/** - * Expected JSON RPC response for the "getSupply" message - */ -const GetSupplyRpcResult = jsonRpcResultAndContext( - pick({ - total: number(), - circulating: number(), - nonCirculating: number(), - nonCirculatingAccounts: array(PublicKeyFromString), - }), -); - -/** - * Token amount object which returns a token amount in different formats - * for various client use cases. - */ -export type TokenAmount = { - /** Raw amount of tokens as string ignoring decimals */ - amount: string; - /** Number of decimals configured for token's mint */ - decimals: number; - /** Token amount as float, accounts for decimals */ - uiAmount: number | null; - /** Token amount as string, accounts for decimals */ - uiAmountString?: string; -}; - -/** - * Expected JSON RPC structure for token amounts - */ -const TokenAmountResult = pick({ - amount: string(), - uiAmount: nullable(number()), - decimals: number(), - uiAmountString: optional(string()), -}); - -/** - * Token address and balance. - */ -export type TokenAccountBalancePair = { - /** Address of the token account */ - address: PublicKey; - /** Raw amount of tokens as string ignoring decimals */ - amount: string; - /** Number of decimals configured for token's mint */ - decimals: number; - /** Token amount as float, accounts for decimals */ - uiAmount: number | null; - /** Token amount as string, accounts for decimals */ - uiAmountString?: string; -}; - -/** - * Expected JSON RPC response for the "getTokenLargestAccounts" message - */ -const GetTokenLargestAccountsResult = jsonRpcResultAndContext( - array( - pick({ - address: PublicKeyFromString, - amount: string(), - uiAmount: nullable(number()), - decimals: number(), - uiAmountString: optional(string()), - }), - ), -); - -/** - * Expected JSON RPC response for the "getTokenAccountsByOwner" message - */ -const GetTokenAccountsByOwner = jsonRpcResultAndContext( - array( - pick({ - pubkey: PublicKeyFromString, - account: pick({ - executable: boolean(), - owner: PublicKeyFromString, - lamports: number(), - data: BufferFromRawAccountData, - rentEpoch: number(), - }), - }), - ), -); - -const ParsedAccountDataResult = pick({ - program: string(), - parsed: unknown(), - space: number(), -}); - -/** - * Expected JSON RPC response for the "getTokenAccountsByOwner" message with parsed data - */ -const GetParsedTokenAccountsByOwner = jsonRpcResultAndContext( - array( - pick({ - pubkey: PublicKeyFromString, - account: pick({ - executable: boolean(), - owner: PublicKeyFromString, - lamports: number(), - data: ParsedAccountDataResult, - rentEpoch: number(), - }), - }), - ), -); - -/** - * Pair of an account address and its balance - */ -export type AccountBalancePair = { - address: PublicKey; - lamports: number; -}; - -/** - * Expected JSON RPC response for the "getLargestAccounts" message - */ -const GetLargestAccountsRpcResult = jsonRpcResultAndContext( - array( - pick({ - lamports: number(), - address: PublicKeyFromString, - }), - ), -); - -/** - * @internal - */ -const AccountInfoResult = pick({ - executable: boolean(), - owner: PublicKeyFromString, - lamports: number(), - data: BufferFromRawAccountData, - rentEpoch: number(), -}); - -/** - * @internal - */ -const KeyedAccountInfoResult = pick({ - pubkey: PublicKeyFromString, - account: AccountInfoResult, -}); - -const ParsedOrRawAccountData = coerce( - union([instance(Buffer), ParsedAccountDataResult]), - union([RawAccountDataResult, ParsedAccountDataResult]), - value => { - if (Array.isArray(value)) { - return create(value, BufferFromRawAccountData); - } else { - return value; - } - }, -); - -/** - * @internal - */ -const ParsedAccountInfoResult = pick({ - executable: boolean(), - owner: PublicKeyFromString, - lamports: number(), - data: ParsedOrRawAccountData, - rentEpoch: number(), -}); - -const KeyedParsedAccountInfoResult = pick({ - pubkey: PublicKeyFromString, - account: ParsedAccountInfoResult, -}); - -/** - * @internal - */ -const StakeActivationResult = pick({ - state: union([ - literal('active'), - literal('inactive'), - literal('activating'), - literal('deactivating'), - ]), - active: number(), - inactive: number(), -}); - -/** - * Expected JSON RPC response for the "getConfirmedSignaturesForAddress2" message - */ - -const GetConfirmedSignaturesForAddress2RpcResult = jsonRpcResult( - array( - pick({ - signature: string(), - slot: number(), - err: TransactionErrorResult, - memo: nullable(string()), - blockTime: optional(nullable(number())), - }), - ), -); - -/** - * Expected JSON RPC response for the "getSignaturesForAddress" message - */ -const GetSignaturesForAddressRpcResult = jsonRpcResult( - array( - pick({ - signature: string(), - slot: number(), - err: TransactionErrorResult, - memo: nullable(string()), - blockTime: optional(nullable(number())), - }), - ), -); - -/*** - * Expected JSON RPC response for the "accountNotification" message - */ -const AccountNotificationResult = pick({ - subscription: number(), - result: notificationResultAndContext(AccountInfoResult), -}); - -/** - * @internal - */ -const ProgramAccountInfoResult = pick({ - pubkey: PublicKeyFromString, - account: AccountInfoResult, -}); - -/*** - * Expected JSON RPC response for the "programNotification" message - */ -const ProgramAccountNotificationResult = pick({ - subscription: number(), - result: notificationResultAndContext(ProgramAccountInfoResult), -}); - -/** - * @internal - */ -const SlotInfoResult = pick({ - parent: number(), - slot: number(), - root: number(), -}); - -/** - * Expected JSON RPC response for the "slotNotification" message - */ -const SlotNotificationResult = pick({ - subscription: number(), - result: SlotInfoResult, -}); - -/** - * Slot updates which can be used for tracking the live progress of a cluster. - * - `"firstShredReceived"`: connected node received the first shred of a block. - * Indicates that a new block that is being produced. - * - `"completed"`: connected node has received all shreds of a block. Indicates - * a block was recently produced. - * - `"optimisticConfirmation"`: block was optimistically confirmed by the - * cluster. It is not guaranteed that an optimistic confirmation notification - * will be sent for every finalized blocks. - * - `"root"`: the connected node rooted this block. - * - `"createdBank"`: the connected node has started validating this block. - * - `"frozen"`: the connected node has validated this block. - * - `"dead"`: the connected node failed to validate this block. - */ -export type SlotUpdate = - | { - type: 'firstShredReceived'; - slot: number; - timestamp: number; - } - | { - type: 'completed'; - slot: number; - timestamp: number; - } - | { - type: 'createdBank'; - slot: number; - timestamp: number; - parent: number; - } - | { - type: 'frozen'; - slot: number; - timestamp: number; - stats: { - numTransactionEntries: number; - numSuccessfulTransactions: number; - numFailedTransactions: number; - maxTransactionsPerEntry: number; - }; - } - | { - type: 'dead'; - slot: number; - timestamp: number; - err: string; - } - | { - type: 'optimisticConfirmation'; - slot: number; - timestamp: number; - } - | { - type: 'root'; - slot: number; - timestamp: number; - }; - -/** - * @internal - */ -const SlotUpdateResult = union([ - pick({ - type: union([ - literal('firstShredReceived'), - literal('completed'), - literal('optimisticConfirmation'), - literal('root'), - ]), - slot: number(), - timestamp: number(), - }), - pick({ - type: literal('createdBank'), - parent: number(), - slot: number(), - timestamp: number(), - }), - pick({ - type: literal('frozen'), - slot: number(), - timestamp: number(), - stats: pick({ - numTransactionEntries: number(), - numSuccessfulTransactions: number(), - numFailedTransactions: number(), - maxTransactionsPerEntry: number(), - }), - }), - pick({ - type: literal('dead'), - slot: number(), - timestamp: number(), - err: string(), - }), -]); - -/** - * Expected JSON RPC response for the "slotsUpdatesNotification" message - */ -const SlotUpdateNotificationResult = pick({ - subscription: number(), - result: SlotUpdateResult, -}); - -/** - * Expected JSON RPC response for the "signatureNotification" message - */ -const SignatureNotificationResult = pick({ - subscription: number(), - result: notificationResultAndContext( - union([SignatureStatusResult, SignatureReceivedResult]), - ), -}); - -/** - * Expected JSON RPC response for the "rootNotification" message - */ -const RootNotificationResult = pick({ - subscription: number(), - result: number(), -}); - -const ContactInfoResult = pick({ - pubkey: string(), - gossip: nullable(string()), - tpu: nullable(string()), - rpc: nullable(string()), - version: nullable(string()), -}); - -const VoteAccountInfoResult = pick({ - votePubkey: string(), - nodePubkey: string(), - activatedStake: number(), - epochVoteAccount: boolean(), - epochCredits: array(tuple([number(), number(), number()])), - commission: number(), - lastVote: number(), - rootSlot: nullable(number()), -}); - -/** - * Expected JSON RPC response for the "getVoteAccounts" message - */ -const GetVoteAccounts = jsonRpcResult( - pick({ - current: array(VoteAccountInfoResult), - delinquent: array(VoteAccountInfoResult), - }), -); - -const ConfirmationStatus = union([ - literal('processed'), - literal('confirmed'), - literal('finalized'), -]); - -const SignatureStatusResponse = pick({ - slot: number(), - confirmations: nullable(number()), - err: TransactionErrorResult, - confirmationStatus: optional(ConfirmationStatus), -}); - -/** - * Expected JSON RPC response for the "getSignatureStatuses" message - */ -const GetSignatureStatusesRpcResult = jsonRpcResultAndContext( - array(nullable(SignatureStatusResponse)), -); - -/** - * Expected JSON RPC response for the "getMinimumBalanceForRentExemption" message - */ -const GetMinimumBalanceForRentExemptionRpcResult = jsonRpcResult(number()); - -const AddressTableLookupStruct = pick({ - accountKey: PublicKeyFromString, - writableIndexes: array(number()), - readonlyIndexes: array(number()), -}); - -const ConfirmedTransactionResult = pick({ - signatures: array(string()), - message: pick({ - accountKeys: array(string()), - header: pick({ - numRequiredSignatures: number(), - numReadonlySignedAccounts: number(), - numReadonlyUnsignedAccounts: number(), - }), - instructions: array( - pick({ - accounts: array(number()), - data: string(), - programIdIndex: number(), - }), - ), - recentBlockhash: string(), - addressTableLookups: optional(array(AddressTableLookupStruct)), - }), -}); - -const AnnotatedAccountKey = pick({ - pubkey: PublicKeyFromString, - signer: boolean(), - writable: boolean(), - source: optional(union([literal('transaction'), literal('lookupTable')])), -}); - -const ConfirmedTransactionAccountsModeResult = pick({ - accountKeys: array(AnnotatedAccountKey), - signatures: array(string()), -}); - -const ParsedInstructionResult = pick({ - parsed: unknown(), - program: string(), - programId: PublicKeyFromString, -}); - -const RawInstructionResult = pick({ - accounts: array(PublicKeyFromString), - data: string(), - programId: PublicKeyFromString, -}); - -const InstructionResult = union([ - RawInstructionResult, - ParsedInstructionResult, -]); - -const UnknownInstructionResult = union([ - pick({ - parsed: unknown(), - program: string(), - programId: string(), - }), - pick({ - accounts: array(string()), - data: string(), - programId: string(), - }), -]); - -const ParsedOrRawInstruction = coerce( - InstructionResult, - UnknownInstructionResult, - value => { - if ('accounts' in value) { - return create(value, RawInstructionResult); - } else { - return create(value, ParsedInstructionResult); - } - }, -); - -/** - * @internal - */ -const ParsedConfirmedTransactionResult = pick({ - signatures: array(string()), - message: pick({ - accountKeys: array(AnnotatedAccountKey), - instructions: array(ParsedOrRawInstruction), - recentBlockhash: string(), - addressTableLookups: optional(nullable(array(AddressTableLookupStruct))), - }), -}); - -const TokenBalanceResult = pick({ - accountIndex: number(), - mint: string(), - owner: optional(string()), - uiTokenAmount: TokenAmountResult, -}); - -const LoadedAddressesResult = pick({ - writable: array(PublicKeyFromString), - readonly: array(PublicKeyFromString), -}); - -/** - * @internal - */ -const ConfirmedTransactionMetaResult = pick({ - err: TransactionErrorResult, - fee: number(), - innerInstructions: optional( - nullable( - array( - pick({ - index: number(), - instructions: array( - pick({ - accounts: array(number()), - data: string(), - programIdIndex: number(), - }), - ), - }), - ), - ), - ), - preBalances: array(number()), - postBalances: array(number()), - logMessages: optional(nullable(array(string()))), - preTokenBalances: optional(nullable(array(TokenBalanceResult))), - postTokenBalances: optional(nullable(array(TokenBalanceResult))), - loadedAddresses: optional(LoadedAddressesResult), - computeUnitsConsumed: optional(number()), -}); - -/** - * @internal - */ -const ParsedConfirmedTransactionMetaResult = pick({ - err: TransactionErrorResult, - fee: number(), - innerInstructions: optional( - nullable( - array( - pick({ - index: number(), - instructions: array(ParsedOrRawInstruction), - }), - ), - ), - ), - preBalances: array(number()), - postBalances: array(number()), - logMessages: optional(nullable(array(string()))), - preTokenBalances: optional(nullable(array(TokenBalanceResult))), - postTokenBalances: optional(nullable(array(TokenBalanceResult))), - loadedAddresses: optional(LoadedAddressesResult), - computeUnitsConsumed: optional(number()), -}); - -const TransactionVersionStruct = union([literal(0), literal('legacy')]); - -/** @internal */ -const RewardsResult = pick({ - pubkey: string(), - lamports: number(), - postBalance: nullable(number()), - rewardType: nullable(string()), - commission: optional(nullable(number())), -}); - -/** - * Expected JSON RPC response for the "getBlock" message - */ -const GetBlockRpcResult = jsonRpcResult( - nullable( - pick({ - blockhash: string(), - previousBlockhash: string(), - parentSlot: number(), - transactions: array( - pick({ - transaction: ConfirmedTransactionResult, - meta: nullable(ConfirmedTransactionMetaResult), - version: optional(TransactionVersionStruct), - }), - ), - rewards: optional(array(RewardsResult)), - blockTime: nullable(number()), - blockHeight: nullable(number()), - }), - ), -); - -/** - * Expected JSON RPC response for the "getBlock" message when `transactionDetails` is `none` - */ -const GetNoneModeBlockRpcResult = jsonRpcResult( - nullable( - pick({ - blockhash: string(), - previousBlockhash: string(), - parentSlot: number(), - rewards: optional(array(RewardsResult)), - blockTime: nullable(number()), - blockHeight: nullable(number()), - }), - ), -); - -/** - * Expected JSON RPC response for the "getBlock" message when `transactionDetails` is `accounts` - */ -const GetAccountsModeBlockRpcResult = jsonRpcResult( - nullable( - pick({ - blockhash: string(), - previousBlockhash: string(), - parentSlot: number(), - transactions: array( - pick({ - transaction: ConfirmedTransactionAccountsModeResult, - meta: nullable(ConfirmedTransactionMetaResult), - version: optional(TransactionVersionStruct), - }), - ), - rewards: optional(array(RewardsResult)), - blockTime: nullable(number()), - blockHeight: nullable(number()), - }), - ), -); - -/** - * Expected parsed JSON RPC response for the "getBlock" message - */ -const GetParsedBlockRpcResult = jsonRpcResult( - nullable( - pick({ - blockhash: string(), - previousBlockhash: string(), - parentSlot: number(), - transactions: array( - pick({ - transaction: ParsedConfirmedTransactionResult, - meta: nullable(ParsedConfirmedTransactionMetaResult), - version: optional(TransactionVersionStruct), - }), - ), - rewards: optional(array(RewardsResult)), - blockTime: nullable(number()), - blockHeight: nullable(number()), - }), - ), -); - -/** - * Expected parsed JSON RPC response for the "getBlock" message when `transactionDetails` is `accounts` - */ -const GetParsedAccountsModeBlockRpcResult = jsonRpcResult( - nullable( - pick({ - blockhash: string(), - previousBlockhash: string(), - parentSlot: number(), - transactions: array( - pick({ - transaction: ConfirmedTransactionAccountsModeResult, - meta: nullable(ParsedConfirmedTransactionMetaResult), - version: optional(TransactionVersionStruct), - }), - ), - rewards: optional(array(RewardsResult)), - blockTime: nullable(number()), - blockHeight: nullable(number()), - }), - ), -); - -/** - * Expected parsed JSON RPC response for the "getBlock" message when `transactionDetails` is `none` - */ -const GetParsedNoneModeBlockRpcResult = jsonRpcResult( - nullable( - pick({ - blockhash: string(), - previousBlockhash: string(), - parentSlot: number(), - rewards: optional(array(RewardsResult)), - blockTime: nullable(number()), - blockHeight: nullable(number()), - }), - ), -); - -/** - * Expected JSON RPC response for the "getConfirmedBlock" message - * - * @deprecated Deprecated since RPC v1.8.0. Please use {@link GetBlockRpcResult} instead. - */ -const GetConfirmedBlockRpcResult = jsonRpcResult( - nullable( - pick({ - blockhash: string(), - previousBlockhash: string(), - parentSlot: number(), - transactions: array( - pick({ - transaction: ConfirmedTransactionResult, - meta: nullable(ConfirmedTransactionMetaResult), - }), - ), - rewards: optional(array(RewardsResult)), - blockTime: nullable(number()), - }), - ), -); - -/** - * Expected JSON RPC response for the "getBlock" message - */ -const GetBlockSignaturesRpcResult = jsonRpcResult( - nullable( - pick({ - blockhash: string(), - previousBlockhash: string(), - parentSlot: number(), - signatures: array(string()), - blockTime: nullable(number()), - }), - ), -); - -/** - * Expected JSON RPC response for the "getTransaction" message - */ -const GetTransactionRpcResult = jsonRpcResult( - nullable( - pick({ - slot: number(), - meta: nullable(ConfirmedTransactionMetaResult), - blockTime: optional(nullable(number())), - transaction: ConfirmedTransactionResult, - version: optional(TransactionVersionStruct), - }), - ), -); - -/** - * Expected parsed JSON RPC response for the "getTransaction" message - */ -const GetParsedTransactionRpcResult = jsonRpcResult( - nullable( - pick({ - slot: number(), - transaction: ParsedConfirmedTransactionResult, - meta: nullable(ParsedConfirmedTransactionMetaResult), - blockTime: optional(nullable(number())), - version: optional(TransactionVersionStruct), - }), - ), -); - -/** - * Expected JSON RPC response for the "getRecentBlockhash" message - * - * @deprecated Deprecated since RPC v1.8.0. Please use {@link GetLatestBlockhashRpcResult} instead. - */ -const GetRecentBlockhashAndContextRpcResult = jsonRpcResultAndContext( - pick({ - blockhash: string(), - feeCalculator: pick({ - lamportsPerSignature: number(), - }), - }), -); - -/** - * Expected JSON RPC response for the "getLatestBlockhash" message - */ -const GetLatestBlockhashRpcResult = jsonRpcResultAndContext( - pick({ - blockhash: string(), - lastValidBlockHeight: number(), - }), -); - -/** - * Expected JSON RPC response for the "isBlockhashValid" message - */ -const IsBlockhashValidRpcResult = jsonRpcResultAndContext(boolean()); - -const PerfSampleResult = pick({ - slot: number(), - numTransactions: number(), - numSlots: number(), - samplePeriodSecs: number(), -}); - -/* - * Expected JSON RPC response for "getRecentPerformanceSamples" message - */ -const GetRecentPerformanceSamplesRpcResult = jsonRpcResult( - array(PerfSampleResult), -); - -/** - * Expected JSON RPC response for the "getFeeCalculatorForBlockhash" message - */ -const GetFeeCalculatorRpcResult = jsonRpcResultAndContext( - nullable( - pick({ - feeCalculator: pick({ - lamportsPerSignature: number(), - }), - }), - ), -); - -/** - * Expected JSON RPC response for the "requestAirdrop" message - */ -const RequestAirdropRpcResult = jsonRpcResult(string()); - -/** - * Expected JSON RPC response for the "sendTransaction" message - */ -const SendTransactionRpcResult = jsonRpcResult(string()); - -/** - * Information about the latest slot being processed by a node - */ -export type SlotInfo = { - /** Currently processing slot */ - slot: number; - /** Parent of the current slot */ - parent: number; - /** The root block of the current slot's fork */ - root: number; -}; - -/** - * Parsed account data - */ -export type ParsedAccountData = { - /** Name of the program that owns this account */ - program: string; - /** Parsed account data */ - parsed: any; - /** Space used by account data */ - space: number; -}; - -/** - * Stake Activation data - */ -export type StakeActivationData = { - /** the stake account's activation state */ - state: 'active' | 'inactive' | 'activating' | 'deactivating'; - /** stake active during the epoch */ - active: number; - /** stake inactive during the epoch */ - inactive: number; -}; - -/** - * Data slice argument for getProgramAccounts - */ -export type DataSlice = { - /** offset of data slice */ - offset: number; - /** length of data slice */ - length: number; -}; - -/** - * Memory comparison filter for getProgramAccounts - */ -export type MemcmpFilter = { - memcmp: { - /** offset into program account data to start comparison */ - offset: number; - } & ( - | { - encoding?: 'base58'; // Base-58 is the default when not supplied. - /** data to match, as base-58 encoded string and limited to less than 129 bytes */ - bytes: string; - } - | { - encoding: 'base64'; - /** data to match, as base-64 encoded string */ - bytes: string; - } - ); -}; - -/** - * Data size comparison filter for getProgramAccounts - */ -export type DataSizeFilter = { - /** Size of data for program account data length comparison */ - dataSize: number; -}; - -/** - * A filter object for getProgramAccounts - */ -export type GetProgramAccountsFilter = MemcmpFilter | DataSizeFilter; - -/** - * Configuration object for getProgramAccounts requests - */ -export type GetProgramAccountsConfig = { - /** Optional commitment level */ - commitment?: Commitment; - /** Optional encoding for account data (default base64) - * To use "jsonParsed" encoding, please refer to `getParsedProgramAccounts` in connection.ts - * */ - encoding?: 'base64'; - /** Optional data slice to limit the returned account data */ - dataSlice?: DataSlice; - /** Optional array of filters to apply to accounts */ - filters?: GetProgramAccountsFilter[]; - /** The minimum slot that the request can be evaluated at */ - minContextSlot?: number; - /** wrap the result in an RpcResponse JSON object */ - withContext?: boolean; -}; - -export type GetProgramAccountsResponse = readonly Readonly<{ - account: AccountInfo; - /** the account Pubkey as base-58 encoded string */ - pubkey: PublicKey; -}>[]; - -/** - * Configuration object for getParsedProgramAccounts - */ -export type GetParsedProgramAccountsConfig = { - /** Optional commitment level */ - commitment?: Commitment; - /** Optional array of filters to apply to accounts */ - filters?: GetProgramAccountsFilter[]; - /** The minimum slot that the request can be evaluated at */ - minContextSlot?: number; -}; - -/** - * Configuration object for getMultipleAccounts - */ -export type GetMultipleAccountsConfig = { - /** Optional commitment level */ - commitment?: Commitment; - /** The minimum slot that the request can be evaluated at */ - minContextSlot?: number; - /** Optional data slice to limit the returned account data */ - dataSlice?: DataSlice; -}; - -/** - * Configuration object for `getStakeActivation` - */ -export type GetStakeActivationConfig = { - /** Optional commitment level */ - commitment?: Commitment; - /** Epoch for which to calculate activation details. If parameter not provided, defaults to current epoch */ - epoch?: number; - /** The minimum slot that the request can be evaluated at */ - minContextSlot?: number; -}; - -/** - * Configuration object for `getStakeActivation` - */ -export type GetTokenAccountsByOwnerConfig = { - /** Optional commitment level */ - commitment?: Commitment; - /** The minimum slot that the request can be evaluated at */ - minContextSlot?: number; -}; - -/** - * Configuration object for `getStakeActivation` - */ -export type GetTransactionCountConfig = { - /** Optional commitment level */ - commitment?: Commitment; - /** The minimum slot that the request can be evaluated at */ - minContextSlot?: number; -}; - -/** - * Configuration object for `getNonce` - */ -export type GetNonceConfig = { - /** Optional commitment level */ - commitment?: Commitment; - /** The minimum slot that the request can be evaluated at */ - minContextSlot?: number; -}; - -/** - * Configuration object for `getNonceAndContext` - */ -export type GetNonceAndContextConfig = { - /** Optional commitment level */ - commitment?: Commitment; - /** The minimum slot that the request can be evaluated at */ - minContextSlot?: number; -}; - -export type AccountSubscriptionConfig = Readonly<{ - /** Optional commitment level */ - commitment?: Commitment; - /** - * Encoding format for Account data - * - `base58` is slow. - * - `jsonParsed` encoding attempts to use program-specific state parsers to return more - * human-readable and explicit account state data - * - If `jsonParsed` is requested but a parser cannot be found, the field falls back to `base64` - * encoding, detectable when the `data` field is type `string`. - */ - encoding?: 'base58' | 'base64' | 'base64+zstd' | 'jsonParsed'; -}>; - -export type ProgramAccountSubscriptionConfig = Readonly<{ - /** Optional commitment level */ - commitment?: Commitment; - /** - * Encoding format for Account data - * - `base58` is slow. - * - `jsonParsed` encoding attempts to use program-specific state parsers to return more - * human-readable and explicit account state data - * - If `jsonParsed` is requested but a parser cannot be found, the field falls back to `base64` - * encoding, detectable when the `data` field is type `string`. - */ - encoding?: 'base58' | 'base64' | 'base64+zstd' | 'jsonParsed'; - /** - * Filter results using various filter objects - * The resultant account must meet ALL filter criteria to be included in the returned results - */ - filters?: GetProgramAccountsFilter[]; -}>; - -/** - * Information describing an account - */ -export type AccountInfo = { - /** `true` if this account's data contains a loaded program */ - executable: boolean; - /** Identifier of the program that owns the account */ - owner: PublicKey; - /** Number of lamports assigned to the account */ - lamports: number; - /** Optional data assigned to the account */ - data: T; - /** Optional rent epoch info for account */ - rentEpoch?: number; -}; - -/** - * Account information identified by pubkey - */ -export type KeyedAccountInfo = { - accountId: PublicKey; - accountInfo: AccountInfo; -}; - -/** - * Callback function for account change notifications - */ -export type AccountChangeCallback = ( - accountInfo: AccountInfo, - context: Context, -) => void; - -/** - * Callback function for program account change notifications - */ -export type ProgramAccountChangeCallback = ( - keyedAccountInfo: KeyedAccountInfo, - context: Context, -) => void; - -/** - * Callback function for slot change notifications - */ -export type SlotChangeCallback = (slotInfo: SlotInfo) => void; - -/** - * Callback function for slot update notifications - */ -export type SlotUpdateCallback = (slotUpdate: SlotUpdate) => void; - -/** - * Callback function for signature status notifications - */ -export type SignatureResultCallback = ( - signatureResult: SignatureResult, - context: Context, -) => void; - -/** - * Signature status notification with transaction result - */ -export type SignatureStatusNotification = { - type: 'status'; - result: SignatureResult; -}; - -/** - * Signature received notification - */ -export type SignatureReceivedNotification = { - type: 'received'; -}; - -/** - * Callback function for signature notifications - */ -export type SignatureSubscriptionCallback = ( - notification: SignatureStatusNotification | SignatureReceivedNotification, - context: Context, -) => void; - -/** - * Signature subscription options - */ -export type SignatureSubscriptionOptions = { - commitment?: Commitment; - enableReceivedNotification?: boolean; -}; - -/** - * Callback function for root change notifications - */ -export type RootChangeCallback = (root: number) => void; - -/** - * @internal - */ -const LogsResult = pick({ - err: TransactionErrorResult, - logs: array(string()), - signature: string(), -}); - -/** - * Logs result. - */ -export type Logs = { - err: TransactionError | null; - logs: string[]; - signature: string; -}; - -/** - * Expected JSON RPC response for the "logsNotification" message. - */ -const LogsNotificationResult = pick({ - result: notificationResultAndContext(LogsResult), - subscription: number(), -}); - -/** - * Filter for log subscriptions. - */ -export type LogsFilter = PublicKey | 'all' | 'allWithVotes'; - -/** - * Callback function for log notifications. - */ -export type LogsCallback = (logs: Logs, ctx: Context) => void; - -/** - * Signature result - */ -export type SignatureResult = { - err: TransactionError | null; -}; - -/** - * Transaction error - */ -export type TransactionError = {} | string; - -/** - * Transaction confirmation status - *
- *   'processed': Transaction landed in a block which has reached 1 confirmation by the connected node
- *   'confirmed': Transaction landed in a block which has reached 1 confirmation by the cluster
- *   'finalized': Transaction landed in a block which has been finalized by the cluster
- * 
- */ -export type TransactionConfirmationStatus = - | 'processed' - | 'confirmed' - | 'finalized'; - -/** - * Signature status - */ -export type SignatureStatus = { - /** when the transaction was processed */ - slot: number; - /** the number of blocks that have been confirmed and voted on in the fork containing `slot` */ - confirmations: number | null; - /** transaction error, if any */ - err: TransactionError | null; - /** cluster confirmation status, if data available. Possible responses: `processed`, `confirmed`, `finalized` */ - confirmationStatus?: TransactionConfirmationStatus; -}; - -/** - * A confirmed signature with its status - */ -export type ConfirmedSignatureInfo = { - /** the transaction signature */ - signature: string; - /** when the transaction was processed */ - slot: number; - /** error, if any */ - err: TransactionError | null; - /** memo associated with the transaction, if any */ - memo: string | null; - /** The unix timestamp of when the transaction was processed */ - blockTime?: number | null; - /** Cluster confirmation status, if available. Possible values: `processed`, `confirmed`, `finalized` */ - confirmationStatus?: TransactionConfirmationStatus; -}; - -/** - * An object defining headers to be passed to the RPC server - */ -export type HttpHeaders = { - [header: string]: string; -} & { - // Prohibited headers; for internal use only. - 'solana-client'?: never; -}; - -/** - * The type of the JavaScript `fetch()` API - */ -export type FetchFn = typeof fetchImpl; - -/** - * A callback used to augment the outgoing HTTP request - */ -export type FetchMiddleware = ( - info: Parameters[0], - init: Parameters[1], - fetch: (...a: Parameters) => void, -) => void; - -/** - * Configuration for instantiating a Connection - */ -export type ConnectionConfig = { - /** - * An `http.Agent` that will be used to manage socket connections (eg. to implement connection - * persistence). Set this to `false` to create a connection that uses no agent. This applies to - * Node environments only. - */ - httpAgent?: NodeHttpAgent | NodeHttpsAgent | false; - /** Optional commitment level */ - commitment?: Commitment; - /** Optional endpoint URL to the fullnode JSON RPC PubSub WebSocket Endpoint */ - wsEndpoint?: string; - /** Optional HTTP headers object */ - httpHeaders?: HttpHeaders; - /** Optional custom fetch function */ - fetch?: FetchFn; - /** Optional fetch middleware callback */ - fetchMiddleware?: FetchMiddleware; - /** Optional Disable retrying calls when server responds with HTTP 429 (Too Many Requests) */ - disableRetryOnRateLimit?: boolean; - /** time to allow for the server to initially process a transaction (in milliseconds) */ - confirmTransactionInitialTimeout?: number; -}; - -/** @internal */ -const COMMON_HTTP_HEADERS = { - 'solana-client': `js/${process.env.npm_package_version ?? 'UNKNOWN'}`, -}; - -/** - * A connection to a fullnode JSON RPC endpoint - */ -export class Connection { - /** @internal */ _commitment?: Commitment; - /** @internal */ _confirmTransactionInitialTimeout?: number; - /** @internal */ _rpcEndpoint: string; - /** @internal */ _rpcWsEndpoint: string; - /** @internal */ _rpcClient: RpcClient; - /** @internal */ _rpcRequest: RpcRequest; - /** @internal */ _rpcBatchRequest: RpcBatchRequest; - /** @internal */ _rpcWebSocket: RpcWebSocketClient; - /** @internal */ _rpcWebSocketConnected: boolean = false; - /** @internal */ _rpcWebSocketHeartbeat: ReturnType< - typeof setInterval - > | null = null; - /** @internal */ _rpcWebSocketIdleTimeout: ReturnType< - typeof setTimeout - > | null = null; - /** @internal - * A number that we increment every time an active connection closes. - * Used to determine whether the same socket connection that was open - * when an async operation started is the same one that's active when - * its continuation fires. - * - */ private _rpcWebSocketGeneration: number = 0; - - /** @internal */ _disableBlockhashCaching: boolean = false; - /** @internal */ _pollingBlockhash: boolean = false; - /** @internal */ _blockhashInfo: { - latestBlockhash: BlockhashWithExpiryBlockHeight | null; - lastFetch: number; - simulatedSignatures: Array; - transactionSignatures: Array; - } = { - latestBlockhash: null, - lastFetch: 0, - transactionSignatures: [], - simulatedSignatures: [], - }; - - /** @internal */ private _nextClientSubscriptionId: ClientSubscriptionId = 0; - /** @internal */ private _subscriptionDisposeFunctionsByClientSubscriptionId: { - [clientSubscriptionId: ClientSubscriptionId]: - | SubscriptionDisposeFn - | undefined; - } = {}; - /** @internal */ private _subscriptionHashByClientSubscriptionId: { - [clientSubscriptionId: ClientSubscriptionId]: - | SubscriptionConfigHash - | undefined; - } = {}; - /** @internal */ private _subscriptionStateChangeCallbacksByHash: { - [hash: SubscriptionConfigHash]: - | Set - | undefined; - } = {}; - /** @internal */ private _subscriptionCallbacksByServerSubscriptionId: { - [serverSubscriptionId: ServerSubscriptionId]: - | Set - | undefined; - } = {}; - /** @internal */ private _subscriptionsByHash: { - [hash: SubscriptionConfigHash]: Subscription | undefined; - } = {}; - /** - * Special case. - * After a signature is processed, RPCs automatically dispose of the - * subscription on the server side. We need to track which of these - * subscriptions have been disposed in such a way, so that we know - * whether the client is dealing with a not-yet-processed signature - * (in which case we must tear down the server subscription) or an - * already-processed signature (in which case the client can simply - * clear out the subscription locally without telling the server). - * - * NOTE: There is a proposal to eliminate this special case, here: - * https://github.com/solana-labs/solana/issues/18892 - */ - /** @internal */ private _subscriptionsAutoDisposedByRpc: Set = - new Set(); - - /** - * Establish a JSON RPC connection - * - * @param endpoint URL to the fullnode JSON RPC endpoint - * @param commitmentOrConfig optional default commitment level or optional ConnectionConfig configuration object - */ - constructor( - endpoint: string, - commitmentOrConfig?: Commitment | ConnectionConfig, - ) { - let wsEndpoint; - let httpHeaders; - let fetch; - let fetchMiddleware; - let disableRetryOnRateLimit; - let httpAgent; - if (commitmentOrConfig && typeof commitmentOrConfig === 'string') { - this._commitment = commitmentOrConfig; - } else if (commitmentOrConfig) { - this._commitment = commitmentOrConfig.commitment; - this._confirmTransactionInitialTimeout = - commitmentOrConfig.confirmTransactionInitialTimeout; - wsEndpoint = commitmentOrConfig.wsEndpoint; - httpHeaders = commitmentOrConfig.httpHeaders; - fetch = commitmentOrConfig.fetch; - fetchMiddleware = commitmentOrConfig.fetchMiddleware; - disableRetryOnRateLimit = commitmentOrConfig.disableRetryOnRateLimit; - httpAgent = commitmentOrConfig.httpAgent; - } - - this._rpcEndpoint = assertEndpointUrl(endpoint); - this._rpcWsEndpoint = wsEndpoint || makeWebsocketUrl(endpoint); - - this._rpcClient = createRpcClient( - endpoint, - httpHeaders, - fetch, - fetchMiddleware, - disableRetryOnRateLimit, - httpAgent, - ); - this._rpcRequest = createRpcRequest(this._rpcClient); - this._rpcBatchRequest = createRpcBatchRequest(this._rpcClient); - - this._rpcWebSocket = new RpcWebSocketClient(this._rpcWsEndpoint, { - autoconnect: false, - max_reconnects: Infinity, - }); - this._rpcWebSocket.on('open', this._wsOnOpen.bind(this)); - this._rpcWebSocket.on('error', this._wsOnError.bind(this)); - this._rpcWebSocket.on('close', this._wsOnClose.bind(this)); - this._rpcWebSocket.on( - 'accountNotification', - this._wsOnAccountNotification.bind(this), - ); - this._rpcWebSocket.on( - 'programNotification', - this._wsOnProgramAccountNotification.bind(this), - ); - this._rpcWebSocket.on( - 'slotNotification', - this._wsOnSlotNotification.bind(this), - ); - this._rpcWebSocket.on( - 'slotsUpdatesNotification', - this._wsOnSlotUpdatesNotification.bind(this), - ); - this._rpcWebSocket.on( - 'signatureNotification', - this._wsOnSignatureNotification.bind(this), - ); - this._rpcWebSocket.on( - 'rootNotification', - this._wsOnRootNotification.bind(this), - ); - this._rpcWebSocket.on( - 'logsNotification', - this._wsOnLogsNotification.bind(this), - ); - } - - /** - * The default commitment used for requests - */ - get commitment(): Commitment | undefined { - return this._commitment; - } - - /** - * The RPC endpoint - */ - get rpcEndpoint(): string { - return this._rpcEndpoint; - } - - /** - * Fetch the balance for the specified public key, return with context - */ - async getBalanceAndContext( - publicKey: PublicKey, - commitmentOrConfig?: Commitment | GetBalanceConfig, - ): Promise> { - /** @internal */ - const {commitment, config} = - extractCommitmentFromConfig(commitmentOrConfig); - const args = this._buildArgs( - [publicKey.toBase58()], - commitment, - undefined /* encoding */, - config, - ); - const unsafeRes = await this._rpcRequest('getBalance', args); - const res = create(unsafeRes, jsonRpcResultAndContext(number())); - if ('error' in res) { - throw new SolanaJSONRPCError( - res.error, - `failed to get balance for ${publicKey.toBase58()}`, - ); - } - return res.result; - } - - /** - * Fetch the balance for the specified public key - */ - async getBalance( - publicKey: PublicKey, - commitmentOrConfig?: Commitment | GetBalanceConfig, - ): Promise { - return await this.getBalanceAndContext(publicKey, commitmentOrConfig) - .then(x => x.value) - .catch(e => { - throw new Error( - 'failed to get balance of account ' + publicKey.toBase58() + ': ' + e, - ); - }); - } - - /** - * Fetch the estimated production time of a block - */ - async getBlockTime(slot: number): Promise { - const unsafeRes = await this._rpcRequest('getBlockTime', [slot]); - const res = create(unsafeRes, jsonRpcResult(nullable(number()))); - if ('error' in res) { - throw new SolanaJSONRPCError( - res.error, - `failed to get block time for slot ${slot}`, - ); - } - return res.result; - } - - /** - * Fetch the lowest slot that the node has information about in its ledger. - * This value may increase over time if the node is configured to purge older ledger data - */ - async getMinimumLedgerSlot(): Promise { - const unsafeRes = await this._rpcRequest('minimumLedgerSlot', []); - const res = create(unsafeRes, jsonRpcResult(number())); - if ('error' in res) { - throw new SolanaJSONRPCError( - res.error, - 'failed to get minimum ledger slot', - ); - } - return res.result; - } - - /** - * Fetch the slot of the lowest confirmed block that has not been purged from the ledger - */ - async getFirstAvailableBlock(): Promise { - const unsafeRes = await this._rpcRequest('getFirstAvailableBlock', []); - const res = create(unsafeRes, SlotRpcResult); - if ('error' in res) { - throw new SolanaJSONRPCError( - res.error, - 'failed to get first available block', - ); - } - return res.result; - } - - /** - * Fetch information about the current supply - */ - async getSupply( - config?: GetSupplyConfig | Commitment, - ): Promise> { - let configArg: GetSupplyConfig = {}; - if (typeof config === 'string') { - configArg = {commitment: config}; - } else if (config) { - configArg = { - ...config, - commitment: (config && config.commitment) || this.commitment, - }; - } else { - configArg = { - commitment: this.commitment, - }; - } - - const unsafeRes = await this._rpcRequest('getSupply', [configArg]); - const res = create(unsafeRes, GetSupplyRpcResult); - if ('error' in res) { - throw new SolanaJSONRPCError(res.error, 'failed to get supply'); - } - return res.result; - } - - /** - * Fetch the current supply of a token mint - */ - async getTokenSupply( - tokenMintAddress: PublicKey, - commitment?: Commitment, - ): Promise> { - const args = this._buildArgs([tokenMintAddress.toBase58()], commitment); - const unsafeRes = await this._rpcRequest('getTokenSupply', args); - const res = create(unsafeRes, jsonRpcResultAndContext(TokenAmountResult)); - if ('error' in res) { - throw new SolanaJSONRPCError(res.error, 'failed to get token supply'); - } - return res.result; - } - - /** - * Fetch the current balance of a token account - */ - async getTokenAccountBalance( - tokenAddress: PublicKey, - commitment?: Commitment, - ): Promise> { - const args = this._buildArgs([tokenAddress.toBase58()], commitment); - const unsafeRes = await this._rpcRequest('getTokenAccountBalance', args); - const res = create(unsafeRes, jsonRpcResultAndContext(TokenAmountResult)); - if ('error' in res) { - throw new SolanaJSONRPCError( - res.error, - 'failed to get token account balance', - ); - } - return res.result; - } - - /** - * Fetch all the token accounts owned by the specified account - * - * @return {Promise} - */ - async getTokenAccountsByOwner( - ownerAddress: PublicKey, - filter: TokenAccountsFilter, - commitmentOrConfig?: Commitment | GetTokenAccountsByOwnerConfig, - ): Promise> { - const {commitment, config} = - extractCommitmentFromConfig(commitmentOrConfig); - let _args: any[] = [ownerAddress.toBase58()]; - if ('mint' in filter) { - _args.push({mint: filter.mint.toBase58()}); - } else { - _args.push({programId: filter.programId.toBase58()}); - } - - const args = this._buildArgs(_args, commitment, 'base64', config); - const unsafeRes = await this._rpcRequest('getTokenAccountsByOwner', args); - const res = create(unsafeRes, GetTokenAccountsByOwner); - if ('error' in res) { - throw new SolanaJSONRPCError( - res.error, - `failed to get token accounts owned by account ${ownerAddress.toBase58()}`, - ); - } - return res.result; - } - - /** - * Fetch parsed token accounts owned by the specified account - * - * @return {Promise}>>>} - */ - async getParsedTokenAccountsByOwner( - ownerAddress: PublicKey, - filter: TokenAccountsFilter, - commitment?: Commitment, - ): Promise< - RpcResponseAndContext< - Array<{pubkey: PublicKey; account: AccountInfo}> - > - > { - let _args: any[] = [ownerAddress.toBase58()]; - if ('mint' in filter) { - _args.push({mint: filter.mint.toBase58()}); - } else { - _args.push({programId: filter.programId.toBase58()}); - } - - const args = this._buildArgs(_args, commitment, 'jsonParsed'); - const unsafeRes = await this._rpcRequest('getTokenAccountsByOwner', args); - const res = create(unsafeRes, GetParsedTokenAccountsByOwner); - if ('error' in res) { - throw new SolanaJSONRPCError( - res.error, - `failed to get token accounts owned by account ${ownerAddress.toBase58()}`, - ); - } - return res.result; - } - - /** - * Fetch the 20 largest accounts with their current balances - */ - async getLargestAccounts( - config?: GetLargestAccountsConfig, - ): Promise>> { - const arg = { - ...config, - commitment: (config && config.commitment) || this.commitment, - }; - const args = arg.filter || arg.commitment ? [arg] : []; - const unsafeRes = await this._rpcRequest('getLargestAccounts', args); - const res = create(unsafeRes, GetLargestAccountsRpcResult); - if ('error' in res) { - throw new SolanaJSONRPCError(res.error, 'failed to get largest accounts'); - } - return res.result; - } - - /** - * Fetch the 20 largest token accounts with their current balances - * for a given mint. - */ - async getTokenLargestAccounts( - mintAddress: PublicKey, - commitment?: Commitment, - ): Promise>> { - const args = this._buildArgs([mintAddress.toBase58()], commitment); - const unsafeRes = await this._rpcRequest('getTokenLargestAccounts', args); - const res = create(unsafeRes, GetTokenLargestAccountsResult); - if ('error' in res) { - throw new SolanaJSONRPCError( - res.error, - 'failed to get token largest accounts', - ); - } - return res.result; - } - - /** - * Fetch all the account info for the specified public key, return with context - */ - async getAccountInfoAndContext( - publicKey: PublicKey, - commitmentOrConfig?: Commitment | GetAccountInfoConfig, - ): Promise | null>> { - const {commitment, config} = - extractCommitmentFromConfig(commitmentOrConfig); - const args = this._buildArgs( - [publicKey.toBase58()], - commitment, - 'base64', - config, - ); - const unsafeRes = await this._rpcRequest('getAccountInfo', args); - const res = create( - unsafeRes, - jsonRpcResultAndContext(nullable(AccountInfoResult)), - ); - if ('error' in res) { - throw new SolanaJSONRPCError( - res.error, - `failed to get info about account ${publicKey.toBase58()}`, - ); - } - return res.result; - } - - /** - * Fetch parsed account info for the specified public key - */ - async getParsedAccountInfo( - publicKey: PublicKey, - commitmentOrConfig?: Commitment | GetAccountInfoConfig, - ): Promise< - RpcResponseAndContext | null> - > { - const {commitment, config} = - extractCommitmentFromConfig(commitmentOrConfig); - const args = this._buildArgs( - [publicKey.toBase58()], - commitment, - 'jsonParsed', - config, - ); - const unsafeRes = await this._rpcRequest('getAccountInfo', args); - const res = create( - unsafeRes, - jsonRpcResultAndContext(nullable(ParsedAccountInfoResult)), - ); - if ('error' in res) { - throw new SolanaJSONRPCError( - res.error, - `failed to get info about account ${publicKey.toBase58()}`, - ); - } - return res.result; - } - - /** - * Fetch all the account info for the specified public key - */ - async getAccountInfo( - publicKey: PublicKey, - commitmentOrConfig?: Commitment | GetAccountInfoConfig, - ): Promise | null> { - try { - const res = await this.getAccountInfoAndContext( - publicKey, - commitmentOrConfig, - ); - return res.value; - } catch (e) { - throw new Error( - 'failed to get info about account ' + publicKey.toBase58() + ': ' + e, - ); - } - } - - /** - * Fetch all the account info for multiple accounts specified by an array of public keys, return with context - */ - async getMultipleParsedAccounts( - publicKeys: PublicKey[], - rawConfig?: GetMultipleAccountsConfig, - ): Promise< - RpcResponseAndContext<(AccountInfo | null)[]> - > { - const {commitment, config} = extractCommitmentFromConfig(rawConfig); - const keys = publicKeys.map(key => key.toBase58()); - const args = this._buildArgs([keys], commitment, 'jsonParsed', config); - const unsafeRes = await this._rpcRequest('getMultipleAccounts', args); - const res = create( - unsafeRes, - jsonRpcResultAndContext(array(nullable(ParsedAccountInfoResult))), - ); - if ('error' in res) { - throw new SolanaJSONRPCError( - res.error, - `failed to get info for accounts ${keys}`, - ); - } - return res.result; - } - - /** - * Fetch all the account info for multiple accounts specified by an array of public keys, return with context - */ - async getMultipleAccountsInfoAndContext( - publicKeys: PublicKey[], - commitmentOrConfig?: Commitment | GetMultipleAccountsConfig, - ): Promise | null)[]>> { - const {commitment, config} = - extractCommitmentFromConfig(commitmentOrConfig); - const keys = publicKeys.map(key => key.toBase58()); - const args = this._buildArgs([keys], commitment, 'base64', config); - const unsafeRes = await this._rpcRequest('getMultipleAccounts', args); - const res = create( - unsafeRes, - jsonRpcResultAndContext(array(nullable(AccountInfoResult))), - ); - if ('error' in res) { - throw new SolanaJSONRPCError( - res.error, - `failed to get info for accounts ${keys}`, - ); - } - return res.result; - } - - /** - * Fetch all the account info for multiple accounts specified by an array of public keys - */ - async getMultipleAccountsInfo( - publicKeys: PublicKey[], - commitmentOrConfig?: Commitment | GetMultipleAccountsConfig, - ): Promise<(AccountInfo | null)[]> { - const res = await this.getMultipleAccountsInfoAndContext( - publicKeys, - commitmentOrConfig, - ); - return res.value; - } - - /** - * Returns epoch activation information for a stake account that has been delegated - * - * @deprecated Deprecated since RPC v1.18; will be removed in a future version. - */ - async getStakeActivation( - publicKey: PublicKey, - commitmentOrConfig?: Commitment | GetStakeActivationConfig, - epoch?: number, - ): Promise { - const {commitment, config} = - extractCommitmentFromConfig(commitmentOrConfig); - const args = this._buildArgs( - [publicKey.toBase58()], - commitment, - undefined /* encoding */, - { - ...config, - epoch: epoch != null ? epoch : config?.epoch, - }, - ); - - const unsafeRes = await this._rpcRequest('getStakeActivation', args); - const res = create(unsafeRes, jsonRpcResult(StakeActivationResult)); - if ('error' in res) { - throw new SolanaJSONRPCError( - res.error, - `failed to get Stake Activation ${publicKey.toBase58()}`, - ); - } - return res.result; - } - - /** - * Fetch all the accounts owned by the specified program id - * - * @return {Promise}>>} - */ - async getProgramAccounts( - programId: PublicKey, - configOrCommitment: GetProgramAccountsConfig & - Readonly<{withContext: true}>, - ): Promise>; - // eslint-disable-next-line no-dupe-class-members - async getProgramAccounts( - programId: PublicKey, - configOrCommitment?: GetProgramAccountsConfig | Commitment, - ): Promise; - // eslint-disable-next-line no-dupe-class-members - async getProgramAccounts( - programId: PublicKey, - configOrCommitment?: GetProgramAccountsConfig | Commitment, - ): Promise< - | GetProgramAccountsResponse - | RpcResponseAndContext - > { - const {commitment, config} = - extractCommitmentFromConfig(configOrCommitment); - const {encoding, ...configWithoutEncoding} = config || {}; - const args = this._buildArgs( - [programId.toBase58()], - commitment, - encoding || 'base64', - { - ...configWithoutEncoding, - ...(configWithoutEncoding.filters - ? { - filters: applyDefaultMemcmpEncodingToFilters( - configWithoutEncoding.filters, - ), - } - : null), - }, - ); - const unsafeRes = await this._rpcRequest('getProgramAccounts', args); - const baseSchema = array(KeyedAccountInfoResult); - const res = - configWithoutEncoding.withContext === true - ? create(unsafeRes, jsonRpcResultAndContext(baseSchema)) - : create(unsafeRes, jsonRpcResult(baseSchema)); - if ('error' in res) { - throw new SolanaJSONRPCError( - res.error, - `failed to get accounts owned by program ${programId.toBase58()}`, - ); - } - return res.result; - } - - /** - * Fetch and parse all the accounts owned by the specified program id - * - * @return {Promise}>>} - */ - async getParsedProgramAccounts( - programId: PublicKey, - configOrCommitment?: GetParsedProgramAccountsConfig | Commitment, - ): Promise< - Array<{ - pubkey: PublicKey; - account: AccountInfo; - }> - > { - const {commitment, config} = - extractCommitmentFromConfig(configOrCommitment); - const args = this._buildArgs( - [programId.toBase58()], - commitment, - 'jsonParsed', - config, - ); - const unsafeRes = await this._rpcRequest('getProgramAccounts', args); - const res = create( - unsafeRes, - jsonRpcResult(array(KeyedParsedAccountInfoResult)), - ); - if ('error' in res) { - throw new SolanaJSONRPCError( - res.error, - `failed to get accounts owned by program ${programId.toBase58()}`, - ); - } - return res.result; - } - - confirmTransaction( - strategy: TransactionConfirmationStrategy, - commitment?: Commitment, - ): Promise>; - - /** @deprecated Instead, call `confirmTransaction` and pass in {@link TransactionConfirmationStrategy} */ - // eslint-disable-next-line no-dupe-class-members - confirmTransaction( - strategy: TransactionSignature, - commitment?: Commitment, - ): Promise>; - - // eslint-disable-next-line no-dupe-class-members - async confirmTransaction( - strategy: TransactionConfirmationStrategy | TransactionSignature, - commitment?: Commitment, - ): Promise> { - let rawSignature: string; - - if (typeof strategy == 'string') { - rawSignature = strategy; - } else { - const config = strategy as TransactionConfirmationStrategy; - - if (config.abortSignal?.aborted) { - return Promise.reject(config.abortSignal.reason); - } - rawSignature = config.signature; - } - - let decodedSignature; - - try { - decodedSignature = bs58.decode(rawSignature); - } catch (err) { - throw new Error('signature must be base58 encoded: ' + rawSignature); - } - - assert(decodedSignature.length === 64, 'signature has invalid length'); - - if (typeof strategy === 'string') { - return await this.confirmTransactionUsingLegacyTimeoutStrategy({ - commitment: commitment || this.commitment, - signature: rawSignature, - }); - } else if ('lastValidBlockHeight' in strategy) { - return await this.confirmTransactionUsingBlockHeightExceedanceStrategy({ - commitment: commitment || this.commitment, - strategy, - }); - } else { - return await this.confirmTransactionUsingDurableNonceStrategy({ - commitment: commitment || this.commitment, - strategy, - }); - } - } - - private getCancellationPromise(signal?: AbortSignal): Promise { - return new Promise((_, reject) => { - if (signal == null) { - return; - } - if (signal.aborted) { - reject(signal.reason); - } else { - signal.addEventListener('abort', () => { - reject(signal.reason); - }); - } - }); - } - - private getTransactionConfirmationPromise({ - commitment, - signature, - }: { - commitment?: Commitment; - signature: string; - }): { - abortConfirmation(): void; - confirmationPromise: Promise<{ - __type: TransactionStatus.PROCESSED; - response: RpcResponseAndContext; - }>; - } { - let signatureSubscriptionId: number | undefined; - let disposeSignatureSubscriptionStateChangeObserver: - | SubscriptionStateChangeDisposeFn - | undefined; - let done = false; - const confirmationPromise = new Promise<{ - __type: TransactionStatus.PROCESSED; - response: RpcResponseAndContext; - }>((resolve, reject) => { - try { - signatureSubscriptionId = this.onSignature( - signature, - (result: SignatureResult, context: Context) => { - signatureSubscriptionId = undefined; - const response = { - context, - value: result, - }; - resolve({__type: TransactionStatus.PROCESSED, response}); - }, - commitment, - ); - const subscriptionSetupPromise = new Promise( - resolveSubscriptionSetup => { - if (signatureSubscriptionId == null) { - resolveSubscriptionSetup(); - } else { - disposeSignatureSubscriptionStateChangeObserver = - this._onSubscriptionStateChange( - signatureSubscriptionId, - nextState => { - if (nextState === 'subscribed') { - resolveSubscriptionSetup(); - } - }, - ); - } - }, - ); - (async () => { - await subscriptionSetupPromise; - if (done) return; - const response = await this.getSignatureStatus(signature); - if (done) return; - if (response == null) { - return; - } - const {context, value} = response; - if (value == null) { - return; - } - if (value?.err) { - reject(value.err); - } else { - switch (commitment) { - case 'confirmed': - case 'single': - case 'singleGossip': { - if (value.confirmationStatus === 'processed') { - return; - } - break; - } - case 'finalized': - case 'max': - case 'root': { - if ( - value.confirmationStatus === 'processed' || - value.confirmationStatus === 'confirmed' - ) { - return; - } - break; - } - // exhaust enums to ensure full coverage - case 'processed': - case 'recent': - } - done = true; - resolve({ - __type: TransactionStatus.PROCESSED, - response: { - context, - value, - }, - }); - } - })(); - } catch (err) { - reject(err); - } - }); - const abortConfirmation = () => { - if (disposeSignatureSubscriptionStateChangeObserver) { - disposeSignatureSubscriptionStateChangeObserver(); - disposeSignatureSubscriptionStateChangeObserver = undefined; - } - if (signatureSubscriptionId != null) { - this.removeSignatureListener(signatureSubscriptionId); - signatureSubscriptionId = undefined; - } - }; - return {abortConfirmation, confirmationPromise}; - } - - private async confirmTransactionUsingBlockHeightExceedanceStrategy({ - commitment, - strategy: {abortSignal, lastValidBlockHeight, signature}, - }: { - commitment?: Commitment; - strategy: BlockheightBasedTransactionConfirmationStrategy; - }) { - let done: boolean = false; - const expiryPromise = new Promise<{ - __type: TransactionStatus.BLOCKHEIGHT_EXCEEDED; - }>(resolve => { - const checkBlockHeight = async () => { - try { - const blockHeight = await this.getBlockHeight(commitment); - return blockHeight; - } catch (_e) { - return -1; - } - }; - (async () => { - let currentBlockHeight = await checkBlockHeight(); - if (done) return; - while (currentBlockHeight <= lastValidBlockHeight) { - await sleep(1000); - if (done) return; - currentBlockHeight = await checkBlockHeight(); - if (done) return; - } - resolve({__type: TransactionStatus.BLOCKHEIGHT_EXCEEDED}); - })(); - }); - const {abortConfirmation, confirmationPromise} = - this.getTransactionConfirmationPromise({commitment, signature}); - const cancellationPromise = this.getCancellationPromise(abortSignal); - let result: RpcResponseAndContext; - try { - const outcome = await Promise.race([ - cancellationPromise, - confirmationPromise, - expiryPromise, - ]); - if (outcome.__type === TransactionStatus.PROCESSED) { - result = outcome.response; - } else { - throw new TransactionExpiredBlockheightExceededError(signature); - } - } finally { - done = true; - abortConfirmation(); - } - return result; - } - - private async confirmTransactionUsingDurableNonceStrategy({ - commitment, - strategy: { - abortSignal, - minContextSlot, - nonceAccountPubkey, - nonceValue, - signature, - }, - }: { - commitment?: Commitment; - strategy: DurableNonceTransactionConfirmationStrategy; - }) { - let done: boolean = false; - const expiryPromise = new Promise<{ - __type: TransactionStatus.NONCE_INVALID; - slotInWhichNonceDidAdvance: number | null; - }>(resolve => { - let currentNonceValue: string | undefined = nonceValue; - let lastCheckedSlot: number | null = null; - const getCurrentNonceValue = async () => { - try { - const {context, value: nonceAccount} = await this.getNonceAndContext( - nonceAccountPubkey, - { - commitment, - minContextSlot, - }, - ); - lastCheckedSlot = context.slot; - return nonceAccount?.nonce; - } catch (e) { - // If for whatever reason we can't reach/read the nonce - // account, just keep using the last-known value. - return currentNonceValue; - } - }; - (async () => { - currentNonceValue = await getCurrentNonceValue(); - if (done) return; - while ( - true // eslint-disable-line no-constant-condition - ) { - if (nonceValue !== currentNonceValue) { - resolve({ - __type: TransactionStatus.NONCE_INVALID, - slotInWhichNonceDidAdvance: lastCheckedSlot, - }); - return; - } - await sleep(2000); - if (done) return; - currentNonceValue = await getCurrentNonceValue(); - if (done) return; - } - })(); - }); - const {abortConfirmation, confirmationPromise} = - this.getTransactionConfirmationPromise({commitment, signature}); - const cancellationPromise = this.getCancellationPromise(abortSignal); - let result: RpcResponseAndContext; - try { - const outcome = await Promise.race([ - cancellationPromise, - confirmationPromise, - expiryPromise, - ]); - if (outcome.__type === TransactionStatus.PROCESSED) { - result = outcome.response; - } else { - // Double check that the transaction is indeed unconfirmed. - let signatureStatus: - | RpcResponseAndContext - | null - | undefined; - while ( - true // eslint-disable-line no-constant-condition - ) { - const status = await this.getSignatureStatus(signature); - if (status == null) { - break; - } - if ( - status.context.slot < - (outcome.slotInWhichNonceDidAdvance ?? minContextSlot) - ) { - await sleep(400); - continue; - } - signatureStatus = status; - break; - } - if (signatureStatus?.value) { - const commitmentForStatus = commitment || 'finalized'; - const {confirmationStatus} = signatureStatus.value; - switch (commitmentForStatus) { - case 'processed': - case 'recent': - if ( - confirmationStatus !== 'processed' && - confirmationStatus !== 'confirmed' && - confirmationStatus !== 'finalized' - ) { - throw new TransactionExpiredNonceInvalidError(signature); - } - break; - case 'confirmed': - case 'single': - case 'singleGossip': - if ( - confirmationStatus !== 'confirmed' && - confirmationStatus !== 'finalized' - ) { - throw new TransactionExpiredNonceInvalidError(signature); - } - break; - case 'finalized': - case 'max': - case 'root': - if (confirmationStatus !== 'finalized') { - throw new TransactionExpiredNonceInvalidError(signature); - } - break; - default: - // Exhaustive switch. - // eslint-disable-next-line @typescript-eslint/no-unused-vars - ((_: never) => {})(commitmentForStatus); - } - result = { - context: signatureStatus.context, - value: {err: signatureStatus.value.err}, - }; - } else { - throw new TransactionExpiredNonceInvalidError(signature); - } - } - } finally { - done = true; - abortConfirmation(); - } - return result; - } - - private async confirmTransactionUsingLegacyTimeoutStrategy({ - commitment, - signature, - }: { - commitment?: Commitment; - signature: string; - }) { - let timeoutId; - const expiryPromise = new Promise<{ - __type: TransactionStatus.TIMED_OUT; - timeoutMs: number; - }>(resolve => { - let timeoutMs = this._confirmTransactionInitialTimeout || 60 * 1000; - switch (commitment) { - case 'processed': - case 'recent': - case 'single': - case 'confirmed': - case 'singleGossip': { - timeoutMs = this._confirmTransactionInitialTimeout || 30 * 1000; - break; - } - // exhaust enums to ensure full coverage - case 'finalized': - case 'max': - case 'root': - } - timeoutId = setTimeout( - () => resolve({__type: TransactionStatus.TIMED_OUT, timeoutMs}), - timeoutMs, - ); - }); - const {abortConfirmation, confirmationPromise} = - this.getTransactionConfirmationPromise({ - commitment, - signature, - }); - let result: RpcResponseAndContext; - try { - const outcome = await Promise.race([confirmationPromise, expiryPromise]); - if (outcome.__type === TransactionStatus.PROCESSED) { - result = outcome.response; - } else { - throw new TransactionExpiredTimeoutError( - signature, - outcome.timeoutMs / 1000, - ); - } - } finally { - clearTimeout(timeoutId); - abortConfirmation(); - } - return result; - } - - /** - * Return the list of nodes that are currently participating in the cluster - */ - async getClusterNodes(): Promise> { - const unsafeRes = await this._rpcRequest('getClusterNodes', []); - const res = create(unsafeRes, jsonRpcResult(array(ContactInfoResult))); - if ('error' in res) { - throw new SolanaJSONRPCError(res.error, 'failed to get cluster nodes'); - } - return res.result; - } - - /** - * Return the list of nodes that are currently participating in the cluster - */ - async getVoteAccounts(commitment?: Commitment): Promise { - const args = this._buildArgs([], commitment); - const unsafeRes = await this._rpcRequest('getVoteAccounts', args); - const res = create(unsafeRes, GetVoteAccounts); - if ('error' in res) { - throw new SolanaJSONRPCError(res.error, 'failed to get vote accounts'); - } - return res.result; - } - - /** - * Fetch the current slot that the node is processing - */ - async getSlot( - commitmentOrConfig?: Commitment | GetSlotConfig, - ): Promise { - const {commitment, config} = - extractCommitmentFromConfig(commitmentOrConfig); - const args = this._buildArgs( - [], - commitment, - undefined /* encoding */, - config, - ); - const unsafeRes = await this._rpcRequest('getSlot', args); - const res = create(unsafeRes, jsonRpcResult(number())); - if ('error' in res) { - throw new SolanaJSONRPCError(res.error, 'failed to get slot'); - } - return res.result; - } - - /** - * Fetch the current slot leader of the cluster - */ - async getSlotLeader( - commitmentOrConfig?: Commitment | GetSlotLeaderConfig, - ): Promise { - const {commitment, config} = - extractCommitmentFromConfig(commitmentOrConfig); - const args = this._buildArgs( - [], - commitment, - undefined /* encoding */, - config, - ); - const unsafeRes = await this._rpcRequest('getSlotLeader', args); - const res = create(unsafeRes, jsonRpcResult(string())); - if ('error' in res) { - throw new SolanaJSONRPCError(res.error, 'failed to get slot leader'); - } - return res.result; - } - - /** - * Fetch `limit` number of slot leaders starting from `startSlot` - * - * @param startSlot fetch slot leaders starting from this slot - * @param limit number of slot leaders to return - */ - async getSlotLeaders( - startSlot: number, - limit: number, - ): Promise> { - const args = [startSlot, limit]; - const unsafeRes = await this._rpcRequest('getSlotLeaders', args); - const res = create(unsafeRes, jsonRpcResult(array(PublicKeyFromString))); - if ('error' in res) { - throw new SolanaJSONRPCError(res.error, 'failed to get slot leaders'); - } - return res.result; - } - - /** - * Fetch the current status of a signature - */ - async getSignatureStatus( - signature: TransactionSignature, - config?: SignatureStatusConfig, - ): Promise> { - const {context, value: values} = await this.getSignatureStatuses( - [signature], - config, - ); - assert(values.length === 1); - const value = values[0]; - return {context, value}; - } - - /** - * Fetch the current statuses of a batch of signatures - */ - async getSignatureStatuses( - signatures: Array, - config?: SignatureStatusConfig, - ): Promise>> { - const params: any[] = [signatures]; - if (config) { - params.push(config); - } - const unsafeRes = await this._rpcRequest('getSignatureStatuses', params); - const res = create(unsafeRes, GetSignatureStatusesRpcResult); - if ('error' in res) { - throw new SolanaJSONRPCError(res.error, 'failed to get signature status'); - } - return res.result; - } - - /** - * Fetch the current transaction count of the cluster - */ - async getTransactionCount( - commitmentOrConfig?: Commitment | GetTransactionCountConfig, - ): Promise { - const {commitment, config} = - extractCommitmentFromConfig(commitmentOrConfig); - const args = this._buildArgs( - [], - commitment, - undefined /* encoding */, - config, - ); - const unsafeRes = await this._rpcRequest('getTransactionCount', args); - const res = create(unsafeRes, jsonRpcResult(number())); - if ('error' in res) { - throw new SolanaJSONRPCError( - res.error, - 'failed to get transaction count', - ); - } - return res.result; - } - - /** - * Fetch the current total currency supply of the cluster in lamports - * - * @deprecated Deprecated since RPC v1.2.8. Please use {@link getSupply} instead. - */ - async getTotalSupply(commitment?: Commitment): Promise { - const result = await this.getSupply({ - commitment, - excludeNonCirculatingAccountsList: true, - }); - return result.value.total; - } - - /** - * Fetch the cluster InflationGovernor parameters - */ - async getInflationGovernor( - commitment?: Commitment, - ): Promise { - const args = this._buildArgs([], commitment); - const unsafeRes = await this._rpcRequest('getInflationGovernor', args); - const res = create(unsafeRes, GetInflationGovernorRpcResult); - if ('error' in res) { - throw new SolanaJSONRPCError(res.error, 'failed to get inflation'); - } - return res.result; - } - - /** - * Fetch the inflation reward for a list of addresses for an epoch - */ - async getInflationReward( - addresses: PublicKey[], - epoch?: number, - commitmentOrConfig?: Commitment | GetInflationRewardConfig, - ): Promise<(InflationReward | null)[]> { - const {commitment, config} = - extractCommitmentFromConfig(commitmentOrConfig); - const args = this._buildArgs( - [addresses.map(pubkey => pubkey.toBase58())], - commitment, - undefined /* encoding */, - { - ...config, - epoch: epoch != null ? epoch : config?.epoch, - }, - ); - const unsafeRes = await this._rpcRequest('getInflationReward', args); - const res = create(unsafeRes, GetInflationRewardResult); - if ('error' in res) { - throw new SolanaJSONRPCError(res.error, 'failed to get inflation reward'); - } - return res.result; - } - - /** - * Fetch the specific inflation values for the current epoch - */ - async getInflationRate(): Promise { - const unsafeRes = await this._rpcRequest('getInflationRate', []); - const res = create(unsafeRes, GetInflationRateRpcResult); - if ('error' in res) { - throw new SolanaJSONRPCError(res.error, 'failed to get inflation rate'); - } - return res.result; - } - - /** - * Fetch the Epoch Info parameters - */ - async getEpochInfo( - commitmentOrConfig?: Commitment | GetEpochInfoConfig, - ): Promise { - const {commitment, config} = - extractCommitmentFromConfig(commitmentOrConfig); - const args = this._buildArgs( - [], - commitment, - undefined /* encoding */, - config, - ); - const unsafeRes = await this._rpcRequest('getEpochInfo', args); - const res = create(unsafeRes, GetEpochInfoRpcResult); - if ('error' in res) { - throw new SolanaJSONRPCError(res.error, 'failed to get epoch info'); - } - return res.result; - } - - /** - * Fetch the Epoch Schedule parameters - */ - async getEpochSchedule(): Promise { - const unsafeRes = await this._rpcRequest('getEpochSchedule', []); - const res = create(unsafeRes, GetEpochScheduleRpcResult); - if ('error' in res) { - throw new SolanaJSONRPCError(res.error, 'failed to get epoch schedule'); - } - const epochSchedule = res.result; - return new EpochSchedule( - epochSchedule.slotsPerEpoch, - epochSchedule.leaderScheduleSlotOffset, - epochSchedule.warmup, - epochSchedule.firstNormalEpoch, - epochSchedule.firstNormalSlot, - ); - } - - /** - * Fetch the leader schedule for the current epoch - * @return {Promise>} - */ - async getLeaderSchedule(): Promise { - const unsafeRes = await this._rpcRequest('getLeaderSchedule', []); - const res = create(unsafeRes, GetLeaderScheduleRpcResult); - if ('error' in res) { - throw new SolanaJSONRPCError(res.error, 'failed to get leader schedule'); - } - return res.result; - } - - /** - * Fetch the minimum balance needed to exempt an account of `dataLength` - * size from rent - */ - async getMinimumBalanceForRentExemption( - dataLength: number, - commitment?: Commitment, - ): Promise { - const args = this._buildArgs([dataLength], commitment); - const unsafeRes = await this._rpcRequest( - 'getMinimumBalanceForRentExemption', - args, - ); - const res = create(unsafeRes, GetMinimumBalanceForRentExemptionRpcResult); - if ('error' in res) { - console.warn('Unable to fetch minimum balance for rent exemption'); - return 0; - } - return res.result; - } - - /** - * Fetch a recent blockhash from the cluster, return with context - * @return {Promise>} - * - * @deprecated Deprecated since RPC v1.9.0. Please use {@link getLatestBlockhash} instead. - */ - async getRecentBlockhashAndContext(commitment?: Commitment): Promise< - RpcResponseAndContext<{ - blockhash: Blockhash; - feeCalculator: FeeCalculator; - }> - > { - const args = this._buildArgs([], commitment); - const unsafeRes = await this._rpcRequest('getRecentBlockhash', args); - const res = create(unsafeRes, GetRecentBlockhashAndContextRpcResult); - if ('error' in res) { - throw new SolanaJSONRPCError(res.error, 'failed to get recent blockhash'); - } - return res.result; - } - - /** - * Fetch recent performance samples - * @return {Promise>} - */ - async getRecentPerformanceSamples( - limit?: number, - ): Promise> { - const unsafeRes = await this._rpcRequest( - 'getRecentPerformanceSamples', - limit ? [limit] : [], - ); - const res = create(unsafeRes, GetRecentPerformanceSamplesRpcResult); - if ('error' in res) { - throw new SolanaJSONRPCError( - res.error, - 'failed to get recent performance samples', - ); - } - - return res.result; - } - - /** - * Fetch the fee calculator for a recent blockhash from the cluster, return with context - * - * @deprecated Deprecated since RPC v1.9.0. Please use {@link getFeeForMessage} instead. - */ - async getFeeCalculatorForBlockhash( - blockhash: Blockhash, - commitment?: Commitment, - ): Promise> { - const args = this._buildArgs([blockhash], commitment); - const unsafeRes = await this._rpcRequest( - 'getFeeCalculatorForBlockhash', - args, - ); - - const res = create(unsafeRes, GetFeeCalculatorRpcResult); - if ('error' in res) { - throw new SolanaJSONRPCError(res.error, 'failed to get fee calculator'); - } - const {context, value} = res.result; - return { - context, - value: value !== null ? value.feeCalculator : null, - }; - } - - /** - * Fetch the fee for a message from the cluster, return with context - */ - async getFeeForMessage( - message: VersionedMessage, - commitment?: Commitment, - ): Promise> { - const wireMessage = toBuffer(message.serialize()).toString('base64'); - const args = this._buildArgs([wireMessage], commitment); - const unsafeRes = await this._rpcRequest('getFeeForMessage', args); - - const res = create(unsafeRes, jsonRpcResultAndContext(nullable(number()))); - if ('error' in res) { - throw new SolanaJSONRPCError(res.error, 'failed to get fee for message'); - } - if (res.result === null) { - throw new Error('invalid blockhash'); - } - return res.result; - } - - /** - * Fetch a list of prioritization fees from recent blocks. - */ - async getRecentPrioritizationFees( - config?: GetRecentPrioritizationFeesConfig, - ): Promise { - const accounts = config?.lockedWritableAccounts?.map(key => key.toBase58()); - const args = accounts?.length ? [accounts] : []; - const unsafeRes = await this._rpcRequest( - 'getRecentPrioritizationFees', - args, - ); - const res = create(unsafeRes, GetRecentPrioritizationFeesRpcResult); - if ('error' in res) { - throw new SolanaJSONRPCError( - res.error, - 'failed to get recent prioritization fees', - ); - } - return res.result; - } - /** - * Fetch a recent blockhash from the cluster - * @return {Promise<{blockhash: Blockhash, feeCalculator: FeeCalculator}>} - * - * @deprecated Deprecated since RPC v1.8.0. Please use {@link getLatestBlockhash} instead. - */ - async getRecentBlockhash( - commitment?: Commitment, - ): Promise<{blockhash: Blockhash; feeCalculator: FeeCalculator}> { - try { - const res = await this.getRecentBlockhashAndContext(commitment); - return res.value; - } catch (e) { - throw new Error('failed to get recent blockhash: ' + e); - } - } - - /** - * Fetch the latest blockhash from the cluster - * @return {Promise} - */ - async getLatestBlockhash( - commitmentOrConfig?: Commitment | GetLatestBlockhashConfig, - ): Promise { - try { - const res = await this.getLatestBlockhashAndContext(commitmentOrConfig); - return res.value; - } catch (e) { - throw new Error('failed to get recent blockhash: ' + e); - } - } - - /** - * Fetch the latest blockhash from the cluster - * @return {Promise} - */ - async getLatestBlockhashAndContext( - commitmentOrConfig?: Commitment | GetLatestBlockhashConfig, - ): Promise> { - const {commitment, config} = - extractCommitmentFromConfig(commitmentOrConfig); - const args = this._buildArgs( - [], - commitment, - undefined /* encoding */, - config, - ); - const unsafeRes = await this._rpcRequest('getLatestBlockhash', args); - const res = create(unsafeRes, GetLatestBlockhashRpcResult); - if ('error' in res) { - throw new SolanaJSONRPCError(res.error, 'failed to get latest blockhash'); - } - return res.result; - } - - /** - * Returns whether a blockhash is still valid or not - */ - async isBlockhashValid( - blockhash: Blockhash, - rawConfig?: IsBlockhashValidConfig, - ): Promise> { - const {commitment, config} = extractCommitmentFromConfig(rawConfig); - const args = this._buildArgs( - [blockhash], - commitment, - undefined /* encoding */, - config, - ); - const unsafeRes = await this._rpcRequest('isBlockhashValid', args); - const res = create(unsafeRes, IsBlockhashValidRpcResult); - if ('error' in res) { - throw new SolanaJSONRPCError( - res.error, - 'failed to determine if the blockhash `' + blockhash + '`is valid', - ); - } - return res.result; - } - - /** - * Fetch the node version - */ - async getVersion(): Promise { - const unsafeRes = await this._rpcRequest('getVersion', []); - const res = create(unsafeRes, jsonRpcResult(VersionResult)); - if ('error' in res) { - throw new SolanaJSONRPCError(res.error, 'failed to get version'); - } - return res.result; - } - - /** - * Fetch the genesis hash - */ - async getGenesisHash(): Promise { - const unsafeRes = await this._rpcRequest('getGenesisHash', []); - const res = create(unsafeRes, jsonRpcResult(string())); - if ('error' in res) { - throw new SolanaJSONRPCError(res.error, 'failed to get genesis hash'); - } - return res.result; - } - - /** - * Fetch a processed block from the cluster. - * - * @deprecated Instead, call `getBlock` using a `GetVersionedBlockConfig` by - * setting the `maxSupportedTransactionVersion` property. - */ - async getBlock( - slot: number, - rawConfig?: GetBlockConfig, - ): Promise; - - /** - * @deprecated Instead, call `getBlock` using a `GetVersionedBlockConfig` by - * setting the `maxSupportedTransactionVersion` property. - */ - // eslint-disable-next-line no-dupe-class-members - async getBlock( - slot: number, - rawConfig: GetBlockConfig & {transactionDetails: 'accounts'}, - ): Promise; - - /** - * @deprecated Instead, call `getBlock` using a `GetVersionedBlockConfig` by - * setting the `maxSupportedTransactionVersion` property. - */ - // eslint-disable-next-line no-dupe-class-members - async getBlock( - slot: number, - rawConfig: GetBlockConfig & {transactionDetails: 'none'}, - ): Promise; - - /** - * Fetch a processed block from the cluster. - */ - // eslint-disable-next-line no-dupe-class-members - async getBlock( - slot: number, - rawConfig?: GetVersionedBlockConfig, - ): Promise; - - // eslint-disable-next-line no-dupe-class-members - async getBlock( - slot: number, - rawConfig: GetVersionedBlockConfig & {transactionDetails: 'accounts'}, - ): Promise; - - // eslint-disable-next-line no-dupe-class-members - async getBlock( - slot: number, - rawConfig: GetVersionedBlockConfig & {transactionDetails: 'none'}, - ): Promise; - - /** - * Fetch a processed block from the cluster. - */ - // eslint-disable-next-line no-dupe-class-members - async getBlock( - slot: number, - rawConfig?: GetVersionedBlockConfig, - ): Promise< - | VersionedBlockResponse - | VersionedAccountsModeBlockResponse - | VersionedNoneModeBlockResponse - | null - > { - const {commitment, config} = extractCommitmentFromConfig(rawConfig); - const args = this._buildArgsAtLeastConfirmed( - [slot], - commitment as Finality, - undefined /* encoding */, - config, - ); - const unsafeRes = await this._rpcRequest('getBlock', args); - try { - switch (config?.transactionDetails) { - case 'accounts': { - const res = create(unsafeRes, GetAccountsModeBlockRpcResult); - if ('error' in res) { - throw res.error; - } - return res.result; - } - case 'none': { - const res = create(unsafeRes, GetNoneModeBlockRpcResult); - if ('error' in res) { - throw res.error; - } - return res.result; - } - default: { - const res = create(unsafeRes, GetBlockRpcResult); - if ('error' in res) { - throw res.error; - } - const {result} = res; - return result - ? { - ...result, - transactions: result.transactions.map( - ({transaction, meta, version}) => ({ - meta, - transaction: { - ...transaction, - message: versionedMessageFromResponse( - version, - transaction.message, - ), - }, - version, - }), - ), - } - : null; - } - } - } catch (e) { - throw new SolanaJSONRPCError( - e as JSONRPCError, - 'failed to get confirmed block', - ); - } - } - - /** - * Fetch parsed transaction details for a confirmed or finalized block - */ - async getParsedBlock( - slot: number, - rawConfig?: GetVersionedBlockConfig, - ): Promise; - - // eslint-disable-next-line no-dupe-class-members - async getParsedBlock( - slot: number, - rawConfig: GetVersionedBlockConfig & {transactionDetails: 'accounts'}, - ): Promise; - - // eslint-disable-next-line no-dupe-class-members - async getParsedBlock( - slot: number, - rawConfig: GetVersionedBlockConfig & {transactionDetails: 'none'}, - ): Promise; - // eslint-disable-next-line no-dupe-class-members - async getParsedBlock( - slot: number, - rawConfig?: GetVersionedBlockConfig, - ): Promise< - | ParsedBlockResponse - | ParsedAccountsModeBlockResponse - | ParsedNoneModeBlockResponse - | null - > { - const {commitment, config} = extractCommitmentFromConfig(rawConfig); - const args = this._buildArgsAtLeastConfirmed( - [slot], - commitment as Finality, - 'jsonParsed', - config, - ); - const unsafeRes = await this._rpcRequest('getBlock', args); - try { - switch (config?.transactionDetails) { - case 'accounts': { - const res = create(unsafeRes, GetParsedAccountsModeBlockRpcResult); - if ('error' in res) { - throw res.error; - } - return res.result; - } - case 'none': { - const res = create(unsafeRes, GetParsedNoneModeBlockRpcResult); - if ('error' in res) { - throw res.error; - } - return res.result; - } - default: { - const res = create(unsafeRes, GetParsedBlockRpcResult); - if ('error' in res) { - throw res.error; - } - return res.result; - } - } - } catch (e) { - throw new SolanaJSONRPCError(e as JSONRPCError, 'failed to get block'); - } - } - - /* - * Returns the current block height of the node - */ - getBlockHeight = (() => { - const requestPromises: {[hash: string]: Promise} = {}; - return async ( - commitmentOrConfig?: Commitment | GetBlockHeightConfig, - ): Promise => { - const {commitment, config} = - extractCommitmentFromConfig(commitmentOrConfig); - const args = this._buildArgs( - [], - commitment, - undefined /* encoding */, - config, - ); - const requestHash = fastStableStringify(args); - requestPromises[requestHash] = - requestPromises[requestHash] ?? - (async () => { - try { - const unsafeRes = await this._rpcRequest('getBlockHeight', args); - const res = create(unsafeRes, jsonRpcResult(number())); - if ('error' in res) { - throw new SolanaJSONRPCError( - res.error, - 'failed to get block height information', - ); - } - return res.result; - } finally { - delete requestPromises[requestHash]; - } - })(); - return await requestPromises[requestHash]; - }; - })(); - - /* - * Returns recent block production information from the current or previous epoch - */ - async getBlockProduction( - configOrCommitment?: GetBlockProductionConfig | Commitment, - ): Promise> { - let extra: Omit | undefined; - let commitment: Commitment | undefined; - - if (typeof configOrCommitment === 'string') { - commitment = configOrCommitment; - } else if (configOrCommitment) { - const {commitment: c, ...rest} = configOrCommitment; - commitment = c; - extra = rest; - } - - const args = this._buildArgs([], commitment, 'base64', extra); - const unsafeRes = await this._rpcRequest('getBlockProduction', args); - const res = create(unsafeRes, BlockProductionResponseStruct); - if ('error' in res) { - throw new SolanaJSONRPCError( - res.error, - 'failed to get block production information', - ); - } - - return res.result; - } - - /** - * Fetch a confirmed or finalized transaction from the cluster. - * - * @deprecated Instead, call `getTransaction` using a - * `GetVersionedTransactionConfig` by setting the - * `maxSupportedTransactionVersion` property. - */ - async getTransaction( - signature: string, - rawConfig?: GetTransactionConfig, - ): Promise; - - /** - * Fetch a confirmed or finalized transaction from the cluster. - */ - // eslint-disable-next-line no-dupe-class-members - async getTransaction( - signature: string, - rawConfig: GetVersionedTransactionConfig, - ): Promise; - - /** - * Fetch a confirmed or finalized transaction from the cluster. - */ - // eslint-disable-next-line no-dupe-class-members - async getTransaction( - signature: string, - rawConfig?: GetVersionedTransactionConfig, - ): Promise { - const {commitment, config} = extractCommitmentFromConfig(rawConfig); - const args = this._buildArgsAtLeastConfirmed( - [signature], - commitment as Finality, - undefined /* encoding */, - config, - ); - const unsafeRes = await this._rpcRequest('getTransaction', args); - const res = create(unsafeRes, GetTransactionRpcResult); - if ('error' in res) { - throw new SolanaJSONRPCError(res.error, 'failed to get transaction'); - } - - const result = res.result; - if (!result) return result; - - return { - ...result, - transaction: { - ...result.transaction, - message: versionedMessageFromResponse( - result.version, - result.transaction.message, - ), - }, - }; - } - - /** - * Fetch parsed transaction details for a confirmed or finalized transaction - */ - async getParsedTransaction( - signature: TransactionSignature, - commitmentOrConfig?: GetVersionedTransactionConfig | Finality, - ): Promise { - const {commitment, config} = - extractCommitmentFromConfig(commitmentOrConfig); - const args = this._buildArgsAtLeastConfirmed( - [signature], - commitment as Finality, - 'jsonParsed', - config, - ); - const unsafeRes = await this._rpcRequest('getTransaction', args); - const res = create(unsafeRes, GetParsedTransactionRpcResult); - if ('error' in res) { - throw new SolanaJSONRPCError(res.error, 'failed to get transaction'); - } - return res.result; - } - - /** - * Fetch parsed transaction details for a batch of confirmed transactions - */ - async getParsedTransactions( - signatures: TransactionSignature[], - commitmentOrConfig?: GetVersionedTransactionConfig | Finality, - ): Promise<(ParsedTransactionWithMeta | null)[]> { - const {commitment, config} = - extractCommitmentFromConfig(commitmentOrConfig); - const batch = signatures.map(signature => { - const args = this._buildArgsAtLeastConfirmed( - [signature], - commitment as Finality, - 'jsonParsed', - config, - ); - return { - methodName: 'getTransaction', - args, - }; - }); - - const unsafeRes = await this._rpcBatchRequest(batch); - const res = unsafeRes.map((unsafeRes: any) => { - const res = create(unsafeRes, GetParsedTransactionRpcResult); - if ('error' in res) { - throw new SolanaJSONRPCError(res.error, 'failed to get transactions'); - } - return res.result; - }); - - return res; - } - - /** - * Fetch transaction details for a batch of confirmed transactions. - * Similar to {@link getParsedTransactions} but returns a {@link TransactionResponse}. - * - * @deprecated Instead, call `getTransactions` using a - * `GetVersionedTransactionConfig` by setting the - * `maxSupportedTransactionVersion` property. - */ - async getTransactions( - signatures: TransactionSignature[], - commitmentOrConfig?: GetTransactionConfig | Finality, - ): Promise<(TransactionResponse | null)[]>; - - /** - * Fetch transaction details for a batch of confirmed transactions. - * Similar to {@link getParsedTransactions} but returns a {@link - * VersionedTransactionResponse}. - */ - // eslint-disable-next-line no-dupe-class-members - async getTransactions( - signatures: TransactionSignature[], - commitmentOrConfig: GetVersionedTransactionConfig | Finality, - ): Promise<(VersionedTransactionResponse | null)[]>; - - /** - * Fetch transaction details for a batch of confirmed transactions. - * Similar to {@link getParsedTransactions} but returns a {@link - * VersionedTransactionResponse}. - */ - // eslint-disable-next-line no-dupe-class-members - async getTransactions( - signatures: TransactionSignature[], - commitmentOrConfig: GetVersionedTransactionConfig | Finality, - ): Promise<(VersionedTransactionResponse | null)[]> { - const {commitment, config} = - extractCommitmentFromConfig(commitmentOrConfig); - const batch = signatures.map(signature => { - const args = this._buildArgsAtLeastConfirmed( - [signature], - commitment as Finality, - undefined /* encoding */, - config, - ); - return { - methodName: 'getTransaction', - args, - }; - }); - - const unsafeRes = await this._rpcBatchRequest(batch); - const res = unsafeRes.map((unsafeRes: any) => { - const res = create(unsafeRes, GetTransactionRpcResult); - if ('error' in res) { - throw new SolanaJSONRPCError(res.error, 'failed to get transactions'); - } - const result = res.result; - if (!result) return result; - - return { - ...result, - transaction: { - ...result.transaction, - message: versionedMessageFromResponse( - result.version, - result.transaction.message, - ), - }, - }; - }); - - return res; - } - - /** - * Fetch a list of Transactions and transaction statuses from the cluster - * for a confirmed block. - * - * @deprecated Deprecated since RPC v1.7.0. Please use {@link getBlock} instead. - */ - async getConfirmedBlock( - slot: number, - commitment?: Finality, - ): Promise { - const args = this._buildArgsAtLeastConfirmed([slot], commitment); - const unsafeRes = await this._rpcRequest('getConfirmedBlock', args); - const res = create(unsafeRes, GetConfirmedBlockRpcResult); - - if ('error' in res) { - throw new SolanaJSONRPCError(res.error, 'failed to get confirmed block'); - } - - const result = res.result; - if (!result) { - throw new Error('Confirmed block ' + slot + ' not found'); - } - - const block = { - ...result, - transactions: result.transactions.map(({transaction, meta}) => { - const message = new Message(transaction.message); - return { - meta, - transaction: { - ...transaction, - message, - }, - }; - }), - }; - - return { - ...block, - transactions: block.transactions.map(({transaction, meta}) => { - return { - meta, - transaction: Transaction.populate( - transaction.message, - transaction.signatures, - ), - }; - }), - }; - } - - /** - * Fetch confirmed blocks between two slots - */ - async getBlocks( - startSlot: number, - endSlot?: number, - commitment?: Finality, - ): Promise> { - const args = this._buildArgsAtLeastConfirmed( - endSlot !== undefined ? [startSlot, endSlot] : [startSlot], - commitment, - ); - const unsafeRes = await this._rpcRequest('getBlocks', args); - const res = create(unsafeRes, jsonRpcResult(array(number()))); - if ('error' in res) { - throw new SolanaJSONRPCError(res.error, 'failed to get blocks'); - } - return res.result; - } - - /** - * Fetch a list of Signatures from the cluster for a block, excluding rewards - */ - async getBlockSignatures( - slot: number, - commitment?: Finality, - ): Promise { - const args = this._buildArgsAtLeastConfirmed( - [slot], - commitment, - undefined, - { - transactionDetails: 'signatures', - rewards: false, - }, - ); - const unsafeRes = await this._rpcRequest('getBlock', args); - const res = create(unsafeRes, GetBlockSignaturesRpcResult); - if ('error' in res) { - throw new SolanaJSONRPCError(res.error, 'failed to get block'); - } - const result = res.result; - if (!result) { - throw new Error('Block ' + slot + ' not found'); - } - return result; - } - - /** - * Fetch a list of Signatures from the cluster for a confirmed block, excluding rewards - * - * @deprecated Deprecated since RPC v1.7.0. Please use {@link getBlockSignatures} instead. - */ - async getConfirmedBlockSignatures( - slot: number, - commitment?: Finality, - ): Promise { - const args = this._buildArgsAtLeastConfirmed( - [slot], - commitment, - undefined, - { - transactionDetails: 'signatures', - rewards: false, - }, - ); - const unsafeRes = await this._rpcRequest('getConfirmedBlock', args); - const res = create(unsafeRes, GetBlockSignaturesRpcResult); - if ('error' in res) { - throw new SolanaJSONRPCError(res.error, 'failed to get confirmed block'); - } - const result = res.result; - if (!result) { - throw new Error('Confirmed block ' + slot + ' not found'); - } - return result; - } - - /** - * Fetch a transaction details for a confirmed transaction - * - * @deprecated Deprecated since RPC v1.7.0. Please use {@link getTransaction} instead. - */ - async getConfirmedTransaction( - signature: TransactionSignature, - commitment?: Finality, - ): Promise { - const args = this._buildArgsAtLeastConfirmed([signature], commitment); - const unsafeRes = await this._rpcRequest('getConfirmedTransaction', args); - const res = create(unsafeRes, GetTransactionRpcResult); - if ('error' in res) { - throw new SolanaJSONRPCError(res.error, 'failed to get transaction'); - } - - const result = res.result; - if (!result) return result; - - const message = new Message(result.transaction.message); - const signatures = result.transaction.signatures; - return { - ...result, - transaction: Transaction.populate(message, signatures), - }; - } - - /** - * Fetch parsed transaction details for a confirmed transaction - * - * @deprecated Deprecated since RPC v1.7.0. Please use {@link getParsedTransaction} instead. - */ - async getParsedConfirmedTransaction( - signature: TransactionSignature, - commitment?: Finality, - ): Promise { - const args = this._buildArgsAtLeastConfirmed( - [signature], - commitment, - 'jsonParsed', - ); - const unsafeRes = await this._rpcRequest('getConfirmedTransaction', args); - const res = create(unsafeRes, GetParsedTransactionRpcResult); - if ('error' in res) { - throw new SolanaJSONRPCError( - res.error, - 'failed to get confirmed transaction', - ); - } - return res.result; - } - - /** - * Fetch parsed transaction details for a batch of confirmed transactions - * - * @deprecated Deprecated since RPC v1.7.0. Please use {@link getParsedTransactions} instead. - */ - async getParsedConfirmedTransactions( - signatures: TransactionSignature[], - commitment?: Finality, - ): Promise<(ParsedConfirmedTransaction | null)[]> { - const batch = signatures.map(signature => { - const args = this._buildArgsAtLeastConfirmed( - [signature], - commitment, - 'jsonParsed', - ); - return { - methodName: 'getConfirmedTransaction', - args, - }; - }); - - const unsafeRes = await this._rpcBatchRequest(batch); - const res = unsafeRes.map((unsafeRes: any) => { - const res = create(unsafeRes, GetParsedTransactionRpcResult); - if ('error' in res) { - throw new SolanaJSONRPCError( - res.error, - 'failed to get confirmed transactions', - ); - } - return res.result; - }); - - return res; - } - - /** - * Fetch a list of all the confirmed signatures for transactions involving an address - * within a specified slot range. Max range allowed is 10,000 slots. - * - * @deprecated Deprecated since RPC v1.3. Please use {@link getConfirmedSignaturesForAddress2} instead. - * - * @param address queried address - * @param startSlot start slot, inclusive - * @param endSlot end slot, inclusive - */ - async getConfirmedSignaturesForAddress( - address: PublicKey, - startSlot: number, - endSlot: number, - ): Promise> { - let options: any = {}; - - let firstAvailableBlock = await this.getFirstAvailableBlock(); - while (!('until' in options)) { - startSlot--; - if (startSlot <= 0 || startSlot < firstAvailableBlock) { - break; - } - - try { - const block = await this.getConfirmedBlockSignatures( - startSlot, - 'finalized', - ); - if (block.signatures.length > 0) { - options.until = - block.signatures[block.signatures.length - 1].toString(); - } - } catch (err) { - if (err instanceof Error && err.message.includes('skipped')) { - continue; - } else { - throw err; - } - } - } - - let highestConfirmedRoot = await this.getSlot('finalized'); - while (!('before' in options)) { - endSlot++; - if (endSlot > highestConfirmedRoot) { - break; - } - - try { - const block = await this.getConfirmedBlockSignatures(endSlot); - if (block.signatures.length > 0) { - options.before = - block.signatures[block.signatures.length - 1].toString(); - } - } catch (err) { - if (err instanceof Error && err.message.includes('skipped')) { - continue; - } else { - throw err; - } - } - } - - const confirmedSignatureInfo = await this.getConfirmedSignaturesForAddress2( - address, - options, - ); - return confirmedSignatureInfo.map(info => info.signature); - } - - /** - * Returns confirmed signatures for transactions involving an - * address backwards in time from the provided signature or most recent confirmed block - * - * @deprecated Deprecated since RPC v1.7.0. Please use {@link getSignaturesForAddress} instead. - */ - async getConfirmedSignaturesForAddress2( - address: PublicKey, - options?: ConfirmedSignaturesForAddress2Options, - commitment?: Finality, - ): Promise> { - const args = this._buildArgsAtLeastConfirmed( - [address.toBase58()], - commitment, - undefined, - options, - ); - const unsafeRes = await this._rpcRequest( - 'getConfirmedSignaturesForAddress2', - args, - ); - const res = create(unsafeRes, GetConfirmedSignaturesForAddress2RpcResult); - if ('error' in res) { - throw new SolanaJSONRPCError( - res.error, - 'failed to get confirmed signatures for address', - ); - } - return res.result; - } - - /** - * Returns confirmed signatures for transactions involving an - * address backwards in time from the provided signature or most recent confirmed block - * - * - * @param address queried address - * @param options - */ - async getSignaturesForAddress( - address: PublicKey, - options?: SignaturesForAddressOptions, - commitment?: Finality, - ): Promise> { - const args = this._buildArgsAtLeastConfirmed( - [address.toBase58()], - commitment, - undefined, - options, - ); - const unsafeRes = await this._rpcRequest('getSignaturesForAddress', args); - const res = create(unsafeRes, GetSignaturesForAddressRpcResult); - if ('error' in res) { - throw new SolanaJSONRPCError( - res.error, - 'failed to get signatures for address', - ); - } - return res.result; - } - - async getAddressLookupTable( - accountKey: PublicKey, - config?: GetAccountInfoConfig, - ): Promise> { - const {context, value: accountInfo} = await this.getAccountInfoAndContext( - accountKey, - config, - ); - - let value = null; - if (accountInfo !== null) { - value = new AddressLookupTableAccount({ - key: accountKey, - state: AddressLookupTableAccount.deserialize(accountInfo.data), - }); - } - - return { - context, - value, - }; - } - - /** - * Fetch the contents of a Nonce account from the cluster, return with context - */ - async getNonceAndContext( - nonceAccount: PublicKey, - commitmentOrConfig?: Commitment | GetNonceAndContextConfig, - ): Promise> { - const {context, value: accountInfo} = await this.getAccountInfoAndContext( - nonceAccount, - commitmentOrConfig, - ); - - let value = null; - if (accountInfo !== null) { - value = NonceAccount.fromAccountData(accountInfo.data); - } - - return { - context, - value, - }; - } - - /** - * Fetch the contents of a Nonce account from the cluster - */ - async getNonce( - nonceAccount: PublicKey, - commitmentOrConfig?: Commitment | GetNonceConfig, - ): Promise { - return await this.getNonceAndContext(nonceAccount, commitmentOrConfig) - .then(x => x.value) - .catch(e => { - throw new Error( - 'failed to get nonce for account ' + - nonceAccount.toBase58() + - ': ' + - e, - ); - }); - } - - /** - * Request an allocation of lamports to the specified address - * - * ```typescript - * import { Connection, PublicKey, LAMPORTS_PER_SOL } from "@solana/web3.js"; - * - * (async () => { - * const connection = new Connection("https://api.testnet.solana.com", "confirmed"); - * const myAddress = new PublicKey("2nr1bHFT86W9tGnyvmYW4vcHKsQB3sVQfnddasz4kExM"); - * const signature = await connection.requestAirdrop(myAddress, LAMPORTS_PER_SOL); - * await connection.confirmTransaction(signature); - * })(); - * ``` - */ - async requestAirdrop( - to: PublicKey, - lamports: number, - ): Promise { - const unsafeRes = await this._rpcRequest('requestAirdrop', [ - to.toBase58(), - lamports, - ]); - const res = create(unsafeRes, RequestAirdropRpcResult); - if ('error' in res) { - throw new SolanaJSONRPCError( - res.error, - `airdrop to ${to.toBase58()} failed`, - ); - } - return res.result; - } - - /** - * @internal - */ - async _blockhashWithExpiryBlockHeight( - disableCache: boolean, - ): Promise { - if (!disableCache) { - // Wait for polling to finish - while (this._pollingBlockhash) { - await sleep(100); - } - const timeSinceFetch = Date.now() - this._blockhashInfo.lastFetch; - const expired = timeSinceFetch >= BLOCKHASH_CACHE_TIMEOUT_MS; - if (this._blockhashInfo.latestBlockhash !== null && !expired) { - return this._blockhashInfo.latestBlockhash; - } - } - - return await this._pollNewBlockhash(); - } - - /** - * @internal - */ - async _pollNewBlockhash(): Promise { - this._pollingBlockhash = true; - try { - const startTime = Date.now(); - const cachedLatestBlockhash = this._blockhashInfo.latestBlockhash; - const cachedBlockhash = cachedLatestBlockhash - ? cachedLatestBlockhash.blockhash - : null; - for (let i = 0; i < 50; i++) { - const latestBlockhash = await this.getLatestBlockhash('finalized'); - - if (cachedBlockhash !== latestBlockhash.blockhash) { - this._blockhashInfo = { - latestBlockhash, - lastFetch: Date.now(), - transactionSignatures: [], - simulatedSignatures: [], - }; - return latestBlockhash; - } - - // Sleep for approximately half a slot - await sleep(MS_PER_SLOT / 2); - } - - throw new Error( - `Unable to obtain a new blockhash after ${Date.now() - startTime}ms`, - ); - } finally { - this._pollingBlockhash = false; - } - } - - /** - * get the stake minimum delegation - */ - async getStakeMinimumDelegation( - config?: GetStakeMinimumDelegationConfig, - ): Promise> { - const {commitment, config: configArg} = extractCommitmentFromConfig(config); - const args = this._buildArgs([], commitment, 'base64', configArg); - const unsafeRes = await this._rpcRequest('getStakeMinimumDelegation', args); - const res = create(unsafeRes, jsonRpcResultAndContext(number())); - if ('error' in res) { - throw new SolanaJSONRPCError( - res.error, - `failed to get stake minimum delegation`, - ); - } - return res.result; - } - - /** - * Simulate a transaction - * - * @deprecated Instead, call {@link simulateTransaction} with {@link - * VersionedTransaction} and {@link SimulateTransactionConfig} parameters - */ - simulateTransaction( - transactionOrMessage: Transaction | Message, - signers?: Array, - includeAccounts?: boolean | Array, - ): Promise>; - - /** - * Simulate a transaction - */ - // eslint-disable-next-line no-dupe-class-members - simulateTransaction( - transaction: VersionedTransaction, - config?: SimulateTransactionConfig, - ): Promise>; - - /** - * Simulate a transaction - */ - // eslint-disable-next-line no-dupe-class-members - async simulateTransaction( - transactionOrMessage: VersionedTransaction | Transaction | Message, - configOrSigners?: SimulateTransactionConfig | Array, - includeAccounts?: boolean | Array, - ): Promise> { - if ('message' in transactionOrMessage) { - const versionedTx = transactionOrMessage; - const wireTransaction = versionedTx.serialize(); - const encodedTransaction = - Buffer.from(wireTransaction).toString('base64'); - if (Array.isArray(configOrSigners) || includeAccounts !== undefined) { - throw new Error('Invalid arguments'); - } - - const config: any = configOrSigners || {}; - config.encoding = 'base64'; - if (!('commitment' in config)) { - config.commitment = this.commitment; - } - - if ( - configOrSigners && - typeof configOrSigners === 'object' && - 'innerInstructions' in configOrSigners - ) { - config.innerInstructions = configOrSigners.innerInstructions; - } - - const args = [encodedTransaction, config]; - const unsafeRes = await this._rpcRequest('simulateTransaction', args); - const res = create(unsafeRes, SimulatedTransactionResponseStruct); - if ('error' in res) { - throw new Error('failed to simulate transaction: ' + res.error.message); - } - return res.result; - } - - let transaction; - if (transactionOrMessage instanceof Transaction) { - let originalTx: Transaction = transactionOrMessage; - transaction = new Transaction(); - transaction.feePayer = originalTx.feePayer; - transaction.instructions = transactionOrMessage.instructions; - transaction.nonceInfo = originalTx.nonceInfo; - transaction.signatures = originalTx.signatures; - } else { - transaction = Transaction.populate(transactionOrMessage); - // HACK: this function relies on mutating the populated transaction - transaction._message = transaction._json = undefined; - } - - if (configOrSigners !== undefined && !Array.isArray(configOrSigners)) { - throw new Error('Invalid arguments'); - } - - const signers = configOrSigners; - if (transaction.nonceInfo && signers) { - transaction.sign(...signers); - } else { - let disableCache = this._disableBlockhashCaching; - for (;;) { - const latestBlockhash = - await this._blockhashWithExpiryBlockHeight(disableCache); - transaction.lastValidBlockHeight = latestBlockhash.lastValidBlockHeight; - transaction.recentBlockhash = latestBlockhash.blockhash; - - if (!signers) break; - - transaction.sign(...signers); - if (!transaction.signature) { - throw new Error('!signature'); // should never happen - } - - const signature = transaction.signature.toString('base64'); - if ( - !this._blockhashInfo.simulatedSignatures.includes(signature) && - !this._blockhashInfo.transactionSignatures.includes(signature) - ) { - // The signature of this transaction has not been seen before with the - // current recentBlockhash, all done. Let's break - this._blockhashInfo.simulatedSignatures.push(signature); - break; - } else { - // This transaction would be treated as duplicate (its derived signature - // matched to one of already recorded signatures). - // So, we must fetch a new blockhash for a different signature by disabling - // our cache not to wait for the cache expiration (BLOCKHASH_CACHE_TIMEOUT_MS). - disableCache = true; - } - } - } - - const message = transaction._compile(); - const signData = message.serialize(); - const wireTransaction = transaction._serialize(signData); - const encodedTransaction = wireTransaction.toString('base64'); - const config: any = { - encoding: 'base64', - commitment: this.commitment, - }; - - if (includeAccounts) { - const addresses = ( - Array.isArray(includeAccounts) - ? includeAccounts - : message.nonProgramIds() - ).map(key => key.toBase58()); - - config['accounts'] = { - encoding: 'base64', - addresses, - }; - } - - if (signers) { - config.sigVerify = true; - } - - if ( - configOrSigners && - typeof configOrSigners === 'object' && - 'innerInstructions' in configOrSigners - ) { - config.innerInstructions = configOrSigners.innerInstructions; - } - - const args = [encodedTransaction, config]; - const unsafeRes = await this._rpcRequest('simulateTransaction', args); - const res = create(unsafeRes, SimulatedTransactionResponseStruct); - if ('error' in res) { - let logs; - if ('data' in res.error) { - logs = res.error.data.logs; - if (logs && Array.isArray(logs)) { - const traceIndent = '\n '; - const logTrace = traceIndent + logs.join(traceIndent); - console.error(res.error.message, logTrace); - } - } - - throw new SendTransactionError({ - action: 'simulate', - signature: '', - transactionMessage: res.error.message, - logs: logs, - }); - } - return res.result; - } - - /** - * Sign and send a transaction - * - * @deprecated Instead, call {@link sendTransaction} with a {@link - * VersionedTransaction} - */ - sendTransaction( - transaction: Transaction, - signers: Array, - options?: SendOptions, - ): Promise; - - /** - * Send a signed transaction - */ - // eslint-disable-next-line no-dupe-class-members - sendTransaction( - transaction: VersionedTransaction, - options?: SendOptions, - ): Promise; - - /** - * Sign and send a transaction - */ - // eslint-disable-next-line no-dupe-class-members - async sendTransaction( - transaction: VersionedTransaction | Transaction, - signersOrOptions?: Array | SendOptions, - options?: SendOptions, - ): Promise { - if ('version' in transaction) { - if (signersOrOptions && Array.isArray(signersOrOptions)) { - throw new Error('Invalid arguments'); - } - - const wireTransaction = transaction.serialize(); - return await this.sendRawTransaction(wireTransaction, signersOrOptions); - } - - if (signersOrOptions === undefined || !Array.isArray(signersOrOptions)) { - throw new Error('Invalid arguments'); - } - - const signers = signersOrOptions; - if (transaction.nonceInfo) { - transaction.sign(...signers); - } else { - let disableCache = this._disableBlockhashCaching; - for (;;) { - const latestBlockhash = - await this._blockhashWithExpiryBlockHeight(disableCache); - transaction.lastValidBlockHeight = latestBlockhash.lastValidBlockHeight; - transaction.recentBlockhash = latestBlockhash.blockhash; - transaction.sign(...signers); - if (!transaction.signature) { - throw new Error('!signature'); // should never happen - } - - const signature = transaction.signature.toString('base64'); - if (!this._blockhashInfo.transactionSignatures.includes(signature)) { - // The signature of this transaction has not been seen before with the - // current recentBlockhash, all done. Let's break - this._blockhashInfo.transactionSignatures.push(signature); - break; - } else { - // This transaction would be treated as duplicate (its derived signature - // matched to one of already recorded signatures). - // So, we must fetch a new blockhash for a different signature by disabling - // our cache not to wait for the cache expiration (BLOCKHASH_CACHE_TIMEOUT_MS). - disableCache = true; - } - } - } - - const wireTransaction = transaction.serialize(); - return await this.sendRawTransaction(wireTransaction, options); - } - - /** - * Send a transaction that has already been signed and serialized into the - * wire format - */ - async sendRawTransaction( - rawTransaction: Buffer | Uint8Array | Array, - options?: SendOptions, - ): Promise { - const encodedTransaction = toBuffer(rawTransaction).toString('base64'); - const result = await this.sendEncodedTransaction( - encodedTransaction, - options, - ); - return result; - } - - /** - * Send a transaction that has already been signed, serialized into the - * wire format, and encoded as a base64 string - */ - async sendEncodedTransaction( - encodedTransaction: string, - options?: SendOptions, - ): Promise { - const config: any = {encoding: 'base64'}; - const skipPreflight = options && options.skipPreflight; - const preflightCommitment = - skipPreflight === true - ? 'processed' // FIXME Remove when https://github.com/anza-xyz/agave/pull/483 is deployed. - : (options && options.preflightCommitment) || this.commitment; - - if (options && options.maxRetries != null) { - config.maxRetries = options.maxRetries; - } - if (options && options.minContextSlot != null) { - config.minContextSlot = options.minContextSlot; - } - if (skipPreflight) { - config.skipPreflight = skipPreflight; - } - if (preflightCommitment) { - config.preflightCommitment = preflightCommitment; - } - - const args = [encodedTransaction, config]; - const unsafeRes = await this._rpcRequest('sendTransaction', args); - const res = create(unsafeRes, SendTransactionRpcResult); - if ('error' in res) { - let logs = undefined; - if ('data' in res.error) { - logs = res.error.data.logs; - } - - throw new SendTransactionError({ - action: skipPreflight ? 'send' : 'simulate', - signature: '', - transactionMessage: res.error.message, - logs: logs, - }); - } - return res.result; - } - - /** - * @internal - */ - _wsOnOpen() { - this._rpcWebSocketConnected = true; - this._rpcWebSocketHeartbeat = setInterval(() => { - // Ping server every 5s to prevent idle timeouts - (async () => { - try { - await this._rpcWebSocket.notify('ping'); - // eslint-disable-next-line no-empty - } catch {} - })(); - }, 5000); - this._updateSubscriptions(); - } - - /** - * @internal - */ - _wsOnError(err: Error) { - this._rpcWebSocketConnected = false; - console.error('ws error:', err.message); - } - - /** - * @internal - */ - _wsOnClose(code: number) { - this._rpcWebSocketConnected = false; - this._rpcWebSocketGeneration = - (this._rpcWebSocketGeneration + 1) % Number.MAX_SAFE_INTEGER; - if (this._rpcWebSocketIdleTimeout) { - clearTimeout(this._rpcWebSocketIdleTimeout); - this._rpcWebSocketIdleTimeout = null; - } - if (this._rpcWebSocketHeartbeat) { - clearInterval(this._rpcWebSocketHeartbeat); - this._rpcWebSocketHeartbeat = null; - } - - if (code === 1000) { - // explicit close, check if any subscriptions have been made since close - this._updateSubscriptions(); - return; - } - - // implicit close, prepare subscriptions for auto-reconnect - this._subscriptionCallbacksByServerSubscriptionId = {}; - Object.entries( - this._subscriptionsByHash as Record, - ).forEach(([hash, subscription]) => { - this._setSubscription(hash, { - ...subscription, - state: 'pending', - }); - }); - } - - /** - * @internal - */ - private _setSubscription( - hash: SubscriptionConfigHash, - nextSubscription: Subscription, - ) { - const prevState = this._subscriptionsByHash[hash]?.state; - this._subscriptionsByHash[hash] = nextSubscription; - if (prevState !== nextSubscription.state) { - const stateChangeCallbacks = - this._subscriptionStateChangeCallbacksByHash[hash]; - if (stateChangeCallbacks) { - stateChangeCallbacks.forEach(cb => { - try { - cb(nextSubscription.state); - // eslint-disable-next-line no-empty - } catch {} - }); - } - } - } - - /** - * @internal - */ - private _onSubscriptionStateChange( - clientSubscriptionId: ClientSubscriptionId, - callback: SubscriptionStateChangeCallback, - ): SubscriptionStateChangeDisposeFn { - const hash = - this._subscriptionHashByClientSubscriptionId[clientSubscriptionId]; - if (hash == null) { - return () => {}; - } - const stateChangeCallbacks = (this._subscriptionStateChangeCallbacksByHash[ - hash - ] ||= new Set()); - stateChangeCallbacks.add(callback); - return () => { - stateChangeCallbacks.delete(callback); - if (stateChangeCallbacks.size === 0) { - delete this._subscriptionStateChangeCallbacksByHash[hash]; - } - }; - } - - /** - * @internal - */ - async _updateSubscriptions() { - if (Object.keys(this._subscriptionsByHash).length === 0) { - if (this._rpcWebSocketConnected) { - this._rpcWebSocketConnected = false; - this._rpcWebSocketIdleTimeout = setTimeout(() => { - this._rpcWebSocketIdleTimeout = null; - try { - this._rpcWebSocket.close(); - } catch (err) { - // swallow error if socket has already been closed. - if (err instanceof Error) { - console.log( - `Error when closing socket connection: ${err.message}`, - ); - } - } - }, 500); - } - return; - } - - if (this._rpcWebSocketIdleTimeout !== null) { - clearTimeout(this._rpcWebSocketIdleTimeout); - this._rpcWebSocketIdleTimeout = null; - this._rpcWebSocketConnected = true; - } - - if (!this._rpcWebSocketConnected) { - this._rpcWebSocket.connect(); - return; - } - - const activeWebSocketGeneration = this._rpcWebSocketGeneration; - const isCurrentConnectionStillActive = () => { - return activeWebSocketGeneration === this._rpcWebSocketGeneration; - }; - - await Promise.all( - // Don't be tempted to change this to `Object.entries`. We call - // `_updateSubscriptions` recursively when processing the state, - // so it's important that we look up the *current* version of - // each subscription, every time we process a hash. - Object.keys(this._subscriptionsByHash).map(async hash => { - const subscription = this._subscriptionsByHash[hash]; - if (subscription === undefined) { - // This entry has since been deleted. Skip. - return; - } - switch (subscription.state) { - case 'pending': - case 'unsubscribed': - if (subscription.callbacks.size === 0) { - /** - * You can end up here when: - * - * - a subscription has recently unsubscribed - * without having new callbacks added to it - * while the unsubscribe was in flight, or - * - when a pending subscription has its - * listeners removed before a request was - * sent to the server. - * - * Being that nobody is interested in this - * subscription any longer, delete it. - */ - delete this._subscriptionsByHash[hash]; - if (subscription.state === 'unsubscribed') { - delete this._subscriptionCallbacksByServerSubscriptionId[ - subscription.serverSubscriptionId - ]; - } - await this._updateSubscriptions(); - return; - } - await (async () => { - const {args, method} = subscription; - try { - this._setSubscription(hash, { - ...subscription, - state: 'subscribing', - }); - const serverSubscriptionId: ServerSubscriptionId = - (await this._rpcWebSocket.call(method, args)) as number; - this._setSubscription(hash, { - ...subscription, - serverSubscriptionId, - state: 'subscribed', - }); - this._subscriptionCallbacksByServerSubscriptionId[ - serverSubscriptionId - ] = subscription.callbacks; - await this._updateSubscriptions(); - } catch (e) { - if (e instanceof Error) { - console.error( - `${method} error for argument`, - args, - e.message, - ); - } - if (!isCurrentConnectionStillActive()) { - return; - } - // TODO: Maybe add an 'errored' state or a retry limit? - this._setSubscription(hash, { - ...subscription, - state: 'pending', - }); - await this._updateSubscriptions(); - } - })(); - break; - case 'subscribed': - if (subscription.callbacks.size === 0) { - // By the time we successfully set up a subscription - // with the server, the client stopped caring about it. - // Tear it down now. - await (async () => { - const {serverSubscriptionId, unsubscribeMethod} = subscription; - if ( - this._subscriptionsAutoDisposedByRpc.has(serverSubscriptionId) - ) { - /** - * Special case. - * If we're dealing with a subscription that has been auto- - * disposed by the RPC, then we can skip the RPC call to - * tear down the subscription here. - * - * NOTE: There is a proposal to eliminate this special case, here: - * https://github.com/solana-labs/solana/issues/18892 - */ - this._subscriptionsAutoDisposedByRpc.delete( - serverSubscriptionId, - ); - } else { - this._setSubscription(hash, { - ...subscription, - state: 'unsubscribing', - }); - this._setSubscription(hash, { - ...subscription, - state: 'unsubscribing', - }); - try { - await this._rpcWebSocket.call(unsubscribeMethod, [ - serverSubscriptionId, - ]); - } catch (e) { - if (e instanceof Error) { - console.error(`${unsubscribeMethod} error:`, e.message); - } - if (!isCurrentConnectionStillActive()) { - return; - } - // TODO: Maybe add an 'errored' state or a retry limit? - this._setSubscription(hash, { - ...subscription, - state: 'subscribed', - }); - await this._updateSubscriptions(); - return; - } - } - this._setSubscription(hash, { - ...subscription, - state: 'unsubscribed', - }); - await this._updateSubscriptions(); - })(); - } - break; - case 'subscribing': - case 'unsubscribing': - break; - } - }), - ); - } - - /** - * @internal - */ - private _handleServerNotification< - TCallback extends SubscriptionConfig['callback'], - >( - serverSubscriptionId: ServerSubscriptionId, - callbackArgs: Parameters, - ): void { - const callbacks = - this._subscriptionCallbacksByServerSubscriptionId[serverSubscriptionId]; - if (callbacks === undefined) { - return; - } - callbacks.forEach(cb => { - try { - cb( - // I failed to find a way to convince TypeScript that `cb` is of type - // `TCallback` which is certainly compatible with `Parameters`. - // See https://github.com/microsoft/TypeScript/issues/47615 - // @ts-ignore - ...callbackArgs, - ); - } catch (e) { - console.error(e); - } - }); - } - - /** - * @internal - */ - _wsOnAccountNotification(notification: object) { - const {result, subscription} = create( - notification, - AccountNotificationResult, - ); - this._handleServerNotification(subscription, [ - result.value, - result.context, - ]); - } - - /** - * @internal - */ - private _makeSubscription( - subscriptionConfig: SubscriptionConfig, - /** - * When preparing `args` for a call to `_makeSubscription`, be sure - * to carefully apply a default `commitment` property, if necessary. - * - * - If the user supplied a `commitment` use that. - * - Otherwise, if the `Connection::commitment` is set, use that. - * - Otherwise, set it to the RPC server default: `finalized`. - * - * This is extremely important to ensure that these two fundamentally - * identical subscriptions produce the same identifying hash: - * - * - A subscription made without specifying a commitment. - * - A subscription made where the commitment specified is the same - * as the default applied to the subscription above. - * - * Example; these two subscriptions must produce the same hash: - * - * - An `accountSubscribe` subscription for `'PUBKEY'` - * - An `accountSubscribe` subscription for `'PUBKEY'` with commitment - * `'finalized'`. - * - * See the 'making a subscription with defaulted params omitted' test - * in `connection-subscriptions.ts` for more. - */ - args: IWSRequestParams, - ): ClientSubscriptionId { - const clientSubscriptionId = this._nextClientSubscriptionId++; - const hash = fastStableStringify([subscriptionConfig.method, args]); - const existingSubscription = this._subscriptionsByHash[hash]; - if (existingSubscription === undefined) { - this._subscriptionsByHash[hash] = { - ...subscriptionConfig, - args, - callbacks: new Set([subscriptionConfig.callback]), - state: 'pending', - }; - } else { - existingSubscription.callbacks.add(subscriptionConfig.callback); - } - this._subscriptionHashByClientSubscriptionId[clientSubscriptionId] = hash; - this._subscriptionDisposeFunctionsByClientSubscriptionId[ - clientSubscriptionId - ] = async () => { - delete this._subscriptionDisposeFunctionsByClientSubscriptionId[ - clientSubscriptionId - ]; - delete this._subscriptionHashByClientSubscriptionId[clientSubscriptionId]; - const subscription = this._subscriptionsByHash[hash]; - assert( - subscription !== undefined, - `Could not find a \`Subscription\` when tearing down client subscription #${clientSubscriptionId}`, - ); - subscription.callbacks.delete(subscriptionConfig.callback); - await this._updateSubscriptions(); - }; - this._updateSubscriptions(); - return clientSubscriptionId; - } - - /** - * Register a callback to be invoked whenever the specified account changes - * - * @param publicKey Public key of the account to monitor - * @param callback Function to invoke whenever the account is changed - * @param config - * @return subscription id - */ - onAccountChange( - publicKey: PublicKey, - callback: AccountChangeCallback, - config?: AccountSubscriptionConfig, - ): ClientSubscriptionId; - /** @deprecated Instead, pass in an {@link AccountSubscriptionConfig} */ - // eslint-disable-next-line no-dupe-class-members - onAccountChange( - publicKey: PublicKey, - callback: AccountChangeCallback, - commitment?: Commitment, - ): ClientSubscriptionId; - // eslint-disable-next-line no-dupe-class-members - onAccountChange( - publicKey: PublicKey, - callback: AccountChangeCallback, - commitmentOrConfig?: Commitment | AccountSubscriptionConfig, - ): ClientSubscriptionId { - const {commitment, config} = - extractCommitmentFromConfig(commitmentOrConfig); - const args = this._buildArgs( - [publicKey.toBase58()], - commitment || this._commitment || 'finalized', // Apply connection/server default. - 'base64', - config, - ); - return this._makeSubscription( - { - callback, - method: 'accountSubscribe', - unsubscribeMethod: 'accountUnsubscribe', - }, - args, - ); - } - - /** - * Deregister an account notification callback - * - * @param clientSubscriptionId client subscription id to deregister - */ - async removeAccountChangeListener( - clientSubscriptionId: ClientSubscriptionId, - ): Promise { - await this._unsubscribeClientSubscription( - clientSubscriptionId, - 'account change', - ); - } - - /** - * @internal - */ - _wsOnProgramAccountNotification(notification: Object) { - const {result, subscription} = create( - notification, - ProgramAccountNotificationResult, - ); - this._handleServerNotification(subscription, [ - { - accountId: result.value.pubkey, - accountInfo: result.value.account, - }, - result.context, - ]); - } - - /** - * Register a callback to be invoked whenever accounts owned by the - * specified program change - * - * @param programId Public key of the program to monitor - * @param callback Function to invoke whenever the account is changed - * @param config - * @return subscription id - */ - onProgramAccountChange( - programId: PublicKey, - callback: ProgramAccountChangeCallback, - config?: ProgramAccountSubscriptionConfig, - ): ClientSubscriptionId; - /** @deprecated Instead, pass in a {@link ProgramAccountSubscriptionConfig} */ - // eslint-disable-next-line no-dupe-class-members - onProgramAccountChange( - programId: PublicKey, - callback: ProgramAccountChangeCallback, - commitment?: Commitment, - filters?: GetProgramAccountsFilter[], - ): ClientSubscriptionId; - // eslint-disable-next-line no-dupe-class-members - onProgramAccountChange( - programId: PublicKey, - callback: ProgramAccountChangeCallback, - commitmentOrConfig?: Commitment | ProgramAccountSubscriptionConfig, - maybeFilters?: GetProgramAccountsFilter[], - ): ClientSubscriptionId { - const {commitment, config} = - extractCommitmentFromConfig(commitmentOrConfig); - const args = this._buildArgs( - [programId.toBase58()], - commitment || this._commitment || 'finalized', // Apply connection/server default. - 'base64' /* encoding */, - config - ? config - : maybeFilters - ? {filters: applyDefaultMemcmpEncodingToFilters(maybeFilters)} - : undefined /* extra */, - ); - return this._makeSubscription( - { - callback, - method: 'programSubscribe', - unsubscribeMethod: 'programUnsubscribe', - }, - args, - ); - } - - /** - * Deregister an account notification callback - * - * @param clientSubscriptionId client subscription id to deregister - */ - async removeProgramAccountChangeListener( - clientSubscriptionId: ClientSubscriptionId, - ): Promise { - await this._unsubscribeClientSubscription( - clientSubscriptionId, - 'program account change', - ); - } - - /** - * Registers a callback to be invoked whenever logs are emitted. - */ - onLogs( - filter: LogsFilter, - callback: LogsCallback, - commitment?: Commitment, - ): ClientSubscriptionId { - const args = this._buildArgs( - [typeof filter === 'object' ? {mentions: [filter.toString()]} : filter], - commitment || this._commitment || 'finalized', // Apply connection/server default. - ); - return this._makeSubscription( - { - callback, - method: 'logsSubscribe', - unsubscribeMethod: 'logsUnsubscribe', - }, - args, - ); - } - - /** - * Deregister a logs callback. - * - * @param clientSubscriptionId client subscription id to deregister. - */ - async removeOnLogsListener( - clientSubscriptionId: ClientSubscriptionId, - ): Promise { - await this._unsubscribeClientSubscription(clientSubscriptionId, 'logs'); - } - - /** - * @internal - */ - _wsOnLogsNotification(notification: Object) { - const {result, subscription} = create(notification, LogsNotificationResult); - this._handleServerNotification(subscription, [ - result.value, - result.context, - ]); - } - - /** - * @internal - */ - _wsOnSlotNotification(notification: Object) { - const {result, subscription} = create(notification, SlotNotificationResult); - this._handleServerNotification(subscription, [result]); - } - - /** - * Register a callback to be invoked upon slot changes - * - * @param callback Function to invoke whenever the slot changes - * @return subscription id - */ - onSlotChange(callback: SlotChangeCallback): ClientSubscriptionId { - return this._makeSubscription( - { - callback, - method: 'slotSubscribe', - unsubscribeMethod: 'slotUnsubscribe', - }, - [] /* args */, - ); - } - - /** - * Deregister a slot notification callback - * - * @param clientSubscriptionId client subscription id to deregister - */ - async removeSlotChangeListener( - clientSubscriptionId: ClientSubscriptionId, - ): Promise { - await this._unsubscribeClientSubscription( - clientSubscriptionId, - 'slot change', - ); - } - - /** - * @internal - */ - _wsOnSlotUpdatesNotification(notification: Object) { - const {result, subscription} = create( - notification, - SlotUpdateNotificationResult, - ); - this._handleServerNotification(subscription, [result]); - } - - /** - * Register a callback to be invoked upon slot updates. {@link SlotUpdate}'s - * may be useful to track live progress of a cluster. - * - * @param callback Function to invoke whenever the slot updates - * @return subscription id - */ - onSlotUpdate(callback: SlotUpdateCallback): ClientSubscriptionId { - return this._makeSubscription( - { - callback, - method: 'slotsUpdatesSubscribe', - unsubscribeMethod: 'slotsUpdatesUnsubscribe', - }, - [] /* args */, - ); - } - - /** - * Deregister a slot update notification callback - * - * @param clientSubscriptionId client subscription id to deregister - */ - async removeSlotUpdateListener( - clientSubscriptionId: ClientSubscriptionId, - ): Promise { - await this._unsubscribeClientSubscription( - clientSubscriptionId, - 'slot update', - ); - } - - /** - * @internal - */ - - private async _unsubscribeClientSubscription( - clientSubscriptionId: ClientSubscriptionId, - subscriptionName: string, - ) { - const dispose = - this._subscriptionDisposeFunctionsByClientSubscriptionId[ - clientSubscriptionId - ]; - if (dispose) { - await dispose(); - } else { - console.warn( - 'Ignored unsubscribe request because an active subscription with id ' + - `\`${clientSubscriptionId}\` for '${subscriptionName}' events ` + - 'could not be found.', - ); - } - } - - _buildArgs( - args: Array, - override?: Commitment, - encoding?: 'jsonParsed' | 'base64', - extra?: any, - ): Array { - const commitment = override || this._commitment; - if (commitment || encoding || extra) { - let options: any = {}; - if (encoding) { - options.encoding = encoding; - } - if (commitment) { - options.commitment = commitment; - } - if (extra) { - options = Object.assign(options, extra); - } - args.push(options); - } - return args; - } - - /** - * @internal - */ - _buildArgsAtLeastConfirmed( - args: Array, - override?: Finality, - encoding?: 'jsonParsed' | 'base64', - extra?: any, - ): Array { - const commitment = override || this._commitment; - if (commitment && !['confirmed', 'finalized'].includes(commitment)) { - throw new Error( - 'Using Connection with default commitment: `' + - this._commitment + - '`, but method requires at least `confirmed`', - ); - } - return this._buildArgs(args, override, encoding, extra); - } - - /** - * @internal - */ - _wsOnSignatureNotification(notification: Object) { - const {result, subscription} = create( - notification, - SignatureNotificationResult, - ); - if (result.value !== 'receivedSignature') { - /** - * Special case. - * After a signature is processed, RPCs automatically dispose of the - * subscription on the server side. We need to track which of these - * subscriptions have been disposed in such a way, so that we know - * whether the client is dealing with a not-yet-processed signature - * (in which case we must tear down the server subscription) or an - * already-processed signature (in which case the client can simply - * clear out the subscription locally without telling the server). - * - * NOTE: There is a proposal to eliminate this special case, here: - * https://github.com/solana-labs/solana/issues/18892 - */ - this._subscriptionsAutoDisposedByRpc.add(subscription); - } - this._handleServerNotification( - subscription, - result.value === 'receivedSignature' - ? [{type: 'received'}, result.context] - : [{type: 'status', result: result.value}, result.context], - ); - } - - /** - * Register a callback to be invoked upon signature updates - * - * @param signature Transaction signature string in base 58 - * @param callback Function to invoke on signature notifications - * @param commitment Specify the commitment level signature must reach before notification - * @return subscription id - */ - onSignature( - signature: TransactionSignature, - callback: SignatureResultCallback, - commitment?: Commitment, - ): ClientSubscriptionId { - const args = this._buildArgs( - [signature], - commitment || this._commitment || 'finalized', // Apply connection/server default. - ); - const clientSubscriptionId = this._makeSubscription( - { - callback: (notification, context) => { - if (notification.type === 'status') { - callback(notification.result, context); - // Signatures subscriptions are auto-removed by the RPC service - // so no need to explicitly send an unsubscribe message. - try { - this.removeSignatureListener(clientSubscriptionId); - // eslint-disable-next-line no-empty - } catch (_err) { - // Already removed. - } - } - }, - method: 'signatureSubscribe', - unsubscribeMethod: 'signatureUnsubscribe', - }, - args, - ); - return clientSubscriptionId; - } - - /** - * Register a callback to be invoked when a transaction is - * received and/or processed. - * - * @param signature Transaction signature string in base 58 - * @param callback Function to invoke on signature notifications - * @param options Enable received notifications and set the commitment - * level that signature must reach before notification - * @return subscription id - */ - onSignatureWithOptions( - signature: TransactionSignature, - callback: SignatureSubscriptionCallback, - options?: SignatureSubscriptionOptions, - ): ClientSubscriptionId { - const {commitment, ...extra} = { - ...options, - commitment: - (options && options.commitment) || this._commitment || 'finalized', // Apply connection/server default. - }; - const args = this._buildArgs( - [signature], - commitment, - undefined /* encoding */, - extra, - ); - const clientSubscriptionId = this._makeSubscription( - { - callback: (notification, context) => { - callback(notification, context); - // Signatures subscriptions are auto-removed by the RPC service - // so no need to explicitly send an unsubscribe message. - try { - this.removeSignatureListener(clientSubscriptionId); - // eslint-disable-next-line no-empty - } catch (_err) { - // Already removed. - } - }, - method: 'signatureSubscribe', - unsubscribeMethod: 'signatureUnsubscribe', - }, - args, - ); - return clientSubscriptionId; - } - - /** - * Deregister a signature notification callback - * - * @param clientSubscriptionId client subscription id to deregister - */ - async removeSignatureListener( - clientSubscriptionId: ClientSubscriptionId, - ): Promise { - await this._unsubscribeClientSubscription( - clientSubscriptionId, - 'signature result', - ); - } - - /** - * @internal - */ - _wsOnRootNotification(notification: Object) { - const {result, subscription} = create(notification, RootNotificationResult); - this._handleServerNotification(subscription, [result]); - } - - /** - * Register a callback to be invoked upon root changes - * - * @param callback Function to invoke whenever the root changes - * @return subscription id - */ - onRootChange(callback: RootChangeCallback): ClientSubscriptionId { - return this._makeSubscription( - { - callback, - method: 'rootSubscribe', - unsubscribeMethod: 'rootUnsubscribe', - }, - [] /* args */, - ); - } - - /** - * Deregister a root notification callback - * - * @param clientSubscriptionId client subscription id to deregister - */ - async removeRootChangeListener( - clientSubscriptionId: ClientSubscriptionId, - ): Promise { - await this._unsubscribeClientSubscription( - clientSubscriptionId, - 'root change', - ); - } -} diff --git a/packages/library-legacy/src/epoch-schedule.ts b/packages/library-legacy/src/epoch-schedule.ts deleted file mode 100644 index b6d0e7411ba1..000000000000 --- a/packages/library-legacy/src/epoch-schedule.ts +++ /dev/null @@ -1,102 +0,0 @@ -const MINIMUM_SLOT_PER_EPOCH = 32; - -// Returns the number of trailing zeros in the binary representation of self. -function trailingZeros(n: number) { - let trailingZeros = 0; - while (n > 1) { - n /= 2; - trailingZeros++; - } - return trailingZeros; -} - -// Returns the smallest power of two greater than or equal to n -function nextPowerOfTwo(n: number) { - if (n === 0) return 1; - n--; - n |= n >> 1; - n |= n >> 2; - n |= n >> 4; - n |= n >> 8; - n |= n >> 16; - n |= n >> 32; - return n + 1; -} - -/** - * Epoch schedule - * (see https://docs.solana.com/terminology#epoch) - * Can be retrieved with the {@link Connection.getEpochSchedule} method - */ -export class EpochSchedule { - /** The maximum number of slots in each epoch */ - public slotsPerEpoch: number; - /** The number of slots before beginning of an epoch to calculate a leader schedule for that epoch */ - public leaderScheduleSlotOffset: number; - /** Indicates whether epochs start short and grow */ - public warmup: boolean; - /** The first epoch with `slotsPerEpoch` slots */ - public firstNormalEpoch: number; - /** The first slot of `firstNormalEpoch` */ - public firstNormalSlot: number; - - constructor( - slotsPerEpoch: number, - leaderScheduleSlotOffset: number, - warmup: boolean, - firstNormalEpoch: number, - firstNormalSlot: number, - ) { - this.slotsPerEpoch = slotsPerEpoch; - this.leaderScheduleSlotOffset = leaderScheduleSlotOffset; - this.warmup = warmup; - this.firstNormalEpoch = firstNormalEpoch; - this.firstNormalSlot = firstNormalSlot; - } - - getEpoch(slot: number): number { - return this.getEpochAndSlotIndex(slot)[0]; - } - - getEpochAndSlotIndex(slot: number): [number, number] { - if (slot < this.firstNormalSlot) { - const epoch = - trailingZeros(nextPowerOfTwo(slot + MINIMUM_SLOT_PER_EPOCH + 1)) - - trailingZeros(MINIMUM_SLOT_PER_EPOCH) - - 1; - - const epochLen = this.getSlotsInEpoch(epoch); - const slotIndex = slot - (epochLen - MINIMUM_SLOT_PER_EPOCH); - return [epoch, slotIndex]; - } else { - const normalSlotIndex = slot - this.firstNormalSlot; - const normalEpochIndex = Math.floor(normalSlotIndex / this.slotsPerEpoch); - const epoch = this.firstNormalEpoch + normalEpochIndex; - const slotIndex = normalSlotIndex % this.slotsPerEpoch; - return [epoch, slotIndex]; - } - } - - getFirstSlotInEpoch(epoch: number): number { - if (epoch <= this.firstNormalEpoch) { - return (Math.pow(2, epoch) - 1) * MINIMUM_SLOT_PER_EPOCH; - } else { - return ( - (epoch - this.firstNormalEpoch) * this.slotsPerEpoch + - this.firstNormalSlot - ); - } - } - - getLastSlotInEpoch(epoch: number): number { - return this.getFirstSlotInEpoch(epoch) + this.getSlotsInEpoch(epoch) - 1; - } - - getSlotsInEpoch(epoch: number) { - if (epoch < this.firstNormalEpoch) { - return Math.pow(2, epoch + trailingZeros(MINIMUM_SLOT_PER_EPOCH)); - } else { - return this.slotsPerEpoch; - } - } -} diff --git a/packages/library-legacy/src/errors.ts b/packages/library-legacy/src/errors.ts deleted file mode 100644 index 47c5a657e715..000000000000 --- a/packages/library-legacy/src/errors.ts +++ /dev/null @@ -1,133 +0,0 @@ -import {Connection} from './connection'; -import {TransactionSignature} from './transaction'; - -export class SendTransactionError extends Error { - private signature: TransactionSignature; - private transactionMessage: string; - private transactionLogs: string[] | Promise | undefined; - - constructor({ - action, - signature, - transactionMessage, - logs, - }: { - action: 'send' | 'simulate'; - signature: TransactionSignature; - transactionMessage: string; - logs?: string[]; - }) { - const maybeLogsOutput = logs - ? `Logs: \n${JSON.stringify(logs.slice(-10), null, 2)}. ` - : ''; - const guideText = - '\nCatch the `SendTransactionError` and call `getLogs()` on it for full details.'; - let message: string; - switch (action) { - case 'send': - message = - `Transaction ${signature} resulted in an error. \n` + - `${transactionMessage}. ` + - maybeLogsOutput + - guideText; - break; - case 'simulate': - message = - `Simulation failed. \nMessage: ${transactionMessage}. \n` + - maybeLogsOutput + - guideText; - break; - default: { - message = `Unknown action '${((a: never) => a)(action)}'`; - } - } - super(message); - - this.signature = signature; - this.transactionMessage = transactionMessage; - this.transactionLogs = logs ? logs : undefined; - } - - get transactionError(): {message: string; logs?: string[]} { - return { - message: this.transactionMessage, - logs: Array.isArray(this.transactionLogs) - ? this.transactionLogs - : undefined, - }; - } - - /* @deprecated Use `await getLogs()` instead */ - get logs(): string[] | undefined { - const cachedLogs = this.transactionLogs; - if ( - cachedLogs != null && - typeof cachedLogs === 'object' && - 'then' in cachedLogs - ) { - return undefined; - } - return cachedLogs; - } - - async getLogs(connection: Connection): Promise { - if (!Array.isArray(this.transactionLogs)) { - this.transactionLogs = new Promise((resolve, reject) => { - connection - .getTransaction(this.signature) - .then(tx => { - if (tx && tx.meta && tx.meta.logMessages) { - const logs = tx.meta.logMessages; - this.transactionLogs = logs; - resolve(logs); - } else { - reject(new Error('Log messages not found')); - } - }) - .catch(reject); - }); - } - return await this.transactionLogs; - } -} - -// Keep in sync with client/src/rpc_custom_errors.rs -// Typescript `enums` thwart tree-shaking. See https://bargsten.org/jsts/enums/ -export const SolanaJSONRPCErrorCode = { - JSON_RPC_SERVER_ERROR_BLOCK_CLEANED_UP: -32001, - JSON_RPC_SERVER_ERROR_SEND_TRANSACTION_PREFLIGHT_FAILURE: -32002, - JSON_RPC_SERVER_ERROR_TRANSACTION_SIGNATURE_VERIFICATION_FAILURE: -32003, - JSON_RPC_SERVER_ERROR_BLOCK_NOT_AVAILABLE: -32004, - JSON_RPC_SERVER_ERROR_NODE_UNHEALTHY: -32005, - JSON_RPC_SERVER_ERROR_TRANSACTION_PRECOMPILE_VERIFICATION_FAILURE: -32006, - JSON_RPC_SERVER_ERROR_SLOT_SKIPPED: -32007, - JSON_RPC_SERVER_ERROR_NO_SNAPSHOT: -32008, - JSON_RPC_SERVER_ERROR_LONG_TERM_STORAGE_SLOT_SKIPPED: -32009, - JSON_RPC_SERVER_ERROR_KEY_EXCLUDED_FROM_SECONDARY_INDEX: -32010, - JSON_RPC_SERVER_ERROR_TRANSACTION_HISTORY_NOT_AVAILABLE: -32011, - JSON_RPC_SCAN_ERROR: -32012, - JSON_RPC_SERVER_ERROR_TRANSACTION_SIGNATURE_LEN_MISMATCH: -32013, - JSON_RPC_SERVER_ERROR_BLOCK_STATUS_NOT_AVAILABLE_YET: -32014, - JSON_RPC_SERVER_ERROR_UNSUPPORTED_TRANSACTION_VERSION: -32015, - JSON_RPC_SERVER_ERROR_MIN_CONTEXT_SLOT_NOT_REACHED: -32016, -} as const; -export type SolanaJSONRPCErrorCodeEnum = - (typeof SolanaJSONRPCErrorCode)[keyof typeof SolanaJSONRPCErrorCode]; - -export class SolanaJSONRPCError extends Error { - code: SolanaJSONRPCErrorCodeEnum | unknown; - data?: any; - constructor( - { - code, - message, - data, - }: Readonly<{code: unknown; message: string; data?: any}>, - customMessage?: string, - ) { - super(customMessage != null ? `${customMessage}: ${message}` : message); - this.code = code; - this.data = data; - this.name = 'SolanaJSONRPCError'; - } -} diff --git a/packages/library-legacy/src/fee-calculator.ts b/packages/library-legacy/src/fee-calculator.ts deleted file mode 100644 index eca886ac33bf..000000000000 --- a/packages/library-legacy/src/fee-calculator.ts +++ /dev/null @@ -1,18 +0,0 @@ -import * as BufferLayout from '@solana/buffer-layout'; - -/** - * https://github.com/solana-labs/solana/blob/90bedd7e067b5b8f3ddbb45da00a4e9cabb22c62/sdk/src/fee_calculator.rs#L7-L11 - * - * @internal - */ -export const FeeCalculatorLayout = BufferLayout.nu64('lamportsPerSignature'); - -/** - * Calculator for transaction fees. - * - * @deprecated Deprecated since Solana v1.8.0. - */ -export interface FeeCalculator { - /** Cost in lamports to validate a signature. */ - lamportsPerSignature: number; -} diff --git a/packages/library-legacy/src/fetch-impl.ts b/packages/library-legacy/src/fetch-impl.ts deleted file mode 100644 index a41c05afa33c..000000000000 --- a/packages/library-legacy/src/fetch-impl.ts +++ /dev/null @@ -1,16 +0,0 @@ -import * as nodeFetch from 'node-fetch'; - -export default (typeof globalThis.fetch === 'function' - ? // The Fetch API is supported experimentally in Node 17.5+ and natively in Node 18+. - globalThis.fetch - : // Otherwise use the polyfill. - async function ( - input: nodeFetch.RequestInfo, - init?: nodeFetch.RequestInit, - ): Promise { - const processedInput = - typeof input === 'string' && input.slice(0, 2) === '//' - ? 'https:' + input - : input; - return await nodeFetch.default(processedInput, init); - }) as typeof globalThis.fetch; diff --git a/packages/library-legacy/src/index.ts b/packages/library-legacy/src/index.ts deleted file mode 100644 index 5a0f705710f0..000000000000 --- a/packages/library-legacy/src/index.ts +++ /dev/null @@ -1,24 +0,0 @@ -export * from './account'; -export * from './blockhash'; -export * from './bpf-loader-deprecated'; -export * from './bpf-loader'; -export * from './connection'; -export * from './epoch-schedule'; -export * from './errors'; -export * from './fee-calculator'; -export * from './keypair'; -export * from './loader'; -export * from './message'; -export * from './nonce-account'; -export * from './programs'; -export * from './publickey'; -export * from './transaction'; -export * from './validator-info'; -export * from './vote-account'; -export * from './sysvar'; -export * from './utils'; - -/** - * There are 1-billion lamports in one SOL - */ -export const LAMPORTS_PER_SOL = 1000000000; diff --git a/packages/library-legacy/src/instruction.ts b/packages/library-legacy/src/instruction.ts deleted file mode 100644 index 4097211a50a9..000000000000 --- a/packages/library-legacy/src/instruction.ts +++ /dev/null @@ -1,58 +0,0 @@ -import {Buffer} from 'buffer'; -import * as BufferLayout from '@solana/buffer-layout'; - -import * as Layout from './layout'; - -export interface IInstructionInputData { - readonly instruction: number; -} - -/** - * @internal - */ -export type InstructionType = { - /** The Instruction index (from solana upstream program) */ - index: number; - /** The BufferLayout to use to build data */ - layout: BufferLayout.Layout; -}; - -/** - * Populate a buffer of instruction data using an InstructionType - * @internal - */ -export function encodeData( - type: InstructionType, - fields?: any, -): Buffer { - const allocLength = - type.layout.span >= 0 ? type.layout.span : Layout.getAlloc(type, fields); - const data = Buffer.alloc(allocLength); - const layoutFields = Object.assign({instruction: type.index}, fields); - type.layout.encode(layoutFields, data); - return data; -} - -/** - * Decode instruction data buffer using an InstructionType - * @internal - */ -export function decodeData( - type: InstructionType, - buffer: Buffer, -): TInputData { - let data: TInputData; - try { - data = type.layout.decode(buffer); - } catch (err) { - throw new Error('invalid instruction; ' + err); - } - - if (data.instruction !== type.index) { - throw new Error( - `invalid instruction; instruction index mismatch ${data.instruction} != ${type.index}`, - ); - } - - return data; -} diff --git a/packages/library-legacy/src/keypair.ts b/packages/library-legacy/src/keypair.ts deleted file mode 100644 index 7129df9c6f06..000000000000 --- a/packages/library-legacy/src/keypair.ts +++ /dev/null @@ -1,102 +0,0 @@ -import {generateKeypair, getPublicKey, Ed25519Keypair} from './utils/ed25519'; -import {PublicKey} from './publickey'; - -/** - * Keypair signer interface - */ -export interface Signer { - publicKey: PublicKey; - secretKey: Uint8Array; -} - -/** - * An account keypair used for signing transactions. - */ -export class Keypair { - private _keypair: Ed25519Keypair; - - /** - * Create a new keypair instance. - * Generate random keypair if no {@link Ed25519Keypair} is provided. - * - * @param {Ed25519Keypair} keypair ed25519 keypair - */ - constructor(keypair?: Ed25519Keypair) { - this._keypair = keypair ?? generateKeypair(); - } - - /** - * Generate a new random keypair - * - * @returns {Keypair} Keypair - */ - static generate(): Keypair { - return new Keypair(generateKeypair()); - } - - /** - * Create a keypair from a raw secret key byte array. - * - * This method should only be used to recreate a keypair from a previously - * generated secret key. Generating keypairs from a random seed should be done - * with the {@link Keypair.fromSeed} method. - * - * @throws error if the provided secret key is invalid and validation is not skipped. - * - * @param secretKey secret key byte array - * @param options skip secret key validation - * - * @returns {Keypair} Keypair - */ - static fromSecretKey( - secretKey: Uint8Array, - options?: {skipValidation?: boolean}, - ): Keypair { - if (secretKey.byteLength !== 64) { - throw new Error('bad secret key size'); - } - const publicKey = secretKey.slice(32, 64); - if (!options || !options.skipValidation) { - const privateScalar = secretKey.slice(0, 32); - const computedPublicKey = getPublicKey(privateScalar); - for (let ii = 0; ii < 32; ii++) { - if (publicKey[ii] !== computedPublicKey[ii]) { - throw new Error('provided secretKey is invalid'); - } - } - } - return new Keypair({publicKey, secretKey}); - } - - /** - * Generate a keypair from a 32 byte seed. - * - * @param seed seed byte array - * - * @returns {Keypair} Keypair - */ - static fromSeed(seed: Uint8Array): Keypair { - const publicKey = getPublicKey(seed); - const secretKey = new Uint8Array(64); - secretKey.set(seed); - secretKey.set(publicKey, 32); - return new Keypair({publicKey, secretKey}); - } - - /** - * The public key for this keypair - * - * @returns {PublicKey} PublicKey - */ - get publicKey(): PublicKey { - return new PublicKey(this._keypair.publicKey); - } - - /** - * The raw secret key for this keypair - * @returns {Uint8Array} Secret key in an array of Uint8 bytes - */ - get secretKey(): Uint8Array { - return new Uint8Array(this._keypair.secretKey); - } -} diff --git a/packages/library-legacy/src/layout.ts b/packages/library-legacy/src/layout.ts deleted file mode 100644 index 35a5f6d8027a..000000000000 --- a/packages/library-legacy/src/layout.ts +++ /dev/null @@ -1,188 +0,0 @@ -import {Buffer} from 'buffer'; -import * as BufferLayout from '@solana/buffer-layout'; - -import {VoteAuthorizeWithSeedArgs} from './programs/vote'; - -/** - * Layout for a public key - */ -export const publicKey = (property: string = 'publicKey') => { - return BufferLayout.blob(32, property); -}; - -/** - * Layout for a signature - */ -export const signature = (property: string = 'signature') => { - return BufferLayout.blob(64, property); -}; - -/** - * Layout for a 64bit unsigned value - */ -export const uint64 = (property: string = 'uint64') => { - return BufferLayout.blob(8, property); -}; - -interface IRustStringShim - extends Omit< - BufferLayout.Structure< - Readonly<{ - length: number; - lengthPadding: number; - chars: Uint8Array; - }> - >, - 'decode' | 'encode' | 'replicate' - > { - alloc: (str: string) => number; - decode: (b: Uint8Array, offset?: number) => string; - encode: (str: string, b: Uint8Array, offset?: number) => number; - replicate: (property: string) => this; -} - -/** - * Layout for a Rust String type - */ -export const rustString = ( - property: string = 'string', -): BufferLayout.Layout => { - const rsl = BufferLayout.struct< - Readonly<{ - length?: number; - lengthPadding?: number; - chars: Uint8Array; - }> - >( - [ - BufferLayout.u32('length'), - BufferLayout.u32('lengthPadding'), - BufferLayout.blob(BufferLayout.offset(BufferLayout.u32(), -8), 'chars'), - ], - property, - ); - const _decode = rsl.decode.bind(rsl); - const _encode = rsl.encode.bind(rsl); - - const rslShim = rsl as unknown as IRustStringShim; - - rslShim.decode = (b: Uint8Array, offset?: number) => { - const data = _decode(b, offset); - return data['chars'].toString(); - }; - - rslShim.encode = (str: string, b: Uint8Array, offset?: number) => { - const data = { - chars: Buffer.from(str, 'utf8'), - }; - return _encode(data, b, offset); - }; - - rslShim.alloc = (str: string) => { - return ( - BufferLayout.u32().span + - BufferLayout.u32().span + - Buffer.from(str, 'utf8').length - ); - }; - - return rslShim; -}; - -/** - * Layout for an Authorized object - */ -export const authorized = (property: string = 'authorized') => { - return BufferLayout.struct< - Readonly<{ - staker: Uint8Array; - withdrawer: Uint8Array; - }> - >([publicKey('staker'), publicKey('withdrawer')], property); -}; - -/** - * Layout for a Lockup object - */ -export const lockup = (property: string = 'lockup') => { - return BufferLayout.struct< - Readonly<{ - custodian: Uint8Array; - epoch: number; - unixTimestamp: number; - }> - >( - [ - BufferLayout.ns64('unixTimestamp'), - BufferLayout.ns64('epoch'), - publicKey('custodian'), - ], - property, - ); -}; - -/** - * Layout for a VoteInit object - */ -export const voteInit = (property: string = 'voteInit') => { - return BufferLayout.struct< - Readonly<{ - authorizedVoter: Uint8Array; - authorizedWithdrawer: Uint8Array; - commission: number; - nodePubkey: Uint8Array; - }> - >( - [ - publicKey('nodePubkey'), - publicKey('authorizedVoter'), - publicKey('authorizedWithdrawer'), - BufferLayout.u8('commission'), - ], - property, - ); -}; - -/** - * Layout for a VoteAuthorizeWithSeedArgs object - */ -export const voteAuthorizeWithSeedArgs = ( - property: string = 'voteAuthorizeWithSeedArgs', -) => { - return BufferLayout.struct( - [ - BufferLayout.u32('voteAuthorizationType'), - publicKey('currentAuthorityDerivedKeyOwnerPubkey'), - rustString('currentAuthorityDerivedKeySeed'), - publicKey('newAuthorized'), - ], - property, - ); -}; - -export function getAlloc(type: any, fields: any): number { - const getItemAlloc = (item: any): number => { - if (item.span >= 0) { - return item.span; - } else if (typeof item.alloc === 'function') { - return item.alloc(fields[item.property]); - } else if ('count' in item && 'elementLayout' in item) { - const field = fields[item.property]; - if (Array.isArray(field)) { - return field.length * getItemAlloc(item.elementLayout); - } - } else if ('fields' in item) { - // This is a `Structure` whose size needs to be recursively measured. - return getAlloc({layout: item}, fields[item.property]); - } - // Couldn't determine allocated size of layout - return 0; - }; - - let alloc = 0; - type.layout.fields.forEach((item: any) => { - alloc += getItemAlloc(item); - }); - - return alloc; -} diff --git a/packages/library-legacy/src/loader.ts b/packages/library-legacy/src/loader.ts deleted file mode 100644 index 736c5e85f3b7..000000000000 --- a/packages/library-legacy/src/loader.ts +++ /dev/null @@ -1,267 +0,0 @@ -import {Buffer} from 'buffer'; -import * as BufferLayout from '@solana/buffer-layout'; - -import {PublicKey} from './publickey'; -import {Transaction, PACKET_DATA_SIZE} from './transaction'; -import {MS_PER_SLOT} from './timing'; -import {SYSVAR_RENT_PUBKEY} from './sysvar'; -import {sendAndConfirmTransaction} from './utils/send-and-confirm-transaction'; -import {sleep} from './utils/sleep'; -import type {Connection} from './connection'; -import type {Signer} from './keypair'; -import {SystemProgram} from './programs/system'; -import {IInstructionInputData} from './instruction'; - -// Keep program chunks under PACKET_DATA_SIZE, leaving enough room for the -// rest of the Transaction fields -// -// TODO: replace 300 with a proper constant for the size of the other -// Transaction fields -const CHUNK_SIZE = PACKET_DATA_SIZE - 300; - -/** - * Program loader interface - */ -export class Loader { - /** - * @internal - */ - constructor() {} - - /** - * Amount of program data placed in each load Transaction - */ - static chunkSize: number = CHUNK_SIZE; - - /** - * Minimum number of signatures required to load a program not including - * retries - * - * Can be used to calculate transaction fees - */ - static getMinNumSignatures(dataLength: number): number { - return ( - 2 * // Every transaction requires two signatures (payer + program) - (Math.ceil(dataLength / Loader.chunkSize) + - 1 + // Add one for Create transaction - 1) // Add one for Finalize transaction - ); - } - - /** - * Loads a generic program - * - * @param connection The connection to use - * @param payer System account that pays to load the program - * @param program Account to load the program into - * @param programId Public key that identifies the loader - * @param data Program octets - * @return true if program was loaded successfully, false if program was already loaded - */ - static async load( - connection: Connection, - payer: Signer, - program: Signer, - programId: PublicKey, - data: Buffer | Uint8Array | Array, - ): Promise { - { - const balanceNeeded = await connection.getMinimumBalanceForRentExemption( - data.length, - ); - - // Fetch program account info to check if it has already been created - const programInfo = await connection.getAccountInfo( - program.publicKey, - 'confirmed', - ); - - let transaction: Transaction | null = null; - if (programInfo !== null) { - if (programInfo.executable) { - console.error('Program load failed, account is already executable'); - return false; - } - - if (programInfo.data.length !== data.length) { - transaction = transaction || new Transaction(); - transaction.add( - SystemProgram.allocate({ - accountPubkey: program.publicKey, - space: data.length, - }), - ); - } - - if (!programInfo.owner.equals(programId)) { - transaction = transaction || new Transaction(); - transaction.add( - SystemProgram.assign({ - accountPubkey: program.publicKey, - programId, - }), - ); - } - - if (programInfo.lamports < balanceNeeded) { - transaction = transaction || new Transaction(); - transaction.add( - SystemProgram.transfer({ - fromPubkey: payer.publicKey, - toPubkey: program.publicKey, - lamports: balanceNeeded - programInfo.lamports, - }), - ); - } - } else { - transaction = new Transaction().add( - SystemProgram.createAccount({ - fromPubkey: payer.publicKey, - newAccountPubkey: program.publicKey, - lamports: balanceNeeded > 0 ? balanceNeeded : 1, - space: data.length, - programId, - }), - ); - } - - // If the account is already created correctly, skip this step - // and proceed directly to loading instructions - if (transaction !== null) { - await sendAndConfirmTransaction( - connection, - transaction, - [payer, program], - { - commitment: 'confirmed', - }, - ); - } - } - - const dataLayout = BufferLayout.struct< - Readonly<{ - bytes: number[]; - bytesLength: number; - bytesLengthPadding: number; - instruction: number; - offset: number; - }> - >([ - BufferLayout.u32('instruction'), - BufferLayout.u32('offset'), - BufferLayout.u32('bytesLength'), - BufferLayout.u32('bytesLengthPadding'), - BufferLayout.seq( - BufferLayout.u8('byte'), - BufferLayout.offset(BufferLayout.u32(), -8), - 'bytes', - ), - ]); - - const chunkSize = Loader.chunkSize; - let offset = 0; - let array = data; - let transactions = []; - while (array.length > 0) { - const bytes = array.slice(0, chunkSize); - const data = Buffer.alloc(chunkSize + 16); - dataLayout.encode( - { - instruction: 0, // Load instruction - offset, - bytes: bytes as number[], - bytesLength: 0, - bytesLengthPadding: 0, - }, - data, - ); - - const transaction = new Transaction().add({ - keys: [{pubkey: program.publicKey, isSigner: true, isWritable: true}], - programId, - data, - }); - transactions.push( - sendAndConfirmTransaction(connection, transaction, [payer, program], { - commitment: 'confirmed', - }), - ); - - // Delay between sends in an attempt to reduce rate limit errors - if (connection._rpcEndpoint.includes('solana.com')) { - const REQUESTS_PER_SECOND = 4; - await sleep(1000 / REQUESTS_PER_SECOND); - } - - offset += chunkSize; - array = array.slice(chunkSize); - } - await Promise.all(transactions); - - // Finalize the account loaded with program data for execution - { - const dataLayout = BufferLayout.struct([ - BufferLayout.u32('instruction'), - ]); - - const data = Buffer.alloc(dataLayout.span); - dataLayout.encode( - { - instruction: 1, // Finalize instruction - }, - data, - ); - - const transaction = new Transaction().add({ - keys: [ - {pubkey: program.publicKey, isSigner: true, isWritable: true}, - {pubkey: SYSVAR_RENT_PUBKEY, isSigner: false, isWritable: false}, - ], - programId, - data, - }); - const deployCommitment = 'processed'; - const finalizeSignature = await connection.sendTransaction( - transaction, - [payer, program], - {preflightCommitment: deployCommitment}, - ); - const {context, value} = await connection.confirmTransaction( - { - signature: finalizeSignature, - lastValidBlockHeight: transaction.lastValidBlockHeight!, - blockhash: transaction.recentBlockhash!, - }, - deployCommitment, - ); - if (value.err) { - throw new Error( - `Transaction ${finalizeSignature} failed (${JSON.stringify(value)})`, - ); - } - // We prevent programs from being usable until the slot after their deployment. - // See https://github.com/solana-labs/solana/pull/29654 - while ( - true // eslint-disable-line no-constant-condition - ) { - try { - const currentSlot = await connection.getSlot({ - commitment: deployCommitment, - }); - if (currentSlot > context.slot) { - break; - } - } catch { - /* empty */ - } - await new Promise(resolve => - setTimeout(resolve, Math.round(MS_PER_SLOT / 2)), - ); - } - } - - // success - return true; - } -} diff --git a/packages/library-legacy/src/message/account-keys.ts b/packages/library-legacy/src/message/account-keys.ts deleted file mode 100644 index 73a6ca56ee41..000000000000 --- a/packages/library-legacy/src/message/account-keys.ts +++ /dev/null @@ -1,79 +0,0 @@ -import {LoadedAddresses} from '../connection'; -import {PublicKey} from '../publickey'; -import {TransactionInstruction} from '../transaction'; -import {MessageCompiledInstruction} from './index'; - -export type AccountKeysFromLookups = LoadedAddresses; - -export class MessageAccountKeys { - staticAccountKeys: Array; - accountKeysFromLookups?: AccountKeysFromLookups; - - constructor( - staticAccountKeys: Array, - accountKeysFromLookups?: AccountKeysFromLookups, - ) { - this.staticAccountKeys = staticAccountKeys; - this.accountKeysFromLookups = accountKeysFromLookups; - } - - keySegments(): Array> { - const keySegments = [this.staticAccountKeys]; - if (this.accountKeysFromLookups) { - keySegments.push(this.accountKeysFromLookups.writable); - keySegments.push(this.accountKeysFromLookups.readonly); - } - return keySegments; - } - - get(index: number): PublicKey | undefined { - for (const keySegment of this.keySegments()) { - if (index < keySegment.length) { - return keySegment[index]; - } else { - index -= keySegment.length; - } - } - return; - } - - get length(): number { - return this.keySegments().flat().length; - } - - compileInstructions( - instructions: Array, - ): Array { - // Bail early if any account indexes would overflow a u8 - const U8_MAX = 255; - if (this.length > U8_MAX + 1) { - throw new Error('Account index overflow encountered during compilation'); - } - - const keyIndexMap = new Map(); - this.keySegments() - .flat() - .forEach((key, index) => { - keyIndexMap.set(key.toBase58(), index); - }); - - const findKeyIndex = (key: PublicKey) => { - const keyIndex = keyIndexMap.get(key.toBase58()); - if (keyIndex === undefined) - throw new Error( - 'Encountered an unknown instruction account key during compilation', - ); - return keyIndex; - }; - - return instructions.map((instruction): MessageCompiledInstruction => { - return { - programIdIndex: findKeyIndex(instruction.programId), - accountKeyIndexes: instruction.keys.map(meta => - findKeyIndex(meta.pubkey), - ), - data: instruction.data, - }; - }); - } -} diff --git a/packages/library-legacy/src/message/compiled-keys.ts b/packages/library-legacy/src/message/compiled-keys.ts deleted file mode 100644 index a0cf88ea3437..000000000000 --- a/packages/library-legacy/src/message/compiled-keys.ts +++ /dev/null @@ -1,165 +0,0 @@ -import {MessageHeader, MessageAddressTableLookup} from './index'; -import {AccountKeysFromLookups} from './account-keys'; -import {AddressLookupTableAccount} from '../programs'; -import {TransactionInstruction} from '../transaction'; -import assert from '../utils/assert'; -import {PublicKey} from '../publickey'; - -export type CompiledKeyMeta = { - isSigner: boolean; - isWritable: boolean; - isInvoked: boolean; -}; - -type KeyMetaMap = Map; - -export class CompiledKeys { - payer: PublicKey; - keyMetaMap: KeyMetaMap; - - constructor(payer: PublicKey, keyMetaMap: KeyMetaMap) { - this.payer = payer; - this.keyMetaMap = keyMetaMap; - } - - static compile( - instructions: Array, - payer: PublicKey, - ): CompiledKeys { - const keyMetaMap: KeyMetaMap = new Map(); - const getOrInsertDefault = (pubkey: PublicKey): CompiledKeyMeta => { - const address = pubkey.toBase58(); - let keyMeta = keyMetaMap.get(address); - if (keyMeta === undefined) { - keyMeta = { - isSigner: false, - isWritable: false, - isInvoked: false, - }; - keyMetaMap.set(address, keyMeta); - } - return keyMeta; - }; - - const payerKeyMeta = getOrInsertDefault(payer); - payerKeyMeta.isSigner = true; - payerKeyMeta.isWritable = true; - - for (const ix of instructions) { - getOrInsertDefault(ix.programId).isInvoked = true; - for (const accountMeta of ix.keys) { - const keyMeta = getOrInsertDefault(accountMeta.pubkey); - keyMeta.isSigner ||= accountMeta.isSigner; - keyMeta.isWritable ||= accountMeta.isWritable; - } - } - - return new CompiledKeys(payer, keyMetaMap); - } - - getMessageComponents(): [MessageHeader, Array] { - const mapEntries = [...this.keyMetaMap.entries()]; - assert(mapEntries.length <= 256, 'Max static account keys length exceeded'); - - const writableSigners = mapEntries.filter( - ([, meta]) => meta.isSigner && meta.isWritable, - ); - const readonlySigners = mapEntries.filter( - ([, meta]) => meta.isSigner && !meta.isWritable, - ); - const writableNonSigners = mapEntries.filter( - ([, meta]) => !meta.isSigner && meta.isWritable, - ); - const readonlyNonSigners = mapEntries.filter( - ([, meta]) => !meta.isSigner && !meta.isWritable, - ); - - const header: MessageHeader = { - numRequiredSignatures: writableSigners.length + readonlySigners.length, - numReadonlySignedAccounts: readonlySigners.length, - numReadonlyUnsignedAccounts: readonlyNonSigners.length, - }; - - // sanity checks - { - assert( - writableSigners.length > 0, - 'Expected at least one writable signer key', - ); - const [payerAddress] = writableSigners[0]; - assert( - payerAddress === this.payer.toBase58(), - 'Expected first writable signer key to be the fee payer', - ); - } - - const staticAccountKeys = [ - ...writableSigners.map(([address]) => new PublicKey(address)), - ...readonlySigners.map(([address]) => new PublicKey(address)), - ...writableNonSigners.map(([address]) => new PublicKey(address)), - ...readonlyNonSigners.map(([address]) => new PublicKey(address)), - ]; - - return [header, staticAccountKeys]; - } - - extractTableLookup( - lookupTable: AddressLookupTableAccount, - ): [MessageAddressTableLookup, AccountKeysFromLookups] | undefined { - const [writableIndexes, drainedWritableKeys] = - this.drainKeysFoundInLookupTable( - lookupTable.state.addresses, - keyMeta => - !keyMeta.isSigner && !keyMeta.isInvoked && keyMeta.isWritable, - ); - const [readonlyIndexes, drainedReadonlyKeys] = - this.drainKeysFoundInLookupTable( - lookupTable.state.addresses, - keyMeta => - !keyMeta.isSigner && !keyMeta.isInvoked && !keyMeta.isWritable, - ); - - // Don't extract lookup if no keys were found - if (writableIndexes.length === 0 && readonlyIndexes.length === 0) { - return; - } - - return [ - { - accountKey: lookupTable.key, - writableIndexes, - readonlyIndexes, - }, - { - writable: drainedWritableKeys, - readonly: drainedReadonlyKeys, - }, - ]; - } - - /** @internal */ - private drainKeysFoundInLookupTable( - lookupTableEntries: Array, - keyMetaFilter: (keyMeta: CompiledKeyMeta) => boolean, - ): [Array, Array] { - const lookupTableIndexes = new Array(); - const drainedKeys = new Array(); - - for (const [address, keyMeta] of this.keyMetaMap.entries()) { - if (keyMetaFilter(keyMeta)) { - const key = new PublicKey(address); - const lookupTableIndex = lookupTableEntries.findIndex(entry => - entry.equals(key), - ); - if (lookupTableIndex >= 0) { - assert(lookupTableIndex < 256, 'Max lookup table index exceeded'); - lookupTableIndexes.push(lookupTableIndex); - drainedKeys.push(key); - this.keyMetaMap.delete(address); - } - } - } - - return [lookupTableIndexes, drainedKeys]; - } -} diff --git a/packages/library-legacy/src/message/index.ts b/packages/library-legacy/src/message/index.ts deleted file mode 100644 index 294a90b17e25..000000000000 --- a/packages/library-legacy/src/message/index.ts +++ /dev/null @@ -1,47 +0,0 @@ -import {PublicKey} from '../publickey'; - -export * from './account-keys'; -// note: compiled-keys is internal and doesn't need to be exported -export * from './legacy'; -export * from './versioned'; -export * from './v0'; - -/** - * The message header, identifying signed and read-only account - */ -export type MessageHeader = { - /** - * The number of signatures required for this message to be considered valid. The - * signatures must match the first `numRequiredSignatures` of `accountKeys`. - */ - numRequiredSignatures: number; - /** The last `numReadonlySignedAccounts` of the signed keys are read-only accounts */ - numReadonlySignedAccounts: number; - /** The last `numReadonlySignedAccounts` of the unsigned keys are read-only accounts */ - numReadonlyUnsignedAccounts: number; -}; - -/** - * An address table lookup used to load additional accounts - */ -export type MessageAddressTableLookup = { - accountKey: PublicKey; - writableIndexes: Array; - readonlyIndexes: Array; -}; - -/** - * An instruction to execute by a program - * - * @property {number} programIdIndex - * @property {number[]} accountKeyIndexes - * @property {Uint8Array} data - */ -export type MessageCompiledInstruction = { - /** Index into the transaction keys array indicating the program account that executes this instruction */ - programIdIndex: number; - /** Ordered indices into the transaction keys array indicating which accounts to pass to the program */ - accountKeyIndexes: number[]; - /** The program input data */ - data: Uint8Array; -}; diff --git a/packages/library-legacy/src/message/legacy.ts b/packages/library-legacy/src/message/legacy.ts deleted file mode 100644 index 6b8ee132967a..000000000000 --- a/packages/library-legacy/src/message/legacy.ts +++ /dev/null @@ -1,323 +0,0 @@ -import bs58 from 'bs58'; -import {Buffer} from 'buffer'; -import * as BufferLayout from '@solana/buffer-layout'; - -import {PublicKey, PUBLIC_KEY_LENGTH} from '../publickey'; -import type {Blockhash} from '../blockhash'; -import * as Layout from '../layout'; -import {PACKET_DATA_SIZE, VERSION_PREFIX_MASK} from '../transaction/constants'; -import * as shortvec from '../utils/shortvec-encoding'; -import {toBuffer} from '../utils/to-buffer'; -import { - MessageHeader, - MessageAddressTableLookup, - MessageCompiledInstruction, -} from './index'; -import {TransactionInstruction} from '../transaction'; -import {CompiledKeys} from './compiled-keys'; -import {MessageAccountKeys} from './account-keys'; -import {guardedShift, guardedSplice} from '../utils/guarded-array-utils'; - -/** - * An instruction to execute by a program - * - * @property {number} programIdIndex - * @property {number[]} accounts - * @property {string} data - */ -export type CompiledInstruction = { - /** Index into the transaction keys array indicating the program account that executes this instruction */ - programIdIndex: number; - /** Ordered indices into the transaction keys array indicating which accounts to pass to the program */ - accounts: number[]; - /** The program input data encoded as base 58 */ - data: string; -}; - -/** - * Message constructor arguments - */ -export type MessageArgs = { - /** The message header, identifying signed and read-only `accountKeys` */ - header: MessageHeader; - /** All the account keys used by this transaction */ - accountKeys: string[] | PublicKey[]; - /** The hash of a recent ledger block */ - recentBlockhash: Blockhash; - /** Instructions that will be executed in sequence and committed in one atomic transaction if all succeed. */ - instructions: CompiledInstruction[]; -}; - -export type CompileLegacyArgs = { - payerKey: PublicKey; - instructions: Array; - recentBlockhash: Blockhash; -}; - -/** - * List of instructions to be processed atomically - */ -export class Message { - header: MessageHeader; - accountKeys: PublicKey[]; - recentBlockhash: Blockhash; - instructions: CompiledInstruction[]; - - private indexToProgramIds: Map = new Map< - number, - PublicKey - >(); - - constructor(args: MessageArgs) { - this.header = args.header; - this.accountKeys = args.accountKeys.map(account => new PublicKey(account)); - this.recentBlockhash = args.recentBlockhash; - this.instructions = args.instructions; - this.instructions.forEach(ix => - this.indexToProgramIds.set( - ix.programIdIndex, - this.accountKeys[ix.programIdIndex], - ), - ); - } - - get version(): 'legacy' { - return 'legacy'; - } - - get staticAccountKeys(): Array { - return this.accountKeys; - } - - get compiledInstructions(): Array { - return this.instructions.map( - (ix): MessageCompiledInstruction => ({ - programIdIndex: ix.programIdIndex, - accountKeyIndexes: ix.accounts, - data: bs58.decode(ix.data), - }), - ); - } - - get addressTableLookups(): Array { - return []; - } - - getAccountKeys(): MessageAccountKeys { - return new MessageAccountKeys(this.staticAccountKeys); - } - - static compile(args: CompileLegacyArgs): Message { - const compiledKeys = CompiledKeys.compile(args.instructions, args.payerKey); - const [header, staticAccountKeys] = compiledKeys.getMessageComponents(); - const accountKeys = new MessageAccountKeys(staticAccountKeys); - const instructions = accountKeys.compileInstructions(args.instructions).map( - (ix: MessageCompiledInstruction): CompiledInstruction => ({ - programIdIndex: ix.programIdIndex, - accounts: ix.accountKeyIndexes, - data: bs58.encode(ix.data), - }), - ); - return new Message({ - header, - accountKeys: staticAccountKeys, - recentBlockhash: args.recentBlockhash, - instructions, - }); - } - - isAccountSigner(index: number): boolean { - return index < this.header.numRequiredSignatures; - } - - isAccountWritable(index: number): boolean { - const numSignedAccounts = this.header.numRequiredSignatures; - if (index >= this.header.numRequiredSignatures) { - const unsignedAccountIndex = index - numSignedAccounts; - const numUnsignedAccounts = this.accountKeys.length - numSignedAccounts; - const numWritableUnsignedAccounts = - numUnsignedAccounts - this.header.numReadonlyUnsignedAccounts; - return unsignedAccountIndex < numWritableUnsignedAccounts; - } else { - const numWritableSignedAccounts = - numSignedAccounts - this.header.numReadonlySignedAccounts; - return index < numWritableSignedAccounts; - } - } - - isProgramId(index: number): boolean { - return this.indexToProgramIds.has(index); - } - - programIds(): PublicKey[] { - return [...this.indexToProgramIds.values()]; - } - - nonProgramIds(): PublicKey[] { - return this.accountKeys.filter((_, index) => !this.isProgramId(index)); - } - - serialize(): Buffer { - const numKeys = this.accountKeys.length; - - let keyCount: number[] = []; - shortvec.encodeLength(keyCount, numKeys); - - const instructions = this.instructions.map(instruction => { - const {accounts, programIdIndex} = instruction; - const data = Array.from(bs58.decode(instruction.data)); - - let keyIndicesCount: number[] = []; - shortvec.encodeLength(keyIndicesCount, accounts.length); - - let dataCount: number[] = []; - shortvec.encodeLength(dataCount, data.length); - - return { - programIdIndex, - keyIndicesCount: Buffer.from(keyIndicesCount), - keyIndices: accounts, - dataLength: Buffer.from(dataCount), - data, - }; - }); - - let instructionCount: number[] = []; - shortvec.encodeLength(instructionCount, instructions.length); - let instructionBuffer = Buffer.alloc(PACKET_DATA_SIZE); - Buffer.from(instructionCount).copy(instructionBuffer); - let instructionBufferLength = instructionCount.length; - - instructions.forEach(instruction => { - const instructionLayout = BufferLayout.struct< - Readonly<{ - data: number[]; - dataLength: Uint8Array; - keyIndices: number[]; - keyIndicesCount: Uint8Array; - programIdIndex: number; - }> - >([ - BufferLayout.u8('programIdIndex'), - - BufferLayout.blob( - instruction.keyIndicesCount.length, - 'keyIndicesCount', - ), - BufferLayout.seq( - BufferLayout.u8('keyIndex'), - instruction.keyIndices.length, - 'keyIndices', - ), - BufferLayout.blob(instruction.dataLength.length, 'dataLength'), - BufferLayout.seq( - BufferLayout.u8('userdatum'), - instruction.data.length, - 'data', - ), - ]); - const length = instructionLayout.encode( - instruction, - instructionBuffer, - instructionBufferLength, - ); - instructionBufferLength += length; - }); - instructionBuffer = instructionBuffer.slice(0, instructionBufferLength); - - const signDataLayout = BufferLayout.struct< - Readonly<{ - keyCount: Uint8Array; - keys: Uint8Array[]; - numReadonlySignedAccounts: Uint8Array; - numReadonlyUnsignedAccounts: Uint8Array; - numRequiredSignatures: Uint8Array; - recentBlockhash: Uint8Array; - }> - >([ - BufferLayout.blob(1, 'numRequiredSignatures'), - BufferLayout.blob(1, 'numReadonlySignedAccounts'), - BufferLayout.blob(1, 'numReadonlyUnsignedAccounts'), - BufferLayout.blob(keyCount.length, 'keyCount'), - BufferLayout.seq(Layout.publicKey('key'), numKeys, 'keys'), - Layout.publicKey('recentBlockhash'), - ]); - - const transaction = { - numRequiredSignatures: Buffer.from([this.header.numRequiredSignatures]), - numReadonlySignedAccounts: Buffer.from([ - this.header.numReadonlySignedAccounts, - ]), - numReadonlyUnsignedAccounts: Buffer.from([ - this.header.numReadonlyUnsignedAccounts, - ]), - keyCount: Buffer.from(keyCount), - keys: this.accountKeys.map(key => toBuffer(key.toBytes())), - recentBlockhash: bs58.decode(this.recentBlockhash), - }; - - let signData = Buffer.alloc(2048); - const length = signDataLayout.encode(transaction, signData); - instructionBuffer.copy(signData, length); - return signData.slice(0, length + instructionBuffer.length); - } - - /** - * Decode a compiled message into a Message object. - */ - static from(buffer: Buffer | Uint8Array | Array): Message { - // Slice up wire data - let byteArray = [...buffer]; - - const numRequiredSignatures = guardedShift(byteArray); - if ( - numRequiredSignatures !== - (numRequiredSignatures & VERSION_PREFIX_MASK) - ) { - throw new Error( - 'Versioned messages must be deserialized with VersionedMessage.deserialize()', - ); - } - - const numReadonlySignedAccounts = guardedShift(byteArray); - const numReadonlyUnsignedAccounts = guardedShift(byteArray); - - const accountCount = shortvec.decodeLength(byteArray); - let accountKeys = []; - for (let i = 0; i < accountCount; i++) { - const account = guardedSplice(byteArray, 0, PUBLIC_KEY_LENGTH); - accountKeys.push(new PublicKey(Buffer.from(account))); - } - - const recentBlockhash = guardedSplice(byteArray, 0, PUBLIC_KEY_LENGTH); - - const instructionCount = shortvec.decodeLength(byteArray); - let instructions: CompiledInstruction[] = []; - for (let i = 0; i < instructionCount; i++) { - const programIdIndex = guardedShift(byteArray); - const accountCount = shortvec.decodeLength(byteArray); - const accounts = guardedSplice(byteArray, 0, accountCount); - const dataLength = shortvec.decodeLength(byteArray); - const dataSlice = guardedSplice(byteArray, 0, dataLength); - const data = bs58.encode(Buffer.from(dataSlice)); - instructions.push({ - programIdIndex, - accounts, - data, - }); - } - - const messageArgs = { - header: { - numRequiredSignatures, - numReadonlySignedAccounts, - numReadonlyUnsignedAccounts, - }, - recentBlockhash: bs58.encode(Buffer.from(recentBlockhash)), - accountKeys, - instructions, - }; - - return new Message(messageArgs); - } -} diff --git a/packages/library-legacy/src/message/v0.ts b/packages/library-legacy/src/message/v0.ts deleted file mode 100644 index c4263389aee0..000000000000 --- a/packages/library-legacy/src/message/v0.ts +++ /dev/null @@ -1,513 +0,0 @@ -import bs58 from 'bs58'; -import * as BufferLayout from '@solana/buffer-layout'; - -import * as Layout from '../layout'; -import {Blockhash} from '../blockhash'; -import { - MessageHeader, - MessageAddressTableLookup, - MessageCompiledInstruction, -} from './index'; -import {PublicKey, PUBLIC_KEY_LENGTH} from '../publickey'; -import * as shortvec from '../utils/shortvec-encoding'; -import assert from '../utils/assert'; -import {PACKET_DATA_SIZE, VERSION_PREFIX_MASK} from '../transaction/constants'; -import {TransactionInstruction} from '../transaction'; -import {AddressLookupTableAccount} from '../programs'; -import {CompiledKeys} from './compiled-keys'; -import {AccountKeysFromLookups, MessageAccountKeys} from './account-keys'; -import {guardedShift, guardedSplice} from '../utils/guarded-array-utils'; - -/** - * Message constructor arguments - */ -export type MessageV0Args = { - /** The message header, identifying signed and read-only `accountKeys` */ - header: MessageHeader; - /** The static account keys used by this transaction */ - staticAccountKeys: PublicKey[]; - /** The hash of a recent ledger block */ - recentBlockhash: Blockhash; - /** Instructions that will be executed in sequence and committed in one atomic transaction if all succeed. */ - compiledInstructions: MessageCompiledInstruction[]; - /** Instructions that will be executed in sequence and committed in one atomic transaction if all succeed. */ - addressTableLookups: MessageAddressTableLookup[]; -}; - -export type CompileV0Args = { - payerKey: PublicKey; - instructions: Array; - recentBlockhash: Blockhash; - addressLookupTableAccounts?: Array; -}; - -export type GetAccountKeysArgs = - | { - accountKeysFromLookups?: AccountKeysFromLookups | null; - } - | { - addressLookupTableAccounts?: AddressLookupTableAccount[] | null; - }; - -export class MessageV0 { - header: MessageHeader; - staticAccountKeys: Array; - recentBlockhash: Blockhash; - compiledInstructions: Array; - addressTableLookups: Array; - - constructor(args: MessageV0Args) { - this.header = args.header; - this.staticAccountKeys = args.staticAccountKeys; - this.recentBlockhash = args.recentBlockhash; - this.compiledInstructions = args.compiledInstructions; - this.addressTableLookups = args.addressTableLookups; - } - - get version(): 0 { - return 0; - } - - get numAccountKeysFromLookups(): number { - let count = 0; - for (const lookup of this.addressTableLookups) { - count += lookup.readonlyIndexes.length + lookup.writableIndexes.length; - } - return count; - } - - getAccountKeys(args?: GetAccountKeysArgs): MessageAccountKeys { - let accountKeysFromLookups: AccountKeysFromLookups | undefined; - if ( - args && - 'accountKeysFromLookups' in args && - args.accountKeysFromLookups - ) { - if ( - this.numAccountKeysFromLookups != - args.accountKeysFromLookups.writable.length + - args.accountKeysFromLookups.readonly.length - ) { - throw new Error( - 'Failed to get account keys because of a mismatch in the number of account keys from lookups', - ); - } - accountKeysFromLookups = args.accountKeysFromLookups; - } else if ( - args && - 'addressLookupTableAccounts' in args && - args.addressLookupTableAccounts - ) { - accountKeysFromLookups = this.resolveAddressTableLookups( - args.addressLookupTableAccounts, - ); - } else if (this.addressTableLookups.length > 0) { - throw new Error( - 'Failed to get account keys because address table lookups were not resolved', - ); - } - return new MessageAccountKeys( - this.staticAccountKeys, - accountKeysFromLookups, - ); - } - - isAccountSigner(index: number): boolean { - return index < this.header.numRequiredSignatures; - } - - isAccountWritable(index: number): boolean { - const numSignedAccounts = this.header.numRequiredSignatures; - const numStaticAccountKeys = this.staticAccountKeys.length; - if (index >= numStaticAccountKeys) { - const lookupAccountKeysIndex = index - numStaticAccountKeys; - const numWritableLookupAccountKeys = this.addressTableLookups.reduce( - (count, lookup) => count + lookup.writableIndexes.length, - 0, - ); - return lookupAccountKeysIndex < numWritableLookupAccountKeys; - } else if (index >= this.header.numRequiredSignatures) { - const unsignedAccountIndex = index - numSignedAccounts; - const numUnsignedAccounts = numStaticAccountKeys - numSignedAccounts; - const numWritableUnsignedAccounts = - numUnsignedAccounts - this.header.numReadonlyUnsignedAccounts; - return unsignedAccountIndex < numWritableUnsignedAccounts; - } else { - const numWritableSignedAccounts = - numSignedAccounts - this.header.numReadonlySignedAccounts; - return index < numWritableSignedAccounts; - } - } - - resolveAddressTableLookups( - addressLookupTableAccounts: AddressLookupTableAccount[], - ): AccountKeysFromLookups { - const accountKeysFromLookups: AccountKeysFromLookups = { - writable: [], - readonly: [], - }; - - for (const tableLookup of this.addressTableLookups) { - const tableAccount = addressLookupTableAccounts.find(account => - account.key.equals(tableLookup.accountKey), - ); - if (!tableAccount) { - throw new Error( - `Failed to find address lookup table account for table key ${tableLookup.accountKey.toBase58()}`, - ); - } - - for (const index of tableLookup.writableIndexes) { - if (index < tableAccount.state.addresses.length) { - accountKeysFromLookups.writable.push( - tableAccount.state.addresses[index], - ); - } else { - throw new Error( - `Failed to find address for index ${index} in address lookup table ${tableLookup.accountKey.toBase58()}`, - ); - } - } - - for (const index of tableLookup.readonlyIndexes) { - if (index < tableAccount.state.addresses.length) { - accountKeysFromLookups.readonly.push( - tableAccount.state.addresses[index], - ); - } else { - throw new Error( - `Failed to find address for index ${index} in address lookup table ${tableLookup.accountKey.toBase58()}`, - ); - } - } - } - - return accountKeysFromLookups; - } - - static compile(args: CompileV0Args): MessageV0 { - const compiledKeys = CompiledKeys.compile(args.instructions, args.payerKey); - - const addressTableLookups = new Array(); - const accountKeysFromLookups: AccountKeysFromLookups = { - writable: new Array(), - readonly: new Array(), - }; - const lookupTableAccounts = args.addressLookupTableAccounts || []; - for (const lookupTable of lookupTableAccounts) { - const extractResult = compiledKeys.extractTableLookup(lookupTable); - if (extractResult !== undefined) { - const [addressTableLookup, {writable, readonly}] = extractResult; - addressTableLookups.push(addressTableLookup); - accountKeysFromLookups.writable.push(...writable); - accountKeysFromLookups.readonly.push(...readonly); - } - } - - const [header, staticAccountKeys] = compiledKeys.getMessageComponents(); - const accountKeys = new MessageAccountKeys( - staticAccountKeys, - accountKeysFromLookups, - ); - const compiledInstructions = accountKeys.compileInstructions( - args.instructions, - ); - return new MessageV0({ - header, - staticAccountKeys, - recentBlockhash: args.recentBlockhash, - compiledInstructions, - addressTableLookups, - }); - } - - serialize(): Uint8Array { - const encodedStaticAccountKeysLength = Array(); - shortvec.encodeLength( - encodedStaticAccountKeysLength, - this.staticAccountKeys.length, - ); - - const serializedInstructions = this.serializeInstructions(); - const encodedInstructionsLength = Array(); - shortvec.encodeLength( - encodedInstructionsLength, - this.compiledInstructions.length, - ); - - const serializedAddressTableLookups = this.serializeAddressTableLookups(); - const encodedAddressTableLookupsLength = Array(); - shortvec.encodeLength( - encodedAddressTableLookupsLength, - this.addressTableLookups.length, - ); - - const messageLayout = BufferLayout.struct<{ - prefix: number; - header: MessageHeader; - staticAccountKeysLength: Uint8Array; - staticAccountKeys: Array; - recentBlockhash: Uint8Array; - instructionsLength: Uint8Array; - serializedInstructions: Uint8Array; - addressTableLookupsLength: Uint8Array; - serializedAddressTableLookups: Uint8Array; - }>([ - BufferLayout.u8('prefix'), - BufferLayout.struct( - [ - BufferLayout.u8('numRequiredSignatures'), - BufferLayout.u8('numReadonlySignedAccounts'), - BufferLayout.u8('numReadonlyUnsignedAccounts'), - ], - 'header', - ), - BufferLayout.blob( - encodedStaticAccountKeysLength.length, - 'staticAccountKeysLength', - ), - BufferLayout.seq( - Layout.publicKey(), - this.staticAccountKeys.length, - 'staticAccountKeys', - ), - Layout.publicKey('recentBlockhash'), - BufferLayout.blob(encodedInstructionsLength.length, 'instructionsLength'), - BufferLayout.blob( - serializedInstructions.length, - 'serializedInstructions', - ), - BufferLayout.blob( - encodedAddressTableLookupsLength.length, - 'addressTableLookupsLength', - ), - BufferLayout.blob( - serializedAddressTableLookups.length, - 'serializedAddressTableLookups', - ), - ]); - - const serializedMessage = new Uint8Array(PACKET_DATA_SIZE); - const MESSAGE_VERSION_0_PREFIX = 1 << 7; - const serializedMessageLength = messageLayout.encode( - { - prefix: MESSAGE_VERSION_0_PREFIX, - header: this.header, - staticAccountKeysLength: new Uint8Array(encodedStaticAccountKeysLength), - staticAccountKeys: this.staticAccountKeys.map(key => key.toBytes()), - recentBlockhash: bs58.decode(this.recentBlockhash), - instructionsLength: new Uint8Array(encodedInstructionsLength), - serializedInstructions, - addressTableLookupsLength: new Uint8Array( - encodedAddressTableLookupsLength, - ), - serializedAddressTableLookups, - }, - serializedMessage, - ); - return serializedMessage.slice(0, serializedMessageLength); - } - - private serializeInstructions(): Uint8Array { - let serializedLength = 0; - const serializedInstructions = new Uint8Array(PACKET_DATA_SIZE); - for (const instruction of this.compiledInstructions) { - const encodedAccountKeyIndexesLength = Array(); - shortvec.encodeLength( - encodedAccountKeyIndexesLength, - instruction.accountKeyIndexes.length, - ); - - const encodedDataLength = Array(); - shortvec.encodeLength(encodedDataLength, instruction.data.length); - - const instructionLayout = BufferLayout.struct<{ - programIdIndex: number; - encodedAccountKeyIndexesLength: Uint8Array; - accountKeyIndexes: number[]; - encodedDataLength: Uint8Array; - data: Uint8Array; - }>([ - BufferLayout.u8('programIdIndex'), - BufferLayout.blob( - encodedAccountKeyIndexesLength.length, - 'encodedAccountKeyIndexesLength', - ), - BufferLayout.seq( - BufferLayout.u8(), - instruction.accountKeyIndexes.length, - 'accountKeyIndexes', - ), - BufferLayout.blob(encodedDataLength.length, 'encodedDataLength'), - BufferLayout.blob(instruction.data.length, 'data'), - ]); - - serializedLength += instructionLayout.encode( - { - programIdIndex: instruction.programIdIndex, - encodedAccountKeyIndexesLength: new Uint8Array( - encodedAccountKeyIndexesLength, - ), - accountKeyIndexes: instruction.accountKeyIndexes, - encodedDataLength: new Uint8Array(encodedDataLength), - data: instruction.data, - }, - serializedInstructions, - serializedLength, - ); - } - - return serializedInstructions.slice(0, serializedLength); - } - - private serializeAddressTableLookups(): Uint8Array { - let serializedLength = 0; - const serializedAddressTableLookups = new Uint8Array(PACKET_DATA_SIZE); - for (const lookup of this.addressTableLookups) { - const encodedWritableIndexesLength = Array(); - shortvec.encodeLength( - encodedWritableIndexesLength, - lookup.writableIndexes.length, - ); - - const encodedReadonlyIndexesLength = Array(); - shortvec.encodeLength( - encodedReadonlyIndexesLength, - lookup.readonlyIndexes.length, - ); - - const addressTableLookupLayout = BufferLayout.struct<{ - accountKey: Uint8Array; - encodedWritableIndexesLength: Uint8Array; - writableIndexes: number[]; - encodedReadonlyIndexesLength: Uint8Array; - readonlyIndexes: number[]; - }>([ - Layout.publicKey('accountKey'), - BufferLayout.blob( - encodedWritableIndexesLength.length, - 'encodedWritableIndexesLength', - ), - BufferLayout.seq( - BufferLayout.u8(), - lookup.writableIndexes.length, - 'writableIndexes', - ), - BufferLayout.blob( - encodedReadonlyIndexesLength.length, - 'encodedReadonlyIndexesLength', - ), - BufferLayout.seq( - BufferLayout.u8(), - lookup.readonlyIndexes.length, - 'readonlyIndexes', - ), - ]); - - serializedLength += addressTableLookupLayout.encode( - { - accountKey: lookup.accountKey.toBytes(), - encodedWritableIndexesLength: new Uint8Array( - encodedWritableIndexesLength, - ), - writableIndexes: lookup.writableIndexes, - encodedReadonlyIndexesLength: new Uint8Array( - encodedReadonlyIndexesLength, - ), - readonlyIndexes: lookup.readonlyIndexes, - }, - serializedAddressTableLookups, - serializedLength, - ); - } - - return serializedAddressTableLookups.slice(0, serializedLength); - } - - static deserialize(serializedMessage: Uint8Array): MessageV0 { - let byteArray = [...serializedMessage]; - - const prefix = guardedShift(byteArray); - const maskedPrefix = prefix & VERSION_PREFIX_MASK; - assert( - prefix !== maskedPrefix, - `Expected versioned message but received legacy message`, - ); - - const version = maskedPrefix; - assert( - version === 0, - `Expected versioned message with version 0 but found version ${version}`, - ); - - const header: MessageHeader = { - numRequiredSignatures: guardedShift(byteArray), - numReadonlySignedAccounts: guardedShift(byteArray), - numReadonlyUnsignedAccounts: guardedShift(byteArray), - }; - - const staticAccountKeys = []; - const staticAccountKeysLength = shortvec.decodeLength(byteArray); - for (let i = 0; i < staticAccountKeysLength; i++) { - staticAccountKeys.push( - new PublicKey(guardedSplice(byteArray, 0, PUBLIC_KEY_LENGTH)), - ); - } - - const recentBlockhash = bs58.encode( - guardedSplice(byteArray, 0, PUBLIC_KEY_LENGTH), - ); - - const instructionCount = shortvec.decodeLength(byteArray); - const compiledInstructions: MessageCompiledInstruction[] = []; - for (let i = 0; i < instructionCount; i++) { - const programIdIndex = guardedShift(byteArray); - const accountKeyIndexesLength = shortvec.decodeLength(byteArray); - const accountKeyIndexes = guardedSplice( - byteArray, - 0, - accountKeyIndexesLength, - ); - const dataLength = shortvec.decodeLength(byteArray); - const data = new Uint8Array(guardedSplice(byteArray, 0, dataLength)); - compiledInstructions.push({ - programIdIndex, - accountKeyIndexes, - data, - }); - } - - const addressTableLookupsCount = shortvec.decodeLength(byteArray); - const addressTableLookups: MessageAddressTableLookup[] = []; - for (let i = 0; i < addressTableLookupsCount; i++) { - const accountKey = new PublicKey( - guardedSplice(byteArray, 0, PUBLIC_KEY_LENGTH), - ); - const writableIndexesLength = shortvec.decodeLength(byteArray); - const writableIndexes = guardedSplice( - byteArray, - 0, - writableIndexesLength, - ); - const readonlyIndexesLength = shortvec.decodeLength(byteArray); - const readonlyIndexes = guardedSplice( - byteArray, - 0, - readonlyIndexesLength, - ); - addressTableLookups.push({ - accountKey, - writableIndexes, - readonlyIndexes, - }); - } - - return new MessageV0({ - header, - staticAccountKeys, - recentBlockhash, - compiledInstructions, - addressTableLookups, - }); - } -} diff --git a/packages/library-legacy/src/message/versioned.ts b/packages/library-legacy/src/message/versioned.ts deleted file mode 100644 index 92b4d888bdbf..000000000000 --- a/packages/library-legacy/src/message/versioned.ts +++ /dev/null @@ -1,36 +0,0 @@ -import {VERSION_PREFIX_MASK} from '../transaction/constants'; -import {Message} from './legacy'; -import {MessageV0} from './v0'; - -export type VersionedMessage = Message | MessageV0; -// eslint-disable-next-line no-redeclare -export const VersionedMessage = { - deserializeMessageVersion(serializedMessage: Uint8Array): 'legacy' | number { - const prefix = serializedMessage[0]; - const maskedPrefix = prefix & VERSION_PREFIX_MASK; - - // if the highest bit of the prefix is not set, the message is not versioned - if (maskedPrefix === prefix) { - return 'legacy'; - } - - // the lower 7 bits of the prefix indicate the message version - return maskedPrefix; - }, - - deserialize: (serializedMessage: Uint8Array): VersionedMessage => { - const version = - VersionedMessage.deserializeMessageVersion(serializedMessage); - if (version === 'legacy') { - return Message.from(serializedMessage); - } - - if (version === 0) { - return MessageV0.deserialize(serializedMessage); - } else { - throw new Error( - `Transaction message version ${version} deserialization is not supported`, - ); - } - }, -}; diff --git a/packages/library-legacy/src/nonce-account.ts b/packages/library-legacy/src/nonce-account.ts deleted file mode 100644 index a09d506b7556..000000000000 --- a/packages/library-legacy/src/nonce-account.ts +++ /dev/null @@ -1,82 +0,0 @@ -import * as BufferLayout from '@solana/buffer-layout'; -import {Buffer} from 'buffer'; - -import * as Layout from './layout'; -import {PublicKey} from './publickey'; -import type {FeeCalculator} from './fee-calculator'; -import {FeeCalculatorLayout} from './fee-calculator'; -import {toBuffer} from './utils/to-buffer'; - -/** - * See https://github.com/solana-labs/solana/blob/0ea2843ec9cdc517572b8e62c959f41b55cf4453/sdk/src/nonce_state.rs#L29-L32 - * - * @internal - */ -const NonceAccountLayout = BufferLayout.struct< - Readonly<{ - authorizedPubkey: Uint8Array; - feeCalculator: Readonly<{ - lamportsPerSignature: number; - }>; - nonce: Uint8Array; - state: number; - version: number; - }> ->([ - BufferLayout.u32('version'), - BufferLayout.u32('state'), - Layout.publicKey('authorizedPubkey'), - Layout.publicKey('nonce'), - BufferLayout.struct>( - [FeeCalculatorLayout], - 'feeCalculator', - ), -]); - -export const NONCE_ACCOUNT_LENGTH = NonceAccountLayout.span; - -/** - * A durable nonce is a 32 byte value encoded as a base58 string. - */ -export type DurableNonce = string; - -type NonceAccountArgs = { - authorizedPubkey: PublicKey; - nonce: DurableNonce; - feeCalculator: FeeCalculator; -}; - -/** - * NonceAccount class - */ -export class NonceAccount { - authorizedPubkey: PublicKey; - nonce: DurableNonce; - feeCalculator: FeeCalculator; - - /** - * @internal - */ - constructor(args: NonceAccountArgs) { - this.authorizedPubkey = args.authorizedPubkey; - this.nonce = args.nonce; - this.feeCalculator = args.feeCalculator; - } - - /** - * Deserialize NonceAccount from the account data. - * - * @param buffer account data - * @return NonceAccount - */ - static fromAccountData( - buffer: Buffer | Uint8Array | Array, - ): NonceAccount { - const nonceAccount = NonceAccountLayout.decode(toBuffer(buffer), 0); - return new NonceAccount({ - authorizedPubkey: new PublicKey(nonceAccount.authorizedPubkey), - nonce: new PublicKey(nonceAccount.nonce).toString(), - feeCalculator: nonceAccount.feeCalculator, - }); - } -} diff --git a/packages/library-legacy/src/programs/address-lookup-table/index.ts b/packages/library-legacy/src/programs/address-lookup-table/index.ts deleted file mode 100644 index da752ddb4f32..000000000000 --- a/packages/library-legacy/src/programs/address-lookup-table/index.ts +++ /dev/null @@ -1,435 +0,0 @@ -import {toBufferLE} from 'bigint-buffer'; -import * as BufferLayout from '@solana/buffer-layout'; - -import * as Layout from '../../layout'; -import {PublicKey} from '../../publickey'; -import * as bigintLayout from '../../utils/bigint'; -import {SystemProgram} from '../system'; -import {TransactionInstruction} from '../../transaction'; -import {decodeData, encodeData, IInstructionInputData} from '../../instruction'; - -export * from './state'; - -export type CreateLookupTableParams = { - /** Account used to derive and control the new address lookup table. */ - authority: PublicKey; - /** Account that will fund the new address lookup table. */ - payer: PublicKey; - /** A recent slot must be used in the derivation path for each initialized table. */ - recentSlot: bigint | number; -}; - -export type FreezeLookupTableParams = { - /** Address lookup table account to freeze. */ - lookupTable: PublicKey; - /** Account which is the current authority. */ - authority: PublicKey; -}; - -export type ExtendLookupTableParams = { - /** Address lookup table account to extend. */ - lookupTable: PublicKey; - /** Account which is the current authority. */ - authority: PublicKey; - /** Account that will fund the table reallocation. - * Not required if the reallocation has already been funded. */ - payer?: PublicKey; - /** List of Public Keys to be added to the lookup table. */ - addresses: Array; -}; - -export type DeactivateLookupTableParams = { - /** Address lookup table account to deactivate. */ - lookupTable: PublicKey; - /** Account which is the current authority. */ - authority: PublicKey; -}; - -export type CloseLookupTableParams = { - /** Address lookup table account to close. */ - lookupTable: PublicKey; - /** Account which is the current authority. */ - authority: PublicKey; - /** Recipient of closed account lamports. */ - recipient: PublicKey; -}; - -/** - * An enumeration of valid LookupTableInstructionType's - */ -export type LookupTableInstructionType = - | 'CreateLookupTable' - | 'ExtendLookupTable' - | 'CloseLookupTable' - | 'FreezeLookupTable' - | 'DeactivateLookupTable'; - -type LookupTableInstructionInputData = { - CreateLookupTable: IInstructionInputData & - Readonly<{ - recentSlot: bigint; - bumpSeed: number; - }>; - FreezeLookupTable: IInstructionInputData; - ExtendLookupTable: IInstructionInputData & - Readonly<{ - numberOfAddresses: bigint; - addresses: Array; - }>; - DeactivateLookupTable: IInstructionInputData; - CloseLookupTable: IInstructionInputData; -}; - -/** - * An enumeration of valid address lookup table InstructionType's - * @internal - */ -export const LOOKUP_TABLE_INSTRUCTION_LAYOUTS = Object.freeze({ - CreateLookupTable: { - index: 0, - layout: BufferLayout.struct< - LookupTableInstructionInputData['CreateLookupTable'] - >([ - BufferLayout.u32('instruction'), - bigintLayout.u64('recentSlot'), - BufferLayout.u8('bumpSeed'), - ]), - }, - FreezeLookupTable: { - index: 1, - layout: BufferLayout.struct< - LookupTableInstructionInputData['FreezeLookupTable'] - >([BufferLayout.u32('instruction')]), - }, - ExtendLookupTable: { - index: 2, - layout: BufferLayout.struct< - LookupTableInstructionInputData['ExtendLookupTable'] - >([ - BufferLayout.u32('instruction'), - bigintLayout.u64(), - BufferLayout.seq( - Layout.publicKey(), - BufferLayout.offset(BufferLayout.u32(), -8), - 'addresses', - ), - ]), - }, - DeactivateLookupTable: { - index: 3, - layout: BufferLayout.struct< - LookupTableInstructionInputData['DeactivateLookupTable'] - >([BufferLayout.u32('instruction')]), - }, - CloseLookupTable: { - index: 4, - layout: BufferLayout.struct< - LookupTableInstructionInputData['CloseLookupTable'] - >([BufferLayout.u32('instruction')]), - }, -}); - -export class AddressLookupTableInstruction { - /** - * @internal - */ - constructor() {} - - static decodeInstructionType( - instruction: TransactionInstruction, - ): LookupTableInstructionType { - this.checkProgramId(instruction.programId); - - const instructionTypeLayout = BufferLayout.u32('instruction'); - const index = instructionTypeLayout.decode(instruction.data); - - let type: LookupTableInstructionType | undefined; - for (const [layoutType, layout] of Object.entries( - LOOKUP_TABLE_INSTRUCTION_LAYOUTS, - )) { - if ((layout as any).index == index) { - type = layoutType as LookupTableInstructionType; - break; - } - } - if (!type) { - throw new Error( - 'Invalid Instruction. Should be a LookupTable Instruction', - ); - } - return type; - } - - static decodeCreateLookupTable( - instruction: TransactionInstruction, - ): CreateLookupTableParams { - this.checkProgramId(instruction.programId); - this.checkKeysLength(instruction.keys, 4); - - const {recentSlot} = decodeData( - LOOKUP_TABLE_INSTRUCTION_LAYOUTS.CreateLookupTable, - instruction.data, - ); - - return { - authority: instruction.keys[1].pubkey, - payer: instruction.keys[2].pubkey, - recentSlot: Number(recentSlot), - }; - } - - static decodeExtendLookupTable( - instruction: TransactionInstruction, - ): ExtendLookupTableParams { - this.checkProgramId(instruction.programId); - if (instruction.keys.length < 2) { - throw new Error( - `invalid instruction; found ${instruction.keys.length} keys, expected at least 2`, - ); - } - - const {addresses} = decodeData( - LOOKUP_TABLE_INSTRUCTION_LAYOUTS.ExtendLookupTable, - instruction.data, - ); - return { - lookupTable: instruction.keys[0].pubkey, - authority: instruction.keys[1].pubkey, - payer: - instruction.keys.length > 2 ? instruction.keys[2].pubkey : undefined, - addresses: addresses.map(buffer => new PublicKey(buffer)), - }; - } - - static decodeCloseLookupTable( - instruction: TransactionInstruction, - ): CloseLookupTableParams { - this.checkProgramId(instruction.programId); - this.checkKeysLength(instruction.keys, 3); - - return { - lookupTable: instruction.keys[0].pubkey, - authority: instruction.keys[1].pubkey, - recipient: instruction.keys[2].pubkey, - }; - } - - static decodeFreezeLookupTable( - instruction: TransactionInstruction, - ): FreezeLookupTableParams { - this.checkProgramId(instruction.programId); - this.checkKeysLength(instruction.keys, 2); - - return { - lookupTable: instruction.keys[0].pubkey, - authority: instruction.keys[1].pubkey, - }; - } - - static decodeDeactivateLookupTable( - instruction: TransactionInstruction, - ): DeactivateLookupTableParams { - this.checkProgramId(instruction.programId); - this.checkKeysLength(instruction.keys, 2); - - return { - lookupTable: instruction.keys[0].pubkey, - authority: instruction.keys[1].pubkey, - }; - } - - /** - * @internal - */ - static checkProgramId(programId: PublicKey) { - if (!programId.equals(AddressLookupTableProgram.programId)) { - throw new Error( - 'invalid instruction; programId is not AddressLookupTable Program', - ); - } - } - /** - * @internal - */ - static checkKeysLength(keys: Array, expectedLength: number) { - if (keys.length < expectedLength) { - throw new Error( - `invalid instruction; found ${keys.length} keys, expected at least ${expectedLength}`, - ); - } - } -} - -export class AddressLookupTableProgram { - /** - * @internal - */ - constructor() {} - - static programId: PublicKey = new PublicKey( - 'AddressLookupTab1e1111111111111111111111111', - ); - - static createLookupTable(params: CreateLookupTableParams) { - const [lookupTableAddress, bumpSeed] = PublicKey.findProgramAddressSync( - [params.authority.toBuffer(), toBufferLE(BigInt(params.recentSlot), 8)], - this.programId, - ); - - const type = LOOKUP_TABLE_INSTRUCTION_LAYOUTS.CreateLookupTable; - const data = encodeData(type, { - recentSlot: BigInt(params.recentSlot), - bumpSeed: bumpSeed, - }); - - const keys = [ - { - pubkey: lookupTableAddress, - isSigner: false, - isWritable: true, - }, - { - pubkey: params.authority, - isSigner: true, - isWritable: false, - }, - { - pubkey: params.payer, - isSigner: true, - isWritable: true, - }, - { - pubkey: SystemProgram.programId, - isSigner: false, - isWritable: false, - }, - ]; - - return [ - new TransactionInstruction({ - programId: this.programId, - keys: keys, - data: data, - }), - lookupTableAddress, - ] as [TransactionInstruction, PublicKey]; - } - - static freezeLookupTable(params: FreezeLookupTableParams) { - const type = LOOKUP_TABLE_INSTRUCTION_LAYOUTS.FreezeLookupTable; - const data = encodeData(type); - - const keys = [ - { - pubkey: params.lookupTable, - isSigner: false, - isWritable: true, - }, - { - pubkey: params.authority, - isSigner: true, - isWritable: false, - }, - ]; - - return new TransactionInstruction({ - programId: this.programId, - keys: keys, - data: data, - }); - } - - static extendLookupTable(params: ExtendLookupTableParams) { - const type = LOOKUP_TABLE_INSTRUCTION_LAYOUTS.ExtendLookupTable; - const data = encodeData(type, { - addresses: params.addresses.map(addr => addr.toBytes()), - }); - - const keys = [ - { - pubkey: params.lookupTable, - isSigner: false, - isWritable: true, - }, - { - pubkey: params.authority, - isSigner: true, - isWritable: false, - }, - ]; - - if (params.payer) { - keys.push( - { - pubkey: params.payer, - isSigner: true, - isWritable: true, - }, - { - pubkey: SystemProgram.programId, - isSigner: false, - isWritable: false, - }, - ); - } - - return new TransactionInstruction({ - programId: this.programId, - keys: keys, - data: data, - }); - } - - static deactivateLookupTable(params: DeactivateLookupTableParams) { - const type = LOOKUP_TABLE_INSTRUCTION_LAYOUTS.DeactivateLookupTable; - const data = encodeData(type); - - const keys = [ - { - pubkey: params.lookupTable, - isSigner: false, - isWritable: true, - }, - { - pubkey: params.authority, - isSigner: true, - isWritable: false, - }, - ]; - - return new TransactionInstruction({ - programId: this.programId, - keys: keys, - data: data, - }); - } - - static closeLookupTable(params: CloseLookupTableParams) { - const type = LOOKUP_TABLE_INSTRUCTION_LAYOUTS.CloseLookupTable; - const data = encodeData(type); - - const keys = [ - { - pubkey: params.lookupTable, - isSigner: false, - isWritable: true, - }, - { - pubkey: params.authority, - isSigner: true, - isWritable: false, - }, - { - pubkey: params.recipient, - isSigner: false, - isWritable: true, - }, - ]; - - return new TransactionInstruction({ - programId: this.programId, - keys: keys, - data: data, - }); - } -} diff --git a/packages/library-legacy/src/programs/address-lookup-table/state.ts b/packages/library-legacy/src/programs/address-lookup-table/state.ts deleted file mode 100644 index 4764ea2e162b..000000000000 --- a/packages/library-legacy/src/programs/address-lookup-table/state.ts +++ /dev/null @@ -1,84 +0,0 @@ -import * as BufferLayout from '@solana/buffer-layout'; - -import assert from '../../utils/assert'; -import * as Layout from '../../layout'; -import {PublicKey} from '../../publickey'; -import {u64} from '../../utils/bigint'; -import {decodeData} from '../../account-data'; - -export type AddressLookupTableState = { - deactivationSlot: bigint; - lastExtendedSlot: number; - lastExtendedSlotStartIndex: number; - authority?: PublicKey; - addresses: Array; -}; - -export type AddressLookupTableAccountArgs = { - key: PublicKey; - state: AddressLookupTableState; -}; - -/// The serialized size of lookup table metadata -const LOOKUP_TABLE_META_SIZE = 56; - -export class AddressLookupTableAccount { - key: PublicKey; - state: AddressLookupTableState; - - constructor(args: AddressLookupTableAccountArgs) { - this.key = args.key; - this.state = args.state; - } - - isActive(): boolean { - const U64_MAX = BigInt('0xffffffffffffffff'); - return this.state.deactivationSlot === U64_MAX; - } - - static deserialize(accountData: Uint8Array): AddressLookupTableState { - const meta = decodeData(LookupTableMetaLayout, accountData); - - const serializedAddressesLen = accountData.length - LOOKUP_TABLE_META_SIZE; - assert(serializedAddressesLen >= 0, 'lookup table is invalid'); - assert(serializedAddressesLen % 32 === 0, 'lookup table is invalid'); - - const numSerializedAddresses = serializedAddressesLen / 32; - const {addresses} = BufferLayout.struct<{addresses: Array}>([ - BufferLayout.seq(Layout.publicKey(), numSerializedAddresses, 'addresses'), - ]).decode(accountData.slice(LOOKUP_TABLE_META_SIZE)); - - return { - deactivationSlot: meta.deactivationSlot, - lastExtendedSlot: meta.lastExtendedSlot, - lastExtendedSlotStartIndex: meta.lastExtendedStartIndex, - authority: - meta.authority.length !== 0 - ? new PublicKey(meta.authority[0]) - : undefined, - addresses: addresses.map(address => new PublicKey(address)), - }; - } -} - -const LookupTableMetaLayout = { - index: 1, - layout: BufferLayout.struct<{ - typeIndex: number; - deactivationSlot: bigint; - lastExtendedSlot: number; - lastExtendedStartIndex: number; - authority: Array; - }>([ - BufferLayout.u32('typeIndex'), - u64('deactivationSlot'), - BufferLayout.nu64('lastExtendedSlot'), - BufferLayout.u8('lastExtendedStartIndex'), - BufferLayout.u8(), // option - BufferLayout.seq( - Layout.publicKey(), - BufferLayout.offset(BufferLayout.u8(), -1), - 'authority', - ), - ]), -}; diff --git a/packages/library-legacy/src/programs/compute-budget.ts b/packages/library-legacy/src/programs/compute-budget.ts deleted file mode 100644 index 60f935c42210..000000000000 --- a/packages/library-legacy/src/programs/compute-budget.ts +++ /dev/null @@ -1,281 +0,0 @@ -import * as BufferLayout from '@solana/buffer-layout'; - -import { - encodeData, - decodeData, - InstructionType, - IInstructionInputData, -} from '../instruction'; -import {PublicKey} from '../publickey'; -import {TransactionInstruction} from '../transaction'; -import {u64} from '../utils/bigint'; - -/** - * Compute Budget Instruction class - */ -export class ComputeBudgetInstruction { - /** - * @internal - */ - constructor() {} - - /** - * Decode a compute budget instruction and retrieve the instruction type. - */ - static decodeInstructionType( - instruction: TransactionInstruction, - ): ComputeBudgetInstructionType { - this.checkProgramId(instruction.programId); - - const instructionTypeLayout = BufferLayout.u8('instruction'); - const typeIndex = instructionTypeLayout.decode(instruction.data); - - let type: ComputeBudgetInstructionType | undefined; - for (const [ixType, layout] of Object.entries( - COMPUTE_BUDGET_INSTRUCTION_LAYOUTS, - )) { - if (layout.index == typeIndex) { - type = ixType as ComputeBudgetInstructionType; - break; - } - } - - if (!type) { - throw new Error( - 'Instruction type incorrect; not a ComputeBudgetInstruction', - ); - } - - return type; - } - - /** - * Decode request units compute budget instruction and retrieve the instruction params. - */ - static decodeRequestUnits( - instruction: TransactionInstruction, - ): RequestUnitsParams { - this.checkProgramId(instruction.programId); - const {units, additionalFee} = decodeData( - COMPUTE_BUDGET_INSTRUCTION_LAYOUTS.RequestUnits, - instruction.data, - ); - return {units, additionalFee}; - } - - /** - * Decode request heap frame compute budget instruction and retrieve the instruction params. - */ - static decodeRequestHeapFrame( - instruction: TransactionInstruction, - ): RequestHeapFrameParams { - this.checkProgramId(instruction.programId); - const {bytes} = decodeData( - COMPUTE_BUDGET_INSTRUCTION_LAYOUTS.RequestHeapFrame, - instruction.data, - ); - return {bytes}; - } - - /** - * Decode set compute unit limit compute budget instruction and retrieve the instruction params. - */ - static decodeSetComputeUnitLimit( - instruction: TransactionInstruction, - ): SetComputeUnitLimitParams { - this.checkProgramId(instruction.programId); - const {units} = decodeData( - COMPUTE_BUDGET_INSTRUCTION_LAYOUTS.SetComputeUnitLimit, - instruction.data, - ); - return {units}; - } - - /** - * Decode set compute unit price compute budget instruction and retrieve the instruction params. - */ - static decodeSetComputeUnitPrice( - instruction: TransactionInstruction, - ): SetComputeUnitPriceParams { - this.checkProgramId(instruction.programId); - const {microLamports} = decodeData( - COMPUTE_BUDGET_INSTRUCTION_LAYOUTS.SetComputeUnitPrice, - instruction.data, - ); - return {microLamports}; - } - - /** - * @internal - */ - static checkProgramId(programId: PublicKey) { - if (!programId.equals(ComputeBudgetProgram.programId)) { - throw new Error( - 'invalid instruction; programId is not ComputeBudgetProgram', - ); - } - } -} - -/** - * An enumeration of valid ComputeBudgetInstructionType's - */ -export type ComputeBudgetInstructionType = - // FIXME - // It would be preferable for this type to be `keyof ComputeBudgetInstructionInputData` - // but Typedoc does not transpile `keyof` expressions. - // See https://github.com/TypeStrong/typedoc/issues/1894 - | 'RequestUnits' - | 'RequestHeapFrame' - | 'SetComputeUnitLimit' - | 'SetComputeUnitPrice'; - -type ComputeBudgetInstructionInputData = { - RequestUnits: IInstructionInputData & Readonly; - RequestHeapFrame: IInstructionInputData & Readonly; - SetComputeUnitLimit: IInstructionInputData & - Readonly; - SetComputeUnitPrice: IInstructionInputData & - Readonly; -}; - -/** - * Request units instruction params - */ -export interface RequestUnitsParams { - /** Units to request for transaction-wide compute */ - units: number; - /** Prioritization fee lamports */ - additionalFee: number; -} - -/** - * Request heap frame instruction params - */ -export type RequestHeapFrameParams = { - /** Requested transaction-wide program heap size in bytes. Must be multiple of 1024. Applies to each program, including CPIs. */ - bytes: number; -}; - -/** - * Set compute unit limit instruction params - */ -export interface SetComputeUnitLimitParams { - /** Transaction-wide compute unit limit */ - units: number; -} - -/** - * Set compute unit price instruction params - */ -export interface SetComputeUnitPriceParams { - /** Transaction compute unit price used for prioritization fees */ - microLamports: number | bigint; -} - -/** - * An enumeration of valid ComputeBudget InstructionType's - * @internal - */ -export const COMPUTE_BUDGET_INSTRUCTION_LAYOUTS = Object.freeze<{ - [Instruction in ComputeBudgetInstructionType]: InstructionType< - ComputeBudgetInstructionInputData[Instruction] - >; -}>({ - RequestUnits: { - index: 0, - layout: BufferLayout.struct< - ComputeBudgetInstructionInputData['RequestUnits'] - >([ - BufferLayout.u8('instruction'), - BufferLayout.u32('units'), - BufferLayout.u32('additionalFee'), - ]), - }, - RequestHeapFrame: { - index: 1, - layout: BufferLayout.struct< - ComputeBudgetInstructionInputData['RequestHeapFrame'] - >([BufferLayout.u8('instruction'), BufferLayout.u32('bytes')]), - }, - SetComputeUnitLimit: { - index: 2, - layout: BufferLayout.struct< - ComputeBudgetInstructionInputData['SetComputeUnitLimit'] - >([BufferLayout.u8('instruction'), BufferLayout.u32('units')]), - }, - SetComputeUnitPrice: { - index: 3, - layout: BufferLayout.struct< - ComputeBudgetInstructionInputData['SetComputeUnitPrice'] - >([BufferLayout.u8('instruction'), u64('microLamports')]), - }, -}); - -/** - * Factory class for transaction instructions to interact with the Compute Budget program - */ -export class ComputeBudgetProgram { - /** - * @internal - */ - constructor() {} - - /** - * Public key that identifies the Compute Budget program - */ - static programId: PublicKey = new PublicKey( - 'ComputeBudget111111111111111111111111111111', - ); - - /** - * @deprecated Instead, call {@link setComputeUnitLimit} and/or {@link setComputeUnitPrice} - */ - static requestUnits(params: RequestUnitsParams): TransactionInstruction { - const type = COMPUTE_BUDGET_INSTRUCTION_LAYOUTS.RequestUnits; - const data = encodeData(type, params); - return new TransactionInstruction({ - keys: [], - programId: this.programId, - data, - }); - } - - static requestHeapFrame( - params: RequestHeapFrameParams, - ): TransactionInstruction { - const type = COMPUTE_BUDGET_INSTRUCTION_LAYOUTS.RequestHeapFrame; - const data = encodeData(type, params); - return new TransactionInstruction({ - keys: [], - programId: this.programId, - data, - }); - } - - static setComputeUnitLimit( - params: SetComputeUnitLimitParams, - ): TransactionInstruction { - const type = COMPUTE_BUDGET_INSTRUCTION_LAYOUTS.SetComputeUnitLimit; - const data = encodeData(type, params); - return new TransactionInstruction({ - keys: [], - programId: this.programId, - data, - }); - } - - static setComputeUnitPrice( - params: SetComputeUnitPriceParams, - ): TransactionInstruction { - const type = COMPUTE_BUDGET_INSTRUCTION_LAYOUTS.SetComputeUnitPrice; - const data = encodeData(type, { - microLamports: BigInt(params.microLamports), - }); - return new TransactionInstruction({ - keys: [], - programId: this.programId, - data, - }); - } -} diff --git a/packages/library-legacy/src/programs/ed25519.ts b/packages/library-legacy/src/programs/ed25519.ts deleted file mode 100644 index 9d75dc0211eb..000000000000 --- a/packages/library-legacy/src/programs/ed25519.ts +++ /dev/null @@ -1,157 +0,0 @@ -import {Buffer} from 'buffer'; -import * as BufferLayout from '@solana/buffer-layout'; - -import {Keypair} from '../keypair'; -import {PublicKey} from '../publickey'; -import {TransactionInstruction} from '../transaction'; -import assert from '../utils/assert'; -import {sign} from '../utils/ed25519'; - -const PRIVATE_KEY_BYTES = 64; -const PUBLIC_KEY_BYTES = 32; -const SIGNATURE_BYTES = 64; - -/** - * Params for creating an ed25519 instruction using a public key - */ -export type CreateEd25519InstructionWithPublicKeyParams = { - publicKey: Uint8Array; - message: Uint8Array; - signature: Uint8Array; - instructionIndex?: number; -}; - -/** - * Params for creating an ed25519 instruction using a private key - */ -export type CreateEd25519InstructionWithPrivateKeyParams = { - privateKey: Uint8Array; - message: Uint8Array; - instructionIndex?: number; -}; - -const ED25519_INSTRUCTION_LAYOUT = BufferLayout.struct< - Readonly<{ - messageDataOffset: number; - messageDataSize: number; - messageInstructionIndex: number; - numSignatures: number; - padding: number; - publicKeyInstructionIndex: number; - publicKeyOffset: number; - signatureInstructionIndex: number; - signatureOffset: number; - }> ->([ - BufferLayout.u8('numSignatures'), - BufferLayout.u8('padding'), - BufferLayout.u16('signatureOffset'), - BufferLayout.u16('signatureInstructionIndex'), - BufferLayout.u16('publicKeyOffset'), - BufferLayout.u16('publicKeyInstructionIndex'), - BufferLayout.u16('messageDataOffset'), - BufferLayout.u16('messageDataSize'), - BufferLayout.u16('messageInstructionIndex'), -]); - -export class Ed25519Program { - /** - * @internal - */ - constructor() {} - - /** - * Public key that identifies the ed25519 program - */ - static programId: PublicKey = new PublicKey( - 'Ed25519SigVerify111111111111111111111111111', - ); - - /** - * Create an ed25519 instruction with a public key and signature. The - * public key must be a buffer that is 32 bytes long, and the signature - * must be a buffer of 64 bytes. - */ - static createInstructionWithPublicKey( - params: CreateEd25519InstructionWithPublicKeyParams, - ): TransactionInstruction { - const {publicKey, message, signature, instructionIndex} = params; - - assert( - publicKey.length === PUBLIC_KEY_BYTES, - `Public Key must be ${PUBLIC_KEY_BYTES} bytes but received ${publicKey.length} bytes`, - ); - - assert( - signature.length === SIGNATURE_BYTES, - `Signature must be ${SIGNATURE_BYTES} bytes but received ${signature.length} bytes`, - ); - - const publicKeyOffset = ED25519_INSTRUCTION_LAYOUT.span; - const signatureOffset = publicKeyOffset + publicKey.length; - const messageDataOffset = signatureOffset + signature.length; - const numSignatures = 1; - - const instructionData = Buffer.alloc(messageDataOffset + message.length); - - const index = - instructionIndex == null - ? 0xffff // An index of `u16::MAX` makes it default to the current instruction. - : instructionIndex; - - ED25519_INSTRUCTION_LAYOUT.encode( - { - numSignatures, - padding: 0, - signatureOffset, - signatureInstructionIndex: index, - publicKeyOffset, - publicKeyInstructionIndex: index, - messageDataOffset, - messageDataSize: message.length, - messageInstructionIndex: index, - }, - instructionData, - ); - - instructionData.fill(publicKey, publicKeyOffset); - instructionData.fill(signature, signatureOffset); - instructionData.fill(message, messageDataOffset); - - return new TransactionInstruction({ - keys: [], - programId: Ed25519Program.programId, - data: instructionData, - }); - } - - /** - * Create an ed25519 instruction with a private key. The private key - * must be a buffer that is 64 bytes long. - */ - static createInstructionWithPrivateKey( - params: CreateEd25519InstructionWithPrivateKeyParams, - ): TransactionInstruction { - const {privateKey, message, instructionIndex} = params; - - assert( - privateKey.length === PRIVATE_KEY_BYTES, - `Private key must be ${PRIVATE_KEY_BYTES} bytes but received ${privateKey.length} bytes`, - ); - - try { - const keypair = Keypair.fromSecretKey(privateKey); - const publicKey = keypair.publicKey.toBytes(); - const signature = sign(message, keypair.secretKey); - - return this.createInstructionWithPublicKey({ - publicKey, - message, - signature, - instructionIndex, - }); - } catch (error) { - throw new Error(`Error creating instruction; ${error}`); - } - } -} diff --git a/packages/library-legacy/src/programs/index.ts b/packages/library-legacy/src/programs/index.ts deleted file mode 100644 index f2dc21fcb21c..000000000000 --- a/packages/library-legacy/src/programs/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -export * from './address-lookup-table'; -export * from './compute-budget'; -export * from './ed25519'; -export * from './secp256k1'; -export * from './stake'; -export * from './system'; -export * from './vote'; diff --git a/packages/library-legacy/src/programs/secp256k1.ts b/packages/library-legacy/src/programs/secp256k1.ts deleted file mode 100644 index 7248798252d6..000000000000 --- a/packages/library-legacy/src/programs/secp256k1.ts +++ /dev/null @@ -1,228 +0,0 @@ -import {Buffer} from 'buffer'; -import * as BufferLayout from '@solana/buffer-layout'; -import {keccak_256} from '@noble/hashes/sha3'; - -import {PublicKey} from '../publickey'; -import {TransactionInstruction} from '../transaction'; -import assert from '../utils/assert'; -import {publicKeyCreate, ecdsaSign} from '../utils/secp256k1'; -import {toBuffer} from '../utils/to-buffer'; - -const PRIVATE_KEY_BYTES = 32; -const ETHEREUM_ADDRESS_BYTES = 20; -const PUBLIC_KEY_BYTES = 64; -const SIGNATURE_OFFSETS_SERIALIZED_SIZE = 11; - -/** - * Params for creating an secp256k1 instruction using a public key - */ -export type CreateSecp256k1InstructionWithPublicKeyParams = { - publicKey: Buffer | Uint8Array | Array; - message: Buffer | Uint8Array | Array; - signature: Buffer | Uint8Array | Array; - recoveryId: number; - instructionIndex?: number; -}; - -/** - * Params for creating an secp256k1 instruction using an Ethereum address - */ -export type CreateSecp256k1InstructionWithEthAddressParams = { - ethAddress: Buffer | Uint8Array | Array | string; - message: Buffer | Uint8Array | Array; - signature: Buffer | Uint8Array | Array; - recoveryId: number; - instructionIndex?: number; -}; - -/** - * Params for creating an secp256k1 instruction using a private key - */ -export type CreateSecp256k1InstructionWithPrivateKeyParams = { - privateKey: Buffer | Uint8Array | Array; - message: Buffer | Uint8Array | Array; - instructionIndex?: number; -}; - -const SECP256K1_INSTRUCTION_LAYOUT = BufferLayout.struct< - Readonly<{ - ethAddress: Uint8Array; - ethAddressInstructionIndex: number; - ethAddressOffset: number; - messageDataOffset: number; - messageDataSize: number; - messageInstructionIndex: number; - numSignatures: number; - recoveryId: number; - signature: Uint8Array; - signatureInstructionIndex: number; - signatureOffset: number; - }> ->([ - BufferLayout.u8('numSignatures'), - BufferLayout.u16('signatureOffset'), - BufferLayout.u8('signatureInstructionIndex'), - BufferLayout.u16('ethAddressOffset'), - BufferLayout.u8('ethAddressInstructionIndex'), - BufferLayout.u16('messageDataOffset'), - BufferLayout.u16('messageDataSize'), - BufferLayout.u8('messageInstructionIndex'), - BufferLayout.blob(20, 'ethAddress'), - BufferLayout.blob(64, 'signature'), - BufferLayout.u8('recoveryId'), -]); - -export class Secp256k1Program { - /** - * @internal - */ - constructor() {} - - /** - * Public key that identifies the secp256k1 program - */ - static programId: PublicKey = new PublicKey( - 'KeccakSecp256k11111111111111111111111111111', - ); - - /** - * Construct an Ethereum address from a secp256k1 public key buffer. - * @param {Buffer} publicKey a 64 byte secp256k1 public key buffer - */ - static publicKeyToEthAddress( - publicKey: Buffer | Uint8Array | Array, - ): Buffer { - assert( - publicKey.length === PUBLIC_KEY_BYTES, - `Public key must be ${PUBLIC_KEY_BYTES} bytes but received ${publicKey.length} bytes`, - ); - - try { - return Buffer.from(keccak_256(toBuffer(publicKey))).slice( - -ETHEREUM_ADDRESS_BYTES, - ); - } catch (error) { - throw new Error(`Error constructing Ethereum address: ${error}`); - } - } - - /** - * Create an secp256k1 instruction with a public key. The public key - * must be a buffer that is 64 bytes long. - */ - static createInstructionWithPublicKey( - params: CreateSecp256k1InstructionWithPublicKeyParams, - ): TransactionInstruction { - const {publicKey, message, signature, recoveryId, instructionIndex} = - params; - return Secp256k1Program.createInstructionWithEthAddress({ - ethAddress: Secp256k1Program.publicKeyToEthAddress(publicKey), - message, - signature, - recoveryId, - instructionIndex, - }); - } - - /** - * Create an secp256k1 instruction with an Ethereum address. The address - * must be a hex string or a buffer that is 20 bytes long. - */ - static createInstructionWithEthAddress( - params: CreateSecp256k1InstructionWithEthAddressParams, - ): TransactionInstruction { - const { - ethAddress: rawAddress, - message, - signature, - recoveryId, - instructionIndex = 0, - } = params; - - let ethAddress; - if (typeof rawAddress === 'string') { - if (rawAddress.startsWith('0x')) { - ethAddress = Buffer.from(rawAddress.substr(2), 'hex'); - } else { - ethAddress = Buffer.from(rawAddress, 'hex'); - } - } else { - ethAddress = rawAddress; - } - - assert( - ethAddress.length === ETHEREUM_ADDRESS_BYTES, - `Address must be ${ETHEREUM_ADDRESS_BYTES} bytes but received ${ethAddress.length} bytes`, - ); - - const dataStart = 1 + SIGNATURE_OFFSETS_SERIALIZED_SIZE; - const ethAddressOffset = dataStart; - const signatureOffset = dataStart + ethAddress.length; - const messageDataOffset = signatureOffset + signature.length + 1; - const numSignatures = 1; - - const instructionData = Buffer.alloc( - SECP256K1_INSTRUCTION_LAYOUT.span + message.length, - ); - - SECP256K1_INSTRUCTION_LAYOUT.encode( - { - numSignatures, - signatureOffset, - signatureInstructionIndex: instructionIndex, - ethAddressOffset, - ethAddressInstructionIndex: instructionIndex, - messageDataOffset, - messageDataSize: message.length, - messageInstructionIndex: instructionIndex, - signature: toBuffer(signature), - ethAddress: toBuffer(ethAddress), - recoveryId, - }, - instructionData, - ); - - instructionData.fill(toBuffer(message), SECP256K1_INSTRUCTION_LAYOUT.span); - - return new TransactionInstruction({ - keys: [], - programId: Secp256k1Program.programId, - data: instructionData, - }); - } - - /** - * Create an secp256k1 instruction with a private key. The private key - * must be a buffer that is 32 bytes long. - */ - static createInstructionWithPrivateKey( - params: CreateSecp256k1InstructionWithPrivateKeyParams, - ): TransactionInstruction { - const {privateKey: pkey, message, instructionIndex} = params; - - assert( - pkey.length === PRIVATE_KEY_BYTES, - `Private key must be ${PRIVATE_KEY_BYTES} bytes but received ${pkey.length} bytes`, - ); - - try { - const privateKey = toBuffer(pkey); - const publicKey = publicKeyCreate( - privateKey, - false /* isCompressed */, - ).slice(1); // throw away leading byte - const messageHash = Buffer.from(keccak_256(toBuffer(message))); - const [signature, recoveryId] = ecdsaSign(messageHash, privateKey); - - return this.createInstructionWithPublicKey({ - publicKey, - message, - signature, - recoveryId, - instructionIndex, - }); - } catch (error) { - throw new Error(`Error creating instruction; ${error}`); - } - } -} diff --git a/packages/library-legacy/src/programs/stake.ts b/packages/library-legacy/src/programs/stake.ts deleted file mode 100644 index ca27e2be3b46..000000000000 --- a/packages/library-legacy/src/programs/stake.ts +++ /dev/null @@ -1,952 +0,0 @@ -import * as BufferLayout from '@solana/buffer-layout'; - -import { - encodeData, - decodeData, - InstructionType, - IInstructionInputData, -} from '../instruction'; -import * as Layout from '../layout'; -import {PublicKey} from '../publickey'; -import {SystemProgram} from './system'; -import { - SYSVAR_CLOCK_PUBKEY, - SYSVAR_RENT_PUBKEY, - SYSVAR_STAKE_HISTORY_PUBKEY, -} from '../sysvar'; -import {Transaction, TransactionInstruction} from '../transaction'; -import {toBuffer} from '../utils/to-buffer'; - -/** - * Address of the stake config account which configures the rate - * of stake warmup and cooldown as well as the slashing penalty. - */ -export const STAKE_CONFIG_ID = new PublicKey( - 'StakeConfig11111111111111111111111111111111', -); - -/** - * Stake account authority info - */ -export class Authorized { - /** stake authority */ - staker: PublicKey; - /** withdraw authority */ - withdrawer: PublicKey; - - /** - * Create a new Authorized object - * @param staker the stake authority - * @param withdrawer the withdraw authority - */ - constructor(staker: PublicKey, withdrawer: PublicKey) { - this.staker = staker; - this.withdrawer = withdrawer; - } -} - -type AuthorizedRaw = Readonly<{ - staker: Uint8Array; - withdrawer: Uint8Array; -}>; - -/** - * Stake account lockup info - */ -export class Lockup { - /** Unix timestamp of lockup expiration */ - unixTimestamp: number; - /** Epoch of lockup expiration */ - epoch: number; - /** Lockup custodian authority */ - custodian: PublicKey; - - /** - * Create a new Lockup object - */ - constructor(unixTimestamp: number, epoch: number, custodian: PublicKey) { - this.unixTimestamp = unixTimestamp; - this.epoch = epoch; - this.custodian = custodian; - } - - /** - * Default, inactive Lockup value - */ - static default: Lockup = new Lockup(0, 0, PublicKey.default); -} - -type LockupRaw = Readonly<{ - custodian: Uint8Array; - epoch: number; - unixTimestamp: number; -}>; - -/** - * Create stake account transaction params - */ -export type CreateStakeAccountParams = { - /** Address of the account which will fund creation */ - fromPubkey: PublicKey; - /** Address of the new stake account */ - stakePubkey: PublicKey; - /** Authorities of the new stake account */ - authorized: Authorized; - /** Lockup of the new stake account */ - lockup?: Lockup; - /** Funding amount */ - lamports: number; -}; - -/** - * Create stake account with seed transaction params - */ -export type CreateStakeAccountWithSeedParams = { - fromPubkey: PublicKey; - stakePubkey: PublicKey; - basePubkey: PublicKey; - seed: string; - authorized: Authorized; - lockup?: Lockup; - lamports: number; -}; - -/** - * Initialize stake instruction params - */ -export type InitializeStakeParams = { - stakePubkey: PublicKey; - authorized: Authorized; - lockup?: Lockup; -}; - -/** - * Delegate stake instruction params - */ -export type DelegateStakeParams = { - stakePubkey: PublicKey; - authorizedPubkey: PublicKey; - votePubkey: PublicKey; -}; - -/** - * Authorize stake instruction params - */ -export type AuthorizeStakeParams = { - stakePubkey: PublicKey; - authorizedPubkey: PublicKey; - newAuthorizedPubkey: PublicKey; - stakeAuthorizationType: StakeAuthorizationType; - custodianPubkey?: PublicKey; -}; - -/** - * Authorize stake instruction params using a derived key - */ -export type AuthorizeWithSeedStakeParams = { - stakePubkey: PublicKey; - authorityBase: PublicKey; - authoritySeed: string; - authorityOwner: PublicKey; - newAuthorizedPubkey: PublicKey; - stakeAuthorizationType: StakeAuthorizationType; - custodianPubkey?: PublicKey; -}; - -/** - * Split stake instruction params - */ -export type SplitStakeParams = { - stakePubkey: PublicKey; - authorizedPubkey: PublicKey; - splitStakePubkey: PublicKey; - lamports: number; -}; - -/** - * Split with seed transaction params - */ -export type SplitStakeWithSeedParams = { - stakePubkey: PublicKey; - authorizedPubkey: PublicKey; - splitStakePubkey: PublicKey; - basePubkey: PublicKey; - seed: string; - lamports: number; -}; - -/** - * Withdraw stake instruction params - */ -export type WithdrawStakeParams = { - stakePubkey: PublicKey; - authorizedPubkey: PublicKey; - toPubkey: PublicKey; - lamports: number; - custodianPubkey?: PublicKey; -}; - -/** - * Deactivate stake instruction params - */ -export type DeactivateStakeParams = { - stakePubkey: PublicKey; - authorizedPubkey: PublicKey; -}; - -/** - * Merge stake instruction params - */ -export type MergeStakeParams = { - stakePubkey: PublicKey; - sourceStakePubKey: PublicKey; - authorizedPubkey: PublicKey; -}; - -/** - * Stake Instruction class - */ -export class StakeInstruction { - /** - * @internal - */ - constructor() {} - - /** - * Decode a stake instruction and retrieve the instruction type. - */ - static decodeInstructionType( - instruction: TransactionInstruction, - ): StakeInstructionType { - this.checkProgramId(instruction.programId); - - const instructionTypeLayout = BufferLayout.u32('instruction'); - const typeIndex = instructionTypeLayout.decode(instruction.data); - - let type: StakeInstructionType | undefined; - for (const [ixType, layout] of Object.entries(STAKE_INSTRUCTION_LAYOUTS)) { - if (layout.index == typeIndex) { - type = ixType as StakeInstructionType; - break; - } - } - - if (!type) { - throw new Error('Instruction type incorrect; not a StakeInstruction'); - } - - return type; - } - - /** - * Decode a initialize stake instruction and retrieve the instruction params. - */ - static decodeInitialize( - instruction: TransactionInstruction, - ): InitializeStakeParams { - this.checkProgramId(instruction.programId); - this.checkKeyLength(instruction.keys, 2); - - const {authorized, lockup} = decodeData( - STAKE_INSTRUCTION_LAYOUTS.Initialize, - instruction.data, - ); - - return { - stakePubkey: instruction.keys[0].pubkey, - authorized: new Authorized( - new PublicKey(authorized.staker), - new PublicKey(authorized.withdrawer), - ), - lockup: new Lockup( - lockup.unixTimestamp, - lockup.epoch, - new PublicKey(lockup.custodian), - ), - }; - } - - /** - * Decode a delegate stake instruction and retrieve the instruction params. - */ - static decodeDelegate( - instruction: TransactionInstruction, - ): DelegateStakeParams { - this.checkProgramId(instruction.programId); - this.checkKeyLength(instruction.keys, 6); - decodeData(STAKE_INSTRUCTION_LAYOUTS.Delegate, instruction.data); - - return { - stakePubkey: instruction.keys[0].pubkey, - votePubkey: instruction.keys[1].pubkey, - authorizedPubkey: instruction.keys[5].pubkey, - }; - } - - /** - * Decode an authorize stake instruction and retrieve the instruction params. - */ - static decodeAuthorize( - instruction: TransactionInstruction, - ): AuthorizeStakeParams { - this.checkProgramId(instruction.programId); - this.checkKeyLength(instruction.keys, 3); - const {newAuthorized, stakeAuthorizationType} = decodeData( - STAKE_INSTRUCTION_LAYOUTS.Authorize, - instruction.data, - ); - - const o: AuthorizeStakeParams = { - stakePubkey: instruction.keys[0].pubkey, - authorizedPubkey: instruction.keys[2].pubkey, - newAuthorizedPubkey: new PublicKey(newAuthorized), - stakeAuthorizationType: { - index: stakeAuthorizationType, - }, - }; - if (instruction.keys.length > 3) { - o.custodianPubkey = instruction.keys[3].pubkey; - } - return o; - } - - /** - * Decode an authorize-with-seed stake instruction and retrieve the instruction params. - */ - static decodeAuthorizeWithSeed( - instruction: TransactionInstruction, - ): AuthorizeWithSeedStakeParams { - this.checkProgramId(instruction.programId); - this.checkKeyLength(instruction.keys, 2); - - const { - newAuthorized, - stakeAuthorizationType, - authoritySeed, - authorityOwner, - } = decodeData( - STAKE_INSTRUCTION_LAYOUTS.AuthorizeWithSeed, - instruction.data, - ); - - const o: AuthorizeWithSeedStakeParams = { - stakePubkey: instruction.keys[0].pubkey, - authorityBase: instruction.keys[1].pubkey, - authoritySeed: authoritySeed, - authorityOwner: new PublicKey(authorityOwner), - newAuthorizedPubkey: new PublicKey(newAuthorized), - stakeAuthorizationType: { - index: stakeAuthorizationType, - }, - }; - if (instruction.keys.length > 3) { - o.custodianPubkey = instruction.keys[3].pubkey; - } - return o; - } - - /** - * Decode a split stake instruction and retrieve the instruction params. - */ - static decodeSplit(instruction: TransactionInstruction): SplitStakeParams { - this.checkProgramId(instruction.programId); - this.checkKeyLength(instruction.keys, 3); - const {lamports} = decodeData( - STAKE_INSTRUCTION_LAYOUTS.Split, - instruction.data, - ); - - return { - stakePubkey: instruction.keys[0].pubkey, - splitStakePubkey: instruction.keys[1].pubkey, - authorizedPubkey: instruction.keys[2].pubkey, - lamports, - }; - } - - /** - * Decode a merge stake instruction and retrieve the instruction params. - */ - static decodeMerge(instruction: TransactionInstruction): MergeStakeParams { - this.checkProgramId(instruction.programId); - this.checkKeyLength(instruction.keys, 3); - decodeData(STAKE_INSTRUCTION_LAYOUTS.Merge, instruction.data); - - return { - stakePubkey: instruction.keys[0].pubkey, - sourceStakePubKey: instruction.keys[1].pubkey, - authorizedPubkey: instruction.keys[4].pubkey, - }; - } - - /** - * Decode a withdraw stake instruction and retrieve the instruction params. - */ - static decodeWithdraw( - instruction: TransactionInstruction, - ): WithdrawStakeParams { - this.checkProgramId(instruction.programId); - this.checkKeyLength(instruction.keys, 5); - const {lamports} = decodeData( - STAKE_INSTRUCTION_LAYOUTS.Withdraw, - instruction.data, - ); - - const o: WithdrawStakeParams = { - stakePubkey: instruction.keys[0].pubkey, - toPubkey: instruction.keys[1].pubkey, - authorizedPubkey: instruction.keys[4].pubkey, - lamports, - }; - if (instruction.keys.length > 5) { - o.custodianPubkey = instruction.keys[5].pubkey; - } - return o; - } - - /** - * Decode a deactivate stake instruction and retrieve the instruction params. - */ - static decodeDeactivate( - instruction: TransactionInstruction, - ): DeactivateStakeParams { - this.checkProgramId(instruction.programId); - this.checkKeyLength(instruction.keys, 3); - decodeData(STAKE_INSTRUCTION_LAYOUTS.Deactivate, instruction.data); - - return { - stakePubkey: instruction.keys[0].pubkey, - authorizedPubkey: instruction.keys[2].pubkey, - }; - } - - /** - * @internal - */ - static checkProgramId(programId: PublicKey) { - if (!programId.equals(StakeProgram.programId)) { - throw new Error('invalid instruction; programId is not StakeProgram'); - } - } - - /** - * @internal - */ - static checkKeyLength(keys: Array, expectedLength: number) { - if (keys.length < expectedLength) { - throw new Error( - `invalid instruction; found ${keys.length} keys, expected at least ${expectedLength}`, - ); - } - } -} - -/** - * An enumeration of valid StakeInstructionType's - */ -export type StakeInstructionType = - // FIXME - // It would be preferable for this type to be `keyof StakeInstructionInputData` - // but Typedoc does not transpile `keyof` expressions. - // See https://github.com/TypeStrong/typedoc/issues/1894 - | 'Authorize' - | 'AuthorizeWithSeed' - | 'Deactivate' - | 'Delegate' - | 'Initialize' - | 'Merge' - | 'Split' - | 'Withdraw'; - -type StakeInstructionInputData = { - Authorize: IInstructionInputData & - Readonly<{ - newAuthorized: Uint8Array; - stakeAuthorizationType: number; - }>; - AuthorizeWithSeed: IInstructionInputData & - Readonly<{ - authorityOwner: Uint8Array; - authoritySeed: string; - instruction: number; - newAuthorized: Uint8Array; - stakeAuthorizationType: number; - }>; - Deactivate: IInstructionInputData; - Delegate: IInstructionInputData; - Initialize: IInstructionInputData & - Readonly<{ - authorized: AuthorizedRaw; - lockup: LockupRaw; - }>; - Merge: IInstructionInputData; - Split: IInstructionInputData & - Readonly<{ - lamports: number; - }>; - Withdraw: IInstructionInputData & - Readonly<{ - lamports: number; - }>; -}; - -/** - * An enumeration of valid stake InstructionType's - * @internal - */ -export const STAKE_INSTRUCTION_LAYOUTS = Object.freeze<{ - [Instruction in StakeInstructionType]: InstructionType< - StakeInstructionInputData[Instruction] - >; -}>({ - Initialize: { - index: 0, - layout: BufferLayout.struct([ - BufferLayout.u32('instruction'), - Layout.authorized(), - Layout.lockup(), - ]), - }, - Authorize: { - index: 1, - layout: BufferLayout.struct([ - BufferLayout.u32('instruction'), - Layout.publicKey('newAuthorized'), - BufferLayout.u32('stakeAuthorizationType'), - ]), - }, - Delegate: { - index: 2, - layout: BufferLayout.struct([ - BufferLayout.u32('instruction'), - ]), - }, - Split: { - index: 3, - layout: BufferLayout.struct([ - BufferLayout.u32('instruction'), - BufferLayout.ns64('lamports'), - ]), - }, - Withdraw: { - index: 4, - layout: BufferLayout.struct([ - BufferLayout.u32('instruction'), - BufferLayout.ns64('lamports'), - ]), - }, - Deactivate: { - index: 5, - layout: BufferLayout.struct([ - BufferLayout.u32('instruction'), - ]), - }, - Merge: { - index: 7, - layout: BufferLayout.struct([ - BufferLayout.u32('instruction'), - ]), - }, - AuthorizeWithSeed: { - index: 8, - layout: BufferLayout.struct( - [ - BufferLayout.u32('instruction'), - Layout.publicKey('newAuthorized'), - BufferLayout.u32('stakeAuthorizationType'), - Layout.rustString('authoritySeed'), - Layout.publicKey('authorityOwner'), - ], - ), - }, -}); - -/** - * Stake authorization type - */ -export type StakeAuthorizationType = { - /** The Stake Authorization index (from solana-stake-program) */ - index: number; -}; - -/** - * An enumeration of valid StakeAuthorizationLayout's - */ -export const StakeAuthorizationLayout = Object.freeze({ - Staker: { - index: 0, - }, - Withdrawer: { - index: 1, - }, -}); - -/** - * Factory class for transactions to interact with the Stake program - */ -export class StakeProgram { - /** - * @internal - */ - constructor() {} - - /** - * Public key that identifies the Stake program - */ - static programId: PublicKey = new PublicKey( - 'Stake11111111111111111111111111111111111111', - ); - - /** - * Max space of a Stake account - * - * This is generated from the solana-stake-program StakeState struct as - * `StakeStateV2::size_of()`: - * https://docs.rs/solana-stake-program/latest/solana_stake_program/stake_state/enum.StakeStateV2.html - */ - static space: number = 200; - - /** - * Generate an Initialize instruction to add to a Stake Create transaction - */ - static initialize(params: InitializeStakeParams): TransactionInstruction { - const {stakePubkey, authorized, lockup: maybeLockup} = params; - const lockup: Lockup = maybeLockup || Lockup.default; - const type = STAKE_INSTRUCTION_LAYOUTS.Initialize; - const data = encodeData(type, { - authorized: { - staker: toBuffer(authorized.staker.toBuffer()), - withdrawer: toBuffer(authorized.withdrawer.toBuffer()), - }, - lockup: { - unixTimestamp: lockup.unixTimestamp, - epoch: lockup.epoch, - custodian: toBuffer(lockup.custodian.toBuffer()), - }, - }); - const instructionData = { - keys: [ - {pubkey: stakePubkey, isSigner: false, isWritable: true}, - {pubkey: SYSVAR_RENT_PUBKEY, isSigner: false, isWritable: false}, - ], - programId: this.programId, - data, - }; - return new TransactionInstruction(instructionData); - } - - /** - * Generate a Transaction that creates a new Stake account at - * an address generated with `from`, a seed, and the Stake programId - */ - static createAccountWithSeed( - params: CreateStakeAccountWithSeedParams, - ): Transaction { - const transaction = new Transaction(); - transaction.add( - SystemProgram.createAccountWithSeed({ - fromPubkey: params.fromPubkey, - newAccountPubkey: params.stakePubkey, - basePubkey: params.basePubkey, - seed: params.seed, - lamports: params.lamports, - space: this.space, - programId: this.programId, - }), - ); - - const {stakePubkey, authorized, lockup} = params; - return transaction.add(this.initialize({stakePubkey, authorized, lockup})); - } - - /** - * Generate a Transaction that creates a new Stake account - */ - static createAccount(params: CreateStakeAccountParams): Transaction { - const transaction = new Transaction(); - transaction.add( - SystemProgram.createAccount({ - fromPubkey: params.fromPubkey, - newAccountPubkey: params.stakePubkey, - lamports: params.lamports, - space: this.space, - programId: this.programId, - }), - ); - - const {stakePubkey, authorized, lockup} = params; - return transaction.add(this.initialize({stakePubkey, authorized, lockup})); - } - - /** - * Generate a Transaction that delegates Stake tokens to a validator - * Vote PublicKey. This transaction can also be used to redelegate Stake - * to a new validator Vote PublicKey. - */ - static delegate(params: DelegateStakeParams): Transaction { - const {stakePubkey, authorizedPubkey, votePubkey} = params; - - const type = STAKE_INSTRUCTION_LAYOUTS.Delegate; - const data = encodeData(type); - - return new Transaction().add({ - keys: [ - {pubkey: stakePubkey, isSigner: false, isWritable: true}, - {pubkey: votePubkey, isSigner: false, isWritable: false}, - {pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false}, - { - pubkey: SYSVAR_STAKE_HISTORY_PUBKEY, - isSigner: false, - isWritable: false, - }, - {pubkey: STAKE_CONFIG_ID, isSigner: false, isWritable: false}, - {pubkey: authorizedPubkey, isSigner: true, isWritable: false}, - ], - programId: this.programId, - data, - }); - } - - /** - * Generate a Transaction that authorizes a new PublicKey as Staker - * or Withdrawer on the Stake account. - */ - static authorize(params: AuthorizeStakeParams): Transaction { - const { - stakePubkey, - authorizedPubkey, - newAuthorizedPubkey, - stakeAuthorizationType, - custodianPubkey, - } = params; - - const type = STAKE_INSTRUCTION_LAYOUTS.Authorize; - const data = encodeData(type, { - newAuthorized: toBuffer(newAuthorizedPubkey.toBuffer()), - stakeAuthorizationType: stakeAuthorizationType.index, - }); - - const keys = [ - {pubkey: stakePubkey, isSigner: false, isWritable: true}, - {pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: true}, - {pubkey: authorizedPubkey, isSigner: true, isWritable: false}, - ]; - if (custodianPubkey) { - keys.push({ - pubkey: custodianPubkey, - isSigner: true, - isWritable: false, - }); - } - return new Transaction().add({ - keys, - programId: this.programId, - data, - }); - } - - /** - * Generate a Transaction that authorizes a new PublicKey as Staker - * or Withdrawer on the Stake account. - */ - static authorizeWithSeed(params: AuthorizeWithSeedStakeParams): Transaction { - const { - stakePubkey, - authorityBase, - authoritySeed, - authorityOwner, - newAuthorizedPubkey, - stakeAuthorizationType, - custodianPubkey, - } = params; - - const type = STAKE_INSTRUCTION_LAYOUTS.AuthorizeWithSeed; - const data = encodeData(type, { - newAuthorized: toBuffer(newAuthorizedPubkey.toBuffer()), - stakeAuthorizationType: stakeAuthorizationType.index, - authoritySeed: authoritySeed, - authorityOwner: toBuffer(authorityOwner.toBuffer()), - }); - - const keys = [ - {pubkey: stakePubkey, isSigner: false, isWritable: true}, - {pubkey: authorityBase, isSigner: true, isWritable: false}, - {pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false}, - ]; - if (custodianPubkey) { - keys.push({ - pubkey: custodianPubkey, - isSigner: true, - isWritable: false, - }); - } - return new Transaction().add({ - keys, - programId: this.programId, - data, - }); - } - - /** - * @internal - */ - static splitInstruction(params: SplitStakeParams): TransactionInstruction { - const {stakePubkey, authorizedPubkey, splitStakePubkey, lamports} = params; - const type = STAKE_INSTRUCTION_LAYOUTS.Split; - const data = encodeData(type, {lamports}); - return new TransactionInstruction({ - keys: [ - {pubkey: stakePubkey, isSigner: false, isWritable: true}, - {pubkey: splitStakePubkey, isSigner: false, isWritable: true}, - {pubkey: authorizedPubkey, isSigner: true, isWritable: false}, - ], - programId: this.programId, - data, - }); - } - - /** - * Generate a Transaction that splits Stake tokens into another stake account - */ - static split( - params: SplitStakeParams, - // Compute the cost of allocating the new stake account in lamports - rentExemptReserve: number, - ): Transaction { - const transaction = new Transaction(); - transaction.add( - SystemProgram.createAccount({ - fromPubkey: params.authorizedPubkey, - newAccountPubkey: params.splitStakePubkey, - lamports: rentExemptReserve, - space: this.space, - programId: this.programId, - }), - ); - return transaction.add(this.splitInstruction(params)); - } - - /** - * Generate a Transaction that splits Stake tokens into another account - * derived from a base public key and seed - */ - static splitWithSeed( - params: SplitStakeWithSeedParams, - // If this stake account is new, compute the cost of allocating it in lamports - rentExemptReserve?: number, - ): Transaction { - const { - stakePubkey, - authorizedPubkey, - splitStakePubkey, - basePubkey, - seed, - lamports, - } = params; - const transaction = new Transaction(); - transaction.add( - SystemProgram.allocate({ - accountPubkey: splitStakePubkey, - basePubkey, - seed, - space: this.space, - programId: this.programId, - }), - ); - if (rentExemptReserve && rentExemptReserve > 0) { - transaction.add( - SystemProgram.transfer({ - fromPubkey: params.authorizedPubkey, - toPubkey: splitStakePubkey, - lamports: rentExemptReserve, - }), - ); - } - return transaction.add( - this.splitInstruction({ - stakePubkey, - authorizedPubkey, - splitStakePubkey, - lamports, - }), - ); - } - - /** - * Generate a Transaction that merges Stake accounts. - */ - static merge(params: MergeStakeParams): Transaction { - const {stakePubkey, sourceStakePubKey, authorizedPubkey} = params; - const type = STAKE_INSTRUCTION_LAYOUTS.Merge; - const data = encodeData(type); - - return new Transaction().add({ - keys: [ - {pubkey: stakePubkey, isSigner: false, isWritable: true}, - {pubkey: sourceStakePubKey, isSigner: false, isWritable: true}, - {pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false}, - { - pubkey: SYSVAR_STAKE_HISTORY_PUBKEY, - isSigner: false, - isWritable: false, - }, - {pubkey: authorizedPubkey, isSigner: true, isWritable: false}, - ], - programId: this.programId, - data, - }); - } - - /** - * Generate a Transaction that withdraws deactivated Stake tokens. - */ - static withdraw(params: WithdrawStakeParams): Transaction { - const {stakePubkey, authorizedPubkey, toPubkey, lamports, custodianPubkey} = - params; - const type = STAKE_INSTRUCTION_LAYOUTS.Withdraw; - const data = encodeData(type, {lamports}); - - const keys = [ - {pubkey: stakePubkey, isSigner: false, isWritable: true}, - {pubkey: toPubkey, isSigner: false, isWritable: true}, - {pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false}, - { - pubkey: SYSVAR_STAKE_HISTORY_PUBKEY, - isSigner: false, - isWritable: false, - }, - {pubkey: authorizedPubkey, isSigner: true, isWritable: false}, - ]; - if (custodianPubkey) { - keys.push({ - pubkey: custodianPubkey, - isSigner: true, - isWritable: false, - }); - } - return new Transaction().add({ - keys, - programId: this.programId, - data, - }); - } - - /** - * Generate a Transaction that deactivates Stake tokens. - */ - static deactivate(params: DeactivateStakeParams): Transaction { - const {stakePubkey, authorizedPubkey} = params; - const type = STAKE_INSTRUCTION_LAYOUTS.Deactivate; - const data = encodeData(type); - - return new Transaction().add({ - keys: [ - {pubkey: stakePubkey, isSigner: false, isWritable: true}, - {pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false}, - {pubkey: authorizedPubkey, isSigner: true, isWritable: false}, - ], - programId: this.programId, - data, - }); - } -} diff --git a/packages/library-legacy/src/programs/system.ts b/packages/library-legacy/src/programs/system.ts deleted file mode 100644 index 32b21bbe0c22..000000000000 --- a/packages/library-legacy/src/programs/system.ts +++ /dev/null @@ -1,1048 +0,0 @@ -import * as BufferLayout from '@solana/buffer-layout'; - -import { - encodeData, - decodeData, - InstructionType, - IInstructionInputData, -} from '../instruction'; -import * as Layout from '../layout'; -import {NONCE_ACCOUNT_LENGTH} from '../nonce-account'; -import {PublicKey} from '../publickey'; -import {SYSVAR_RECENT_BLOCKHASHES_PUBKEY, SYSVAR_RENT_PUBKEY} from '../sysvar'; -import {Transaction, TransactionInstruction} from '../transaction'; -import {toBuffer} from '../utils/to-buffer'; -import {u64} from '../utils/bigint'; - -/** - * Create account system transaction params - */ -export type CreateAccountParams = { - /** The account that will transfer lamports to the created account */ - fromPubkey: PublicKey; - /** Public key of the created account */ - newAccountPubkey: PublicKey; - /** Amount of lamports to transfer to the created account */ - lamports: number; - /** Amount of space in bytes to allocate to the created account */ - space: number; - /** Public key of the program to assign as the owner of the created account */ - programId: PublicKey; -}; - -/** - * Transfer system transaction params - */ -export type TransferParams = { - /** Account that will transfer lamports */ - fromPubkey: PublicKey; - /** Account that will receive transferred lamports */ - toPubkey: PublicKey; - /** Amount of lamports to transfer */ - lamports: number | bigint; -}; - -/** - * Assign system transaction params - */ -export type AssignParams = { - /** Public key of the account which will be assigned a new owner */ - accountPubkey: PublicKey; - /** Public key of the program to assign as the owner */ - programId: PublicKey; -}; - -/** - * Create account with seed system transaction params - */ -export type CreateAccountWithSeedParams = { - /** The account that will transfer lamports to the created account */ - fromPubkey: PublicKey; - /** Public key of the created account. Must be pre-calculated with PublicKey.createWithSeed() */ - newAccountPubkey: PublicKey; - /** Base public key to use to derive the address of the created account. Must be the same as the base key used to create `newAccountPubkey` */ - basePubkey: PublicKey; - /** Seed to use to derive the address of the created account. Must be the same as the seed used to create `newAccountPubkey` */ - seed: string; - /** Amount of lamports to transfer to the created account */ - lamports: number; - /** Amount of space in bytes to allocate to the created account */ - space: number; - /** Public key of the program to assign as the owner of the created account */ - programId: PublicKey; -}; - -/** - * Create nonce account system transaction params - */ -export type CreateNonceAccountParams = { - /** The account that will transfer lamports to the created nonce account */ - fromPubkey: PublicKey; - /** Public key of the created nonce account */ - noncePubkey: PublicKey; - /** Public key to set as authority of the created nonce account */ - authorizedPubkey: PublicKey; - /** Amount of lamports to transfer to the created nonce account */ - lamports: number; -}; - -/** - * Create nonce account with seed system transaction params - */ -export type CreateNonceAccountWithSeedParams = { - /** The account that will transfer lamports to the created nonce account */ - fromPubkey: PublicKey; - /** Public key of the created nonce account */ - noncePubkey: PublicKey; - /** Public key to set as authority of the created nonce account */ - authorizedPubkey: PublicKey; - /** Amount of lamports to transfer to the created nonce account */ - lamports: number; - /** Base public key to use to derive the address of the nonce account */ - basePubkey: PublicKey; - /** Seed to use to derive the address of the nonce account */ - seed: string; -}; - -/** - * Initialize nonce account system instruction params - */ -export type InitializeNonceParams = { - /** Nonce account which will be initialized */ - noncePubkey: PublicKey; - /** Public key to set as authority of the initialized nonce account */ - authorizedPubkey: PublicKey; -}; - -/** - * Advance nonce account system instruction params - */ -export type AdvanceNonceParams = { - /** Nonce account */ - noncePubkey: PublicKey; - /** Public key of the nonce authority */ - authorizedPubkey: PublicKey; -}; - -/** - * Withdraw nonce account system transaction params - */ -export type WithdrawNonceParams = { - /** Nonce account */ - noncePubkey: PublicKey; - /** Public key of the nonce authority */ - authorizedPubkey: PublicKey; - /** Public key of the account which will receive the withdrawn nonce account balance */ - toPubkey: PublicKey; - /** Amount of lamports to withdraw from the nonce account */ - lamports: number; -}; - -/** - * Authorize nonce account system transaction params - */ -export type AuthorizeNonceParams = { - /** Nonce account */ - noncePubkey: PublicKey; - /** Public key of the current nonce authority */ - authorizedPubkey: PublicKey; - /** Public key to set as the new nonce authority */ - newAuthorizedPubkey: PublicKey; -}; - -/** - * Allocate account system transaction params - */ -export type AllocateParams = { - /** Account to allocate */ - accountPubkey: PublicKey; - /** Amount of space in bytes to allocate */ - space: number; -}; - -/** - * Allocate account with seed system transaction params - */ -export type AllocateWithSeedParams = { - /** Account to allocate */ - accountPubkey: PublicKey; - /** Base public key to use to derive the address of the allocated account */ - basePubkey: PublicKey; - /** Seed to use to derive the address of the allocated account */ - seed: string; - /** Amount of space in bytes to allocate */ - space: number; - /** Public key of the program to assign as the owner of the allocated account */ - programId: PublicKey; -}; - -/** - * Assign account with seed system transaction params - */ -export type AssignWithSeedParams = { - /** Public key of the account which will be assigned a new owner */ - accountPubkey: PublicKey; - /** Base public key to use to derive the address of the assigned account */ - basePubkey: PublicKey; - /** Seed to use to derive the address of the assigned account */ - seed: string; - /** Public key of the program to assign as the owner */ - programId: PublicKey; -}; - -/** - * Transfer with seed system transaction params - */ -export type TransferWithSeedParams = { - /** Account that will transfer lamports */ - fromPubkey: PublicKey; - /** Base public key to use to derive the funding account address */ - basePubkey: PublicKey; - /** Account that will receive transferred lamports */ - toPubkey: PublicKey; - /** Amount of lamports to transfer */ - lamports: number | bigint; - /** Seed to use to derive the funding account address */ - seed: string; - /** Program id to use to derive the funding account address */ - programId: PublicKey; -}; - -/** Decoded transfer system transaction instruction */ -export type DecodedTransferInstruction = { - /** Account that will transfer lamports */ - fromPubkey: PublicKey; - /** Account that will receive transferred lamports */ - toPubkey: PublicKey; - /** Amount of lamports to transfer */ - lamports: bigint; -}; - -/** Decoded transferWithSeed system transaction instruction */ -export type DecodedTransferWithSeedInstruction = { - /** Account that will transfer lamports */ - fromPubkey: PublicKey; - /** Base public key to use to derive the funding account address */ - basePubkey: PublicKey; - /** Account that will receive transferred lamports */ - toPubkey: PublicKey; - /** Amount of lamports to transfer */ - lamports: bigint; - /** Seed to use to derive the funding account address */ - seed: string; - /** Program id to use to derive the funding account address */ - programId: PublicKey; -}; - -/** - * System Instruction class - */ -export class SystemInstruction { - /** - * @internal - */ - constructor() {} - - /** - * Decode a system instruction and retrieve the instruction type. - */ - static decodeInstructionType( - instruction: TransactionInstruction, - ): SystemInstructionType { - this.checkProgramId(instruction.programId); - - const instructionTypeLayout = BufferLayout.u32('instruction'); - const typeIndex = instructionTypeLayout.decode(instruction.data); - - let type: SystemInstructionType | undefined; - for (const [ixType, layout] of Object.entries(SYSTEM_INSTRUCTION_LAYOUTS)) { - if (layout.index == typeIndex) { - type = ixType as SystemInstructionType; - break; - } - } - - if (!type) { - throw new Error('Instruction type incorrect; not a SystemInstruction'); - } - - return type; - } - - /** - * Decode a create account system instruction and retrieve the instruction params. - */ - static decodeCreateAccount( - instruction: TransactionInstruction, - ): CreateAccountParams { - this.checkProgramId(instruction.programId); - this.checkKeyLength(instruction.keys, 2); - - const {lamports, space, programId} = decodeData( - SYSTEM_INSTRUCTION_LAYOUTS.Create, - instruction.data, - ); - - return { - fromPubkey: instruction.keys[0].pubkey, - newAccountPubkey: instruction.keys[1].pubkey, - lamports, - space, - programId: new PublicKey(programId), - }; - } - - /** - * Decode a transfer system instruction and retrieve the instruction params. - */ - static decodeTransfer( - instruction: TransactionInstruction, - ): DecodedTransferInstruction { - this.checkProgramId(instruction.programId); - this.checkKeyLength(instruction.keys, 2); - - const {lamports} = decodeData( - SYSTEM_INSTRUCTION_LAYOUTS.Transfer, - instruction.data, - ); - - return { - fromPubkey: instruction.keys[0].pubkey, - toPubkey: instruction.keys[1].pubkey, - lamports, - }; - } - - /** - * Decode a transfer with seed system instruction and retrieve the instruction params. - */ - static decodeTransferWithSeed( - instruction: TransactionInstruction, - ): DecodedTransferWithSeedInstruction { - this.checkProgramId(instruction.programId); - this.checkKeyLength(instruction.keys, 3); - - const {lamports, seed, programId} = decodeData( - SYSTEM_INSTRUCTION_LAYOUTS.TransferWithSeed, - instruction.data, - ); - - return { - fromPubkey: instruction.keys[0].pubkey, - basePubkey: instruction.keys[1].pubkey, - toPubkey: instruction.keys[2].pubkey, - lamports, - seed, - programId: new PublicKey(programId), - }; - } - - /** - * Decode an allocate system instruction and retrieve the instruction params. - */ - static decodeAllocate(instruction: TransactionInstruction): AllocateParams { - this.checkProgramId(instruction.programId); - this.checkKeyLength(instruction.keys, 1); - - const {space} = decodeData( - SYSTEM_INSTRUCTION_LAYOUTS.Allocate, - instruction.data, - ); - - return { - accountPubkey: instruction.keys[0].pubkey, - space, - }; - } - - /** - * Decode an allocate with seed system instruction and retrieve the instruction params. - */ - static decodeAllocateWithSeed( - instruction: TransactionInstruction, - ): AllocateWithSeedParams { - this.checkProgramId(instruction.programId); - this.checkKeyLength(instruction.keys, 1); - - const {base, seed, space, programId} = decodeData( - SYSTEM_INSTRUCTION_LAYOUTS.AllocateWithSeed, - instruction.data, - ); - - return { - accountPubkey: instruction.keys[0].pubkey, - basePubkey: new PublicKey(base), - seed, - space, - programId: new PublicKey(programId), - }; - } - - /** - * Decode an assign system instruction and retrieve the instruction params. - */ - static decodeAssign(instruction: TransactionInstruction): AssignParams { - this.checkProgramId(instruction.programId); - this.checkKeyLength(instruction.keys, 1); - - const {programId} = decodeData( - SYSTEM_INSTRUCTION_LAYOUTS.Assign, - instruction.data, - ); - - return { - accountPubkey: instruction.keys[0].pubkey, - programId: new PublicKey(programId), - }; - } - - /** - * Decode an assign with seed system instruction and retrieve the instruction params. - */ - static decodeAssignWithSeed( - instruction: TransactionInstruction, - ): AssignWithSeedParams { - this.checkProgramId(instruction.programId); - this.checkKeyLength(instruction.keys, 1); - - const {base, seed, programId} = decodeData( - SYSTEM_INSTRUCTION_LAYOUTS.AssignWithSeed, - instruction.data, - ); - - return { - accountPubkey: instruction.keys[0].pubkey, - basePubkey: new PublicKey(base), - seed, - programId: new PublicKey(programId), - }; - } - - /** - * Decode a create account with seed system instruction and retrieve the instruction params. - */ - static decodeCreateWithSeed( - instruction: TransactionInstruction, - ): CreateAccountWithSeedParams { - this.checkProgramId(instruction.programId); - this.checkKeyLength(instruction.keys, 2); - - const {base, seed, lamports, space, programId} = decodeData( - SYSTEM_INSTRUCTION_LAYOUTS.CreateWithSeed, - instruction.data, - ); - - return { - fromPubkey: instruction.keys[0].pubkey, - newAccountPubkey: instruction.keys[1].pubkey, - basePubkey: new PublicKey(base), - seed, - lamports, - space, - programId: new PublicKey(programId), - }; - } - - /** - * Decode a nonce initialize system instruction and retrieve the instruction params. - */ - static decodeNonceInitialize( - instruction: TransactionInstruction, - ): InitializeNonceParams { - this.checkProgramId(instruction.programId); - this.checkKeyLength(instruction.keys, 3); - - const {authorized} = decodeData( - SYSTEM_INSTRUCTION_LAYOUTS.InitializeNonceAccount, - instruction.data, - ); - - return { - noncePubkey: instruction.keys[0].pubkey, - authorizedPubkey: new PublicKey(authorized), - }; - } - - /** - * Decode a nonce advance system instruction and retrieve the instruction params. - */ - static decodeNonceAdvance( - instruction: TransactionInstruction, - ): AdvanceNonceParams { - this.checkProgramId(instruction.programId); - this.checkKeyLength(instruction.keys, 3); - - decodeData( - SYSTEM_INSTRUCTION_LAYOUTS.AdvanceNonceAccount, - instruction.data, - ); - - return { - noncePubkey: instruction.keys[0].pubkey, - authorizedPubkey: instruction.keys[2].pubkey, - }; - } - - /** - * Decode a nonce withdraw system instruction and retrieve the instruction params. - */ - static decodeNonceWithdraw( - instruction: TransactionInstruction, - ): WithdrawNonceParams { - this.checkProgramId(instruction.programId); - this.checkKeyLength(instruction.keys, 5); - - const {lamports} = decodeData( - SYSTEM_INSTRUCTION_LAYOUTS.WithdrawNonceAccount, - instruction.data, - ); - - return { - noncePubkey: instruction.keys[0].pubkey, - toPubkey: instruction.keys[1].pubkey, - authorizedPubkey: instruction.keys[4].pubkey, - lamports, - }; - } - - /** - * Decode a nonce authorize system instruction and retrieve the instruction params. - */ - static decodeNonceAuthorize( - instruction: TransactionInstruction, - ): AuthorizeNonceParams { - this.checkProgramId(instruction.programId); - this.checkKeyLength(instruction.keys, 2); - - const {authorized} = decodeData( - SYSTEM_INSTRUCTION_LAYOUTS.AuthorizeNonceAccount, - instruction.data, - ); - - return { - noncePubkey: instruction.keys[0].pubkey, - authorizedPubkey: instruction.keys[1].pubkey, - newAuthorizedPubkey: new PublicKey(authorized), - }; - } - - /** - * @internal - */ - static checkProgramId(programId: PublicKey) { - if (!programId.equals(SystemProgram.programId)) { - throw new Error('invalid instruction; programId is not SystemProgram'); - } - } - - /** - * @internal - */ - static checkKeyLength(keys: Array, expectedLength: number) { - if (keys.length < expectedLength) { - throw new Error( - `invalid instruction; found ${keys.length} keys, expected at least ${expectedLength}`, - ); - } - } -} - -/** - * An enumeration of valid SystemInstructionType's - */ -export type SystemInstructionType = - // FIXME - // It would be preferable for this type to be `keyof SystemInstructionInputData` - // but Typedoc does not transpile `keyof` expressions. - // See https://github.com/TypeStrong/typedoc/issues/1894 - | 'AdvanceNonceAccount' - | 'Allocate' - | 'AllocateWithSeed' - | 'Assign' - | 'AssignWithSeed' - | 'AuthorizeNonceAccount' - | 'Create' - | 'CreateWithSeed' - | 'InitializeNonceAccount' - | 'Transfer' - | 'TransferWithSeed' - | 'WithdrawNonceAccount' - | 'UpgradeNonceAccount'; - -type SystemInstructionInputData = { - AdvanceNonceAccount: IInstructionInputData; - Allocate: IInstructionInputData & { - space: number; - }; - AllocateWithSeed: IInstructionInputData & { - base: Uint8Array; - programId: Uint8Array; - seed: string; - space: number; - }; - Assign: IInstructionInputData & { - programId: Uint8Array; - }; - AssignWithSeed: IInstructionInputData & { - base: Uint8Array; - seed: string; - programId: Uint8Array; - }; - AuthorizeNonceAccount: IInstructionInputData & { - authorized: Uint8Array; - }; - Create: IInstructionInputData & { - lamports: number; - programId: Uint8Array; - space: number; - }; - CreateWithSeed: IInstructionInputData & { - base: Uint8Array; - lamports: number; - programId: Uint8Array; - seed: string; - space: number; - }; - InitializeNonceAccount: IInstructionInputData & { - authorized: Uint8Array; - }; - Transfer: IInstructionInputData & { - lamports: bigint; - }; - TransferWithSeed: IInstructionInputData & { - lamports: bigint; - programId: Uint8Array; - seed: string; - }; - WithdrawNonceAccount: IInstructionInputData & { - lamports: number; - }; - UpgradeNonceAccount: IInstructionInputData; -}; - -/** - * An enumeration of valid system InstructionType's - * @internal - */ -export const SYSTEM_INSTRUCTION_LAYOUTS = Object.freeze<{ - [Instruction in SystemInstructionType]: InstructionType< - SystemInstructionInputData[Instruction] - >; -}>({ - Create: { - index: 0, - layout: BufferLayout.struct([ - BufferLayout.u32('instruction'), - BufferLayout.ns64('lamports'), - BufferLayout.ns64('space'), - Layout.publicKey('programId'), - ]), - }, - Assign: { - index: 1, - layout: BufferLayout.struct([ - BufferLayout.u32('instruction'), - Layout.publicKey('programId'), - ]), - }, - Transfer: { - index: 2, - layout: BufferLayout.struct([ - BufferLayout.u32('instruction'), - u64('lamports'), - ]), - }, - CreateWithSeed: { - index: 3, - layout: BufferLayout.struct([ - BufferLayout.u32('instruction'), - Layout.publicKey('base'), - Layout.rustString('seed'), - BufferLayout.ns64('lamports'), - BufferLayout.ns64('space'), - Layout.publicKey('programId'), - ]), - }, - AdvanceNonceAccount: { - index: 4, - layout: BufferLayout.struct< - SystemInstructionInputData['AdvanceNonceAccount'] - >([BufferLayout.u32('instruction')]), - }, - WithdrawNonceAccount: { - index: 5, - layout: BufferLayout.struct< - SystemInstructionInputData['WithdrawNonceAccount'] - >([BufferLayout.u32('instruction'), BufferLayout.ns64('lamports')]), - }, - InitializeNonceAccount: { - index: 6, - layout: BufferLayout.struct< - SystemInstructionInputData['InitializeNonceAccount'] - >([BufferLayout.u32('instruction'), Layout.publicKey('authorized')]), - }, - AuthorizeNonceAccount: { - index: 7, - layout: BufferLayout.struct< - SystemInstructionInputData['AuthorizeNonceAccount'] - >([BufferLayout.u32('instruction'), Layout.publicKey('authorized')]), - }, - Allocate: { - index: 8, - layout: BufferLayout.struct([ - BufferLayout.u32('instruction'), - BufferLayout.ns64('space'), - ]), - }, - AllocateWithSeed: { - index: 9, - layout: BufferLayout.struct( - [ - BufferLayout.u32('instruction'), - Layout.publicKey('base'), - Layout.rustString('seed'), - BufferLayout.ns64('space'), - Layout.publicKey('programId'), - ], - ), - }, - AssignWithSeed: { - index: 10, - layout: BufferLayout.struct([ - BufferLayout.u32('instruction'), - Layout.publicKey('base'), - Layout.rustString('seed'), - Layout.publicKey('programId'), - ]), - }, - TransferWithSeed: { - index: 11, - layout: BufferLayout.struct( - [ - BufferLayout.u32('instruction'), - u64('lamports'), - Layout.rustString('seed'), - Layout.publicKey('programId'), - ], - ), - }, - UpgradeNonceAccount: { - index: 12, - layout: BufferLayout.struct< - SystemInstructionInputData['UpgradeNonceAccount'] - >([BufferLayout.u32('instruction')]), - }, -}); - -/** - * Factory class for transactions to interact with the System program - */ -export class SystemProgram { - /** - * @internal - */ - constructor() {} - - /** - * Public key that identifies the System program - */ - static programId: PublicKey = new PublicKey( - '11111111111111111111111111111111', - ); - - /** - * Generate a transaction instruction that creates a new account - */ - static createAccount(params: CreateAccountParams): TransactionInstruction { - const type = SYSTEM_INSTRUCTION_LAYOUTS.Create; - const data = encodeData(type, { - lamports: params.lamports, - space: params.space, - programId: toBuffer(params.programId.toBuffer()), - }); - - return new TransactionInstruction({ - keys: [ - {pubkey: params.fromPubkey, isSigner: true, isWritable: true}, - {pubkey: params.newAccountPubkey, isSigner: true, isWritable: true}, - ], - programId: this.programId, - data, - }); - } - - /** - * Generate a transaction instruction that transfers lamports from one account to another - */ - static transfer( - params: TransferParams | TransferWithSeedParams, - ): TransactionInstruction { - let data; - let keys; - if ('basePubkey' in params) { - const type = SYSTEM_INSTRUCTION_LAYOUTS.TransferWithSeed; - data = encodeData(type, { - lamports: BigInt(params.lamports), - seed: params.seed, - programId: toBuffer(params.programId.toBuffer()), - }); - keys = [ - {pubkey: params.fromPubkey, isSigner: false, isWritable: true}, - {pubkey: params.basePubkey, isSigner: true, isWritable: false}, - {pubkey: params.toPubkey, isSigner: false, isWritable: true}, - ]; - } else { - const type = SYSTEM_INSTRUCTION_LAYOUTS.Transfer; - data = encodeData(type, {lamports: BigInt(params.lamports)}); - keys = [ - {pubkey: params.fromPubkey, isSigner: true, isWritable: true}, - {pubkey: params.toPubkey, isSigner: false, isWritable: true}, - ]; - } - - return new TransactionInstruction({ - keys, - programId: this.programId, - data, - }); - } - - /** - * Generate a transaction instruction that assigns an account to a program - */ - static assign( - params: AssignParams | AssignWithSeedParams, - ): TransactionInstruction { - let data; - let keys; - if ('basePubkey' in params) { - const type = SYSTEM_INSTRUCTION_LAYOUTS.AssignWithSeed; - data = encodeData(type, { - base: toBuffer(params.basePubkey.toBuffer()), - seed: params.seed, - programId: toBuffer(params.programId.toBuffer()), - }); - keys = [ - {pubkey: params.accountPubkey, isSigner: false, isWritable: true}, - {pubkey: params.basePubkey, isSigner: true, isWritable: false}, - ]; - } else { - const type = SYSTEM_INSTRUCTION_LAYOUTS.Assign; - data = encodeData(type, { - programId: toBuffer(params.programId.toBuffer()), - }); - keys = [{pubkey: params.accountPubkey, isSigner: true, isWritable: true}]; - } - - return new TransactionInstruction({ - keys, - programId: this.programId, - data, - }); - } - - /** - * Generate a transaction instruction that creates a new account at - * an address generated with `from`, a seed, and programId - */ - static createAccountWithSeed( - params: CreateAccountWithSeedParams, - ): TransactionInstruction { - const type = SYSTEM_INSTRUCTION_LAYOUTS.CreateWithSeed; - const data = encodeData(type, { - base: toBuffer(params.basePubkey.toBuffer()), - seed: params.seed, - lamports: params.lamports, - space: params.space, - programId: toBuffer(params.programId.toBuffer()), - }); - let keys = [ - {pubkey: params.fromPubkey, isSigner: true, isWritable: true}, - {pubkey: params.newAccountPubkey, isSigner: false, isWritable: true}, - ]; - if (params.basePubkey != params.fromPubkey) { - keys.push({ - pubkey: params.basePubkey, - isSigner: true, - isWritable: false, - }); - } - - return new TransactionInstruction({ - keys, - programId: this.programId, - data, - }); - } - - /** - * Generate a transaction that creates a new Nonce account - */ - static createNonceAccount( - params: CreateNonceAccountParams | CreateNonceAccountWithSeedParams, - ): Transaction { - const transaction = new Transaction(); - if ('basePubkey' in params && 'seed' in params) { - transaction.add( - SystemProgram.createAccountWithSeed({ - fromPubkey: params.fromPubkey, - newAccountPubkey: params.noncePubkey, - basePubkey: params.basePubkey, - seed: params.seed, - lamports: params.lamports, - space: NONCE_ACCOUNT_LENGTH, - programId: this.programId, - }), - ); - } else { - transaction.add( - SystemProgram.createAccount({ - fromPubkey: params.fromPubkey, - newAccountPubkey: params.noncePubkey, - lamports: params.lamports, - space: NONCE_ACCOUNT_LENGTH, - programId: this.programId, - }), - ); - } - - const initParams = { - noncePubkey: params.noncePubkey, - authorizedPubkey: params.authorizedPubkey, - }; - - transaction.add(this.nonceInitialize(initParams)); - return transaction; - } - - /** - * Generate an instruction to initialize a Nonce account - */ - static nonceInitialize( - params: InitializeNonceParams, - ): TransactionInstruction { - const type = SYSTEM_INSTRUCTION_LAYOUTS.InitializeNonceAccount; - const data = encodeData(type, { - authorized: toBuffer(params.authorizedPubkey.toBuffer()), - }); - const instructionData = { - keys: [ - {pubkey: params.noncePubkey, isSigner: false, isWritable: true}, - { - pubkey: SYSVAR_RECENT_BLOCKHASHES_PUBKEY, - isSigner: false, - isWritable: false, - }, - {pubkey: SYSVAR_RENT_PUBKEY, isSigner: false, isWritable: false}, - ], - programId: this.programId, - data, - }; - return new TransactionInstruction(instructionData); - } - - /** - * Generate an instruction to advance the nonce in a Nonce account - */ - static nonceAdvance(params: AdvanceNonceParams): TransactionInstruction { - const type = SYSTEM_INSTRUCTION_LAYOUTS.AdvanceNonceAccount; - const data = encodeData(type); - const instructionData = { - keys: [ - {pubkey: params.noncePubkey, isSigner: false, isWritable: true}, - { - pubkey: SYSVAR_RECENT_BLOCKHASHES_PUBKEY, - isSigner: false, - isWritable: false, - }, - {pubkey: params.authorizedPubkey, isSigner: true, isWritable: false}, - ], - programId: this.programId, - data, - }; - return new TransactionInstruction(instructionData); - } - - /** - * Generate a transaction instruction that withdraws lamports from a Nonce account - */ - static nonceWithdraw(params: WithdrawNonceParams): TransactionInstruction { - const type = SYSTEM_INSTRUCTION_LAYOUTS.WithdrawNonceAccount; - const data = encodeData(type, {lamports: params.lamports}); - - return new TransactionInstruction({ - keys: [ - {pubkey: params.noncePubkey, isSigner: false, isWritable: true}, - {pubkey: params.toPubkey, isSigner: false, isWritable: true}, - { - pubkey: SYSVAR_RECENT_BLOCKHASHES_PUBKEY, - isSigner: false, - isWritable: false, - }, - { - pubkey: SYSVAR_RENT_PUBKEY, - isSigner: false, - isWritable: false, - }, - {pubkey: params.authorizedPubkey, isSigner: true, isWritable: false}, - ], - programId: this.programId, - data, - }); - } - - /** - * Generate a transaction instruction that authorizes a new PublicKey as the authority - * on a Nonce account. - */ - static nonceAuthorize(params: AuthorizeNonceParams): TransactionInstruction { - const type = SYSTEM_INSTRUCTION_LAYOUTS.AuthorizeNonceAccount; - const data = encodeData(type, { - authorized: toBuffer(params.newAuthorizedPubkey.toBuffer()), - }); - - return new TransactionInstruction({ - keys: [ - {pubkey: params.noncePubkey, isSigner: false, isWritable: true}, - {pubkey: params.authorizedPubkey, isSigner: true, isWritable: false}, - ], - programId: this.programId, - data, - }); - } - - /** - * Generate a transaction instruction that allocates space in an account without funding - */ - static allocate( - params: AllocateParams | AllocateWithSeedParams, - ): TransactionInstruction { - let data; - let keys; - if ('basePubkey' in params) { - const type = SYSTEM_INSTRUCTION_LAYOUTS.AllocateWithSeed; - data = encodeData(type, { - base: toBuffer(params.basePubkey.toBuffer()), - seed: params.seed, - space: params.space, - programId: toBuffer(params.programId.toBuffer()), - }); - keys = [ - {pubkey: params.accountPubkey, isSigner: false, isWritable: true}, - {pubkey: params.basePubkey, isSigner: true, isWritable: false}, - ]; - } else { - const type = SYSTEM_INSTRUCTION_LAYOUTS.Allocate; - data = encodeData(type, { - space: params.space, - }); - keys = [{pubkey: params.accountPubkey, isSigner: true, isWritable: true}]; - } - - return new TransactionInstruction({ - keys, - programId: this.programId, - data, - }); - } -} diff --git a/packages/library-legacy/src/programs/vote.ts b/packages/library-legacy/src/programs/vote.ts deleted file mode 100644 index 2c1ba4364806..000000000000 --- a/packages/library-legacy/src/programs/vote.ts +++ /dev/null @@ -1,586 +0,0 @@ -import * as BufferLayout from '@solana/buffer-layout'; - -import { - encodeData, - decodeData, - InstructionType, - IInstructionInputData, -} from '../instruction'; -import * as Layout from '../layout'; -import {PublicKey} from '../publickey'; -import {SystemProgram} from './system'; -import {SYSVAR_CLOCK_PUBKEY, SYSVAR_RENT_PUBKEY} from '../sysvar'; -import {Transaction, TransactionInstruction} from '../transaction'; -import {toBuffer} from '../utils/to-buffer'; - -/** - * Vote account info - */ -export class VoteInit { - nodePubkey: PublicKey; - authorizedVoter: PublicKey; - authorizedWithdrawer: PublicKey; - commission: number; /** [0, 100] */ - - constructor( - nodePubkey: PublicKey, - authorizedVoter: PublicKey, - authorizedWithdrawer: PublicKey, - commission: number, - ) { - this.nodePubkey = nodePubkey; - this.authorizedVoter = authorizedVoter; - this.authorizedWithdrawer = authorizedWithdrawer; - this.commission = commission; - } -} - -/** - * Create vote account transaction params - */ -export type CreateVoteAccountParams = { - fromPubkey: PublicKey; - votePubkey: PublicKey; - voteInit: VoteInit; - lamports: number; -}; - -/** - * InitializeAccount instruction params - */ -export type InitializeAccountParams = { - votePubkey: PublicKey; - nodePubkey: PublicKey; - voteInit: VoteInit; -}; - -/** - * Authorize instruction params - */ -export type AuthorizeVoteParams = { - votePubkey: PublicKey; - /** Current vote or withdraw authority, depending on `voteAuthorizationType` */ - authorizedPubkey: PublicKey; - newAuthorizedPubkey: PublicKey; - voteAuthorizationType: VoteAuthorizationType; -}; - -/** - * AuthorizeWithSeed instruction params - */ -export type AuthorizeVoteWithSeedParams = { - currentAuthorityDerivedKeyBasePubkey: PublicKey; - currentAuthorityDerivedKeyOwnerPubkey: PublicKey; - currentAuthorityDerivedKeySeed: string; - newAuthorizedPubkey: PublicKey; - voteAuthorizationType: VoteAuthorizationType; - votePubkey: PublicKey; -}; - -/** - * Withdraw from vote account transaction params - */ -export type WithdrawFromVoteAccountParams = { - votePubkey: PublicKey; - authorizedWithdrawerPubkey: PublicKey; - lamports: number; - toPubkey: PublicKey; -}; - -/** - * Update validator identity (node pubkey) vote account instruction params. - */ -export type UpdateValidatorIdentityParams = { - votePubkey: PublicKey; - authorizedWithdrawerPubkey: PublicKey; - nodePubkey: PublicKey; -}; - -/** - * Vote Instruction class - */ -export class VoteInstruction { - /** - * @internal - */ - constructor() {} - - /** - * Decode a vote instruction and retrieve the instruction type. - */ - static decodeInstructionType( - instruction: TransactionInstruction, - ): VoteInstructionType { - this.checkProgramId(instruction.programId); - - const instructionTypeLayout = BufferLayout.u32('instruction'); - const typeIndex = instructionTypeLayout.decode(instruction.data); - - let type: VoteInstructionType | undefined; - for (const [ixType, layout] of Object.entries(VOTE_INSTRUCTION_LAYOUTS)) { - if (layout.index == typeIndex) { - type = ixType as VoteInstructionType; - break; - } - } - - if (!type) { - throw new Error('Instruction type incorrect; not a VoteInstruction'); - } - - return type; - } - - /** - * Decode an initialize vote instruction and retrieve the instruction params. - */ - static decodeInitializeAccount( - instruction: TransactionInstruction, - ): InitializeAccountParams { - this.checkProgramId(instruction.programId); - this.checkKeyLength(instruction.keys, 4); - - const {voteInit} = decodeData( - VOTE_INSTRUCTION_LAYOUTS.InitializeAccount, - instruction.data, - ); - - return { - votePubkey: instruction.keys[0].pubkey, - nodePubkey: instruction.keys[3].pubkey, - voteInit: new VoteInit( - new PublicKey(voteInit.nodePubkey), - new PublicKey(voteInit.authorizedVoter), - new PublicKey(voteInit.authorizedWithdrawer), - voteInit.commission, - ), - }; - } - - /** - * Decode an authorize instruction and retrieve the instruction params. - */ - static decodeAuthorize( - instruction: TransactionInstruction, - ): AuthorizeVoteParams { - this.checkProgramId(instruction.programId); - this.checkKeyLength(instruction.keys, 3); - - const {newAuthorized, voteAuthorizationType} = decodeData( - VOTE_INSTRUCTION_LAYOUTS.Authorize, - instruction.data, - ); - - return { - votePubkey: instruction.keys[0].pubkey, - authorizedPubkey: instruction.keys[2].pubkey, - newAuthorizedPubkey: new PublicKey(newAuthorized), - voteAuthorizationType: { - index: voteAuthorizationType, - }, - }; - } - - /** - * Decode an authorize instruction and retrieve the instruction params. - */ - static decodeAuthorizeWithSeed( - instruction: TransactionInstruction, - ): AuthorizeVoteWithSeedParams { - this.checkProgramId(instruction.programId); - this.checkKeyLength(instruction.keys, 3); - - const { - voteAuthorizeWithSeedArgs: { - currentAuthorityDerivedKeyOwnerPubkey, - currentAuthorityDerivedKeySeed, - newAuthorized, - voteAuthorizationType, - }, - } = decodeData( - VOTE_INSTRUCTION_LAYOUTS.AuthorizeWithSeed, - instruction.data, - ); - - return { - currentAuthorityDerivedKeyBasePubkey: instruction.keys[2].pubkey, - currentAuthorityDerivedKeyOwnerPubkey: new PublicKey( - currentAuthorityDerivedKeyOwnerPubkey, - ), - currentAuthorityDerivedKeySeed: currentAuthorityDerivedKeySeed, - newAuthorizedPubkey: new PublicKey(newAuthorized), - voteAuthorizationType: { - index: voteAuthorizationType, - }, - votePubkey: instruction.keys[0].pubkey, - }; - } - - /** - * Decode a withdraw instruction and retrieve the instruction params. - */ - static decodeWithdraw( - instruction: TransactionInstruction, - ): WithdrawFromVoteAccountParams { - this.checkProgramId(instruction.programId); - this.checkKeyLength(instruction.keys, 3); - - const {lamports} = decodeData( - VOTE_INSTRUCTION_LAYOUTS.Withdraw, - instruction.data, - ); - - return { - votePubkey: instruction.keys[0].pubkey, - authorizedWithdrawerPubkey: instruction.keys[2].pubkey, - lamports, - toPubkey: instruction.keys[1].pubkey, - }; - } - - /** - * @internal - */ - static checkProgramId(programId: PublicKey) { - if (!programId.equals(VoteProgram.programId)) { - throw new Error('invalid instruction; programId is not VoteProgram'); - } - } - - /** - * @internal - */ - static checkKeyLength(keys: Array, expectedLength: number) { - if (keys.length < expectedLength) { - throw new Error( - `invalid instruction; found ${keys.length} keys, expected at least ${expectedLength}`, - ); - } - } -} - -/** - * An enumeration of valid VoteInstructionType's - */ -export type VoteInstructionType = - // FIXME - // It would be preferable for this type to be `keyof VoteInstructionInputData` - // but Typedoc does not transpile `keyof` expressions. - // See https://github.com/TypeStrong/typedoc/issues/1894 - | 'Authorize' - | 'AuthorizeWithSeed' - | 'InitializeAccount' - | 'Withdraw' - | 'UpdateValidatorIdentity'; - -/** @internal */ -export type VoteAuthorizeWithSeedArgs = Readonly<{ - currentAuthorityDerivedKeyOwnerPubkey: Uint8Array; - currentAuthorityDerivedKeySeed: string; - newAuthorized: Uint8Array; - voteAuthorizationType: number; -}>; -type VoteInstructionInputData = { - Authorize: IInstructionInputData & { - newAuthorized: Uint8Array; - voteAuthorizationType: number; - }; - AuthorizeWithSeed: IInstructionInputData & { - voteAuthorizeWithSeedArgs: VoteAuthorizeWithSeedArgs; - }; - InitializeAccount: IInstructionInputData & { - voteInit: Readonly<{ - authorizedVoter: Uint8Array; - authorizedWithdrawer: Uint8Array; - commission: number; - nodePubkey: Uint8Array; - }>; - }; - Withdraw: IInstructionInputData & { - lamports: number; - }; - UpdateValidatorIdentity: IInstructionInputData; -}; - -const VOTE_INSTRUCTION_LAYOUTS = Object.freeze<{ - [Instruction in VoteInstructionType]: InstructionType< - VoteInstructionInputData[Instruction] - >; -}>({ - InitializeAccount: { - index: 0, - layout: BufferLayout.struct([ - BufferLayout.u32('instruction'), - Layout.voteInit(), - ]), - }, - Authorize: { - index: 1, - layout: BufferLayout.struct([ - BufferLayout.u32('instruction'), - Layout.publicKey('newAuthorized'), - BufferLayout.u32('voteAuthorizationType'), - ]), - }, - Withdraw: { - index: 3, - layout: BufferLayout.struct([ - BufferLayout.u32('instruction'), - BufferLayout.ns64('lamports'), - ]), - }, - UpdateValidatorIdentity: { - index: 4, - layout: BufferLayout.struct< - VoteInstructionInputData['UpdateValidatorIdentity'] - >([BufferLayout.u32('instruction')]), - }, - AuthorizeWithSeed: { - index: 10, - layout: BufferLayout.struct([ - BufferLayout.u32('instruction'), - Layout.voteAuthorizeWithSeedArgs(), - ]), - }, -}); - -/** - * VoteAuthorize type - */ -export type VoteAuthorizationType = { - /** The VoteAuthorize index (from solana-vote-program) */ - index: number; -}; - -/** - * An enumeration of valid VoteAuthorization layouts. - */ -export const VoteAuthorizationLayout = Object.freeze({ - Voter: { - index: 0, - }, - Withdrawer: { - index: 1, - }, -}); - -/** - * Factory class for transactions to interact with the Vote program - */ -export class VoteProgram { - /** - * @internal - */ - constructor() {} - - /** - * Public key that identifies the Vote program - */ - static programId: PublicKey = new PublicKey( - 'Vote111111111111111111111111111111111111111', - ); - - /** - * Max space of a Vote account - * - * This is generated from the solana-vote-program VoteState struct as - * `VoteState::size_of()`: - * https://docs.rs/solana-vote-program/1.9.5/solana_vote_program/vote_state/struct.VoteState.html#method.size_of - * - * KEEP IN SYNC WITH `VoteState::size_of()` in https://github.com/solana-labs/solana/blob/a474cb24b9238f5edcc982f65c0b37d4a1046f7e/sdk/program/src/vote/state/mod.rs#L340-L342 - */ - static space: number = 3762; - - /** - * Generate an Initialize instruction. - */ - static initializeAccount( - params: InitializeAccountParams, - ): TransactionInstruction { - const {votePubkey, nodePubkey, voteInit} = params; - const type = VOTE_INSTRUCTION_LAYOUTS.InitializeAccount; - const data = encodeData(type, { - voteInit: { - nodePubkey: toBuffer(voteInit.nodePubkey.toBuffer()), - authorizedVoter: toBuffer(voteInit.authorizedVoter.toBuffer()), - authorizedWithdrawer: toBuffer( - voteInit.authorizedWithdrawer.toBuffer(), - ), - commission: voteInit.commission, - }, - }); - const instructionData = { - keys: [ - {pubkey: votePubkey, isSigner: false, isWritable: true}, - {pubkey: SYSVAR_RENT_PUBKEY, isSigner: false, isWritable: false}, - {pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false}, - {pubkey: nodePubkey, isSigner: true, isWritable: false}, - ], - programId: this.programId, - data, - }; - return new TransactionInstruction(instructionData); - } - - /** - * Generate a transaction that creates a new Vote account. - */ - static createAccount(params: CreateVoteAccountParams): Transaction { - const transaction = new Transaction(); - transaction.add( - SystemProgram.createAccount({ - fromPubkey: params.fromPubkey, - newAccountPubkey: params.votePubkey, - lamports: params.lamports, - space: this.space, - programId: this.programId, - }), - ); - - return transaction.add( - this.initializeAccount({ - votePubkey: params.votePubkey, - nodePubkey: params.voteInit.nodePubkey, - voteInit: params.voteInit, - }), - ); - } - - /** - * Generate a transaction that authorizes a new Voter or Withdrawer on the Vote account. - */ - static authorize(params: AuthorizeVoteParams): Transaction { - const { - votePubkey, - authorizedPubkey, - newAuthorizedPubkey, - voteAuthorizationType, - } = params; - - const type = VOTE_INSTRUCTION_LAYOUTS.Authorize; - const data = encodeData(type, { - newAuthorized: toBuffer(newAuthorizedPubkey.toBuffer()), - voteAuthorizationType: voteAuthorizationType.index, - }); - - const keys = [ - {pubkey: votePubkey, isSigner: false, isWritable: true}, - {pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false}, - {pubkey: authorizedPubkey, isSigner: true, isWritable: false}, - ]; - - return new Transaction().add({ - keys, - programId: this.programId, - data, - }); - } - - /** - * Generate a transaction that authorizes a new Voter or Withdrawer on the Vote account - * where the current Voter or Withdrawer authority is a derived key. - */ - static authorizeWithSeed(params: AuthorizeVoteWithSeedParams): Transaction { - const { - currentAuthorityDerivedKeyBasePubkey, - currentAuthorityDerivedKeyOwnerPubkey, - currentAuthorityDerivedKeySeed, - newAuthorizedPubkey, - voteAuthorizationType, - votePubkey, - } = params; - - const type = VOTE_INSTRUCTION_LAYOUTS.AuthorizeWithSeed; - const data = encodeData(type, { - voteAuthorizeWithSeedArgs: { - currentAuthorityDerivedKeyOwnerPubkey: toBuffer( - currentAuthorityDerivedKeyOwnerPubkey.toBuffer(), - ), - currentAuthorityDerivedKeySeed: currentAuthorityDerivedKeySeed, - newAuthorized: toBuffer(newAuthorizedPubkey.toBuffer()), - voteAuthorizationType: voteAuthorizationType.index, - }, - }); - - const keys = [ - {pubkey: votePubkey, isSigner: false, isWritable: true}, - {pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false}, - { - pubkey: currentAuthorityDerivedKeyBasePubkey, - isSigner: true, - isWritable: false, - }, - ]; - - return new Transaction().add({ - keys, - programId: this.programId, - data, - }); - } - - /** - * Generate a transaction to withdraw from a Vote account. - */ - static withdraw(params: WithdrawFromVoteAccountParams): Transaction { - const {votePubkey, authorizedWithdrawerPubkey, lamports, toPubkey} = params; - const type = VOTE_INSTRUCTION_LAYOUTS.Withdraw; - const data = encodeData(type, {lamports}); - - const keys = [ - {pubkey: votePubkey, isSigner: false, isWritable: true}, - {pubkey: toPubkey, isSigner: false, isWritable: true}, - {pubkey: authorizedWithdrawerPubkey, isSigner: true, isWritable: false}, - ]; - - return new Transaction().add({ - keys, - programId: this.programId, - data, - }); - } - - /** - * Generate a transaction to withdraw safely from a Vote account. - * - * This function was created as a safeguard for vote accounts running validators, `safeWithdraw` - * checks that the withdraw amount will not exceed the specified balance while leaving enough left - * to cover rent. If you wish to close the vote account by withdrawing the full amount, call the - * `withdraw` method directly. - */ - static safeWithdraw( - params: WithdrawFromVoteAccountParams, - currentVoteAccountBalance: number, - rentExemptMinimum: number, - ): Transaction { - if (params.lamports > currentVoteAccountBalance - rentExemptMinimum) { - throw new Error( - 'Withdraw will leave vote account with insufficient funds.', - ); - } - return VoteProgram.withdraw(params); - } - - /** - * Generate a transaction to update the validator identity (node pubkey) of a Vote account. - */ - static updateValidatorIdentity( - params: UpdateValidatorIdentityParams, - ): Transaction { - const {votePubkey, authorizedWithdrawerPubkey, nodePubkey} = params; - const type = VOTE_INSTRUCTION_LAYOUTS.UpdateValidatorIdentity; - const data = encodeData(type); - - const keys = [ - {pubkey: votePubkey, isSigner: false, isWritable: true}, - {pubkey: nodePubkey, isSigner: true, isWritable: false}, - {pubkey: authorizedWithdrawerPubkey, isSigner: true, isWritable: false}, - ]; - - return new Transaction().add({ - keys, - programId: this.programId, - data, - }); - } -} diff --git a/packages/library-legacy/src/publickey.ts b/packages/library-legacy/src/publickey.ts deleted file mode 100644 index 4d17ae68ca9c..000000000000 --- a/packages/library-legacy/src/publickey.ts +++ /dev/null @@ -1,259 +0,0 @@ -import BN from 'bn.js'; -import bs58 from 'bs58'; -import {Buffer} from 'buffer'; -import {sha256} from '@noble/hashes/sha256'; - -import {isOnCurve} from './utils/ed25519'; -import {Struct, SOLANA_SCHEMA} from './utils/borsh-schema'; -import {toBuffer} from './utils/to-buffer'; - -/** - * Maximum length of derived pubkey seed - */ -export const MAX_SEED_LENGTH = 32; - -/** - * Size of public key in bytes - */ -export const PUBLIC_KEY_LENGTH = 32; - -/** - * Value to be converted into public key - */ -export type PublicKeyInitData = - | number - | string - | Uint8Array - | Array - | PublicKeyData; - -/** - * JSON object representation of PublicKey class - */ -export type PublicKeyData = { - /** @internal */ - _bn: BN; -}; - -function isPublicKeyData(value: PublicKeyInitData): value is PublicKeyData { - return (value as PublicKeyData)._bn !== undefined; -} - -// local counter used by PublicKey.unique() -let uniquePublicKeyCounter = 1; - -/** - * A public key - */ -export class PublicKey extends Struct { - /** @internal */ - _bn: BN; - - /** - * Create a new PublicKey object - * @param value ed25519 public key as buffer or base-58 encoded string - */ - constructor(value: PublicKeyInitData) { - super({}); - if (isPublicKeyData(value)) { - this._bn = value._bn; - } else { - if (typeof value === 'string') { - // assume base 58 encoding by default - const decoded = bs58.decode(value); - if (decoded.length != PUBLIC_KEY_LENGTH) { - throw new Error(`Invalid public key input`); - } - this._bn = new BN(decoded); - } else { - this._bn = new BN(value); - } - - if (this._bn.byteLength() > PUBLIC_KEY_LENGTH) { - throw new Error(`Invalid public key input`); - } - } - } - - /** - * Returns a unique PublicKey for tests and benchmarks using a counter - */ - static unique(): PublicKey { - const key = new PublicKey(uniquePublicKeyCounter); - uniquePublicKeyCounter += 1; - return new PublicKey(key.toBuffer()); - } - - /** - * Default public key value. The base58-encoded string representation is all ones (as seen below) - * The underlying BN number is 32 bytes that are all zeros - */ - static default: PublicKey = new PublicKey('11111111111111111111111111111111'); - - /** - * Checks if two publicKeys are equal - */ - equals(publicKey: PublicKey): boolean { - return this._bn.eq(publicKey._bn); - } - - /** - * Return the base-58 representation of the public key - */ - toBase58(): string { - return bs58.encode(this.toBytes()); - } - - toJSON(): string { - return this.toBase58(); - } - - /** - * Return the byte array representation of the public key in big endian - */ - toBytes(): Uint8Array { - const buf = this.toBuffer(); - return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength); - } - - /** - * Return the Buffer representation of the public key in big endian - */ - toBuffer(): Buffer { - const b = this._bn.toArrayLike(Buffer); - if (b.length === PUBLIC_KEY_LENGTH) { - return b; - } - - const zeroPad = Buffer.alloc(32); - b.copy(zeroPad, 32 - b.length); - return zeroPad; - } - - get [Symbol.toStringTag](): string { - return `PublicKey(${this.toString()})`; - } - - /** - * Return the base-58 representation of the public key - */ - toString(): string { - return this.toBase58(); - } - - /** - * Derive a public key from another key, a seed, and a program ID. - * The program ID will also serve as the owner of the public key, giving - * it permission to write data to the account. - */ - /* eslint-disable require-await */ - static async createWithSeed( - fromPublicKey: PublicKey, - seed: string, - programId: PublicKey, - ): Promise { - const buffer = Buffer.concat([ - fromPublicKey.toBuffer(), - Buffer.from(seed), - programId.toBuffer(), - ]); - const publicKeyBytes = sha256(buffer); - return new PublicKey(publicKeyBytes); - } - - /** - * Derive a program address from seeds and a program ID. - */ - /* eslint-disable require-await */ - static createProgramAddressSync( - seeds: Array, - programId: PublicKey, - ): PublicKey { - let buffer = Buffer.alloc(0); - seeds.forEach(function (seed) { - if (seed.length > MAX_SEED_LENGTH) { - throw new TypeError(`Max seed length exceeded`); - } - buffer = Buffer.concat([buffer, toBuffer(seed)]); - }); - buffer = Buffer.concat([ - buffer, - programId.toBuffer(), - Buffer.from('ProgramDerivedAddress'), - ]); - const publicKeyBytes = sha256(buffer); - if (isOnCurve(publicKeyBytes)) { - throw new Error(`Invalid seeds, address must fall off the curve`); - } - return new PublicKey(publicKeyBytes); - } - - /** - * Async version of createProgramAddressSync - * For backwards compatibility - * - * @deprecated Use {@link createProgramAddressSync} instead - */ - /* eslint-disable require-await */ - static async createProgramAddress( - seeds: Array, - programId: PublicKey, - ): Promise { - return this.createProgramAddressSync(seeds, programId); - } - - /** - * Find a valid program address - * - * Valid program addresses must fall off the ed25519 curve. This function - * iterates a nonce until it finds one that when combined with the seeds - * results in a valid program address. - */ - static findProgramAddressSync( - seeds: Array, - programId: PublicKey, - ): [PublicKey, number] { - let nonce = 255; - let address; - while (nonce != 0) { - try { - const seedsWithNonce = seeds.concat(Buffer.from([nonce])); - address = this.createProgramAddressSync(seedsWithNonce, programId); - } catch (err) { - if (err instanceof TypeError) { - throw err; - } - nonce--; - continue; - } - return [address, nonce]; - } - throw new Error(`Unable to find a viable program address nonce`); - } - - /** - * Async version of findProgramAddressSync - * For backwards compatibility - * - * @deprecated Use {@link findProgramAddressSync} instead - */ - static async findProgramAddress( - seeds: Array, - programId: PublicKey, - ): Promise<[PublicKey, number]> { - return this.findProgramAddressSync(seeds, programId); - } - - /** - * Check that a pubkey is on the ed25519 curve. - */ - static isOnCurve(pubkeyData: PublicKeyInitData): boolean { - const pubkey = new PublicKey(pubkeyData); - return isOnCurve(pubkey.toBytes()); - } -} - -SOLANA_SCHEMA.set(PublicKey, { - kind: 'struct', - fields: [['_bn', 'u256']], -}); diff --git a/packages/library-legacy/src/rpc-websocket.ts b/packages/library-legacy/src/rpc-websocket.ts deleted file mode 100644 index 5c5863866ea7..000000000000 --- a/packages/library-legacy/src/rpc-websocket.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { - CommonClient, - ICommonWebSocket, - IWSClientAdditionalOptions, - NodeWebSocketType, - NodeWebSocketTypeOptions, - WebSocket as createRpc, -} from 'rpc-websockets'; - -interface IHasReadyState { - readyState: WebSocket['readyState']; -} - -export default class RpcWebSocketClient extends CommonClient { - private underlyingSocket: IHasReadyState | undefined; - constructor( - address?: string, - options?: IWSClientAdditionalOptions & NodeWebSocketTypeOptions, - generate_request_id?: ( - method: string, - params: object | Array, - ) => number, - ) { - const webSocketFactory = (url: string) => { - const rpc = createRpc(url, { - autoconnect: true, - max_reconnects: 5, - reconnect: true, - reconnect_interval: 1000, - ...options, - }); - if ('socket' in rpc) { - this.underlyingSocket = rpc.socket as ReturnType; - } else { - this.underlyingSocket = rpc as NodeWebSocketType; - } - return rpc as ICommonWebSocket; - }; - super(webSocketFactory, address, options, generate_request_id); - } - call( - ...args: Parameters - ): ReturnType { - const readyState = this.underlyingSocket?.readyState; - if (readyState === 1 /* WebSocket.OPEN */) { - return super.call(...args); - } - return Promise.reject( - new Error( - 'Tried to call a JSON-RPC method `' + - args[0] + - '` but the socket was not `CONNECTING` or `OPEN` (`readyState` was ' + - readyState + - ')', - ), - ); - } - notify( - ...args: Parameters - ): ReturnType { - const readyState = this.underlyingSocket?.readyState; - if (readyState === 1 /* WebSocket.OPEN */) { - return super.notify(...args); - } - return Promise.reject( - new Error( - 'Tried to send a JSON-RPC notification `' + - args[0] + - '` but the socket was not `CONNECTING` or `OPEN` (`readyState` was ' + - readyState + - ')', - ), - ); - } -} diff --git a/packages/library-legacy/src/sysvar.ts b/packages/library-legacy/src/sysvar.ts deleted file mode 100644 index d32725ba7d85..000000000000 --- a/packages/library-legacy/src/sysvar.ts +++ /dev/null @@ -1,37 +0,0 @@ -import {PublicKey} from './publickey'; - -export const SYSVAR_CLOCK_PUBKEY = new PublicKey( - 'SysvarC1ock11111111111111111111111111111111', -); - -export const SYSVAR_EPOCH_SCHEDULE_PUBKEY = new PublicKey( - 'SysvarEpochSchedu1e111111111111111111111111', -); - -export const SYSVAR_INSTRUCTIONS_PUBKEY = new PublicKey( - 'Sysvar1nstructions1111111111111111111111111', -); - -export const SYSVAR_RECENT_BLOCKHASHES_PUBKEY = new PublicKey( - 'SysvarRecentB1ockHashes11111111111111111111', -); - -export const SYSVAR_RENT_PUBKEY = new PublicKey( - 'SysvarRent111111111111111111111111111111111', -); - -export const SYSVAR_REWARDS_PUBKEY = new PublicKey( - 'SysvarRewards111111111111111111111111111111', -); - -export const SYSVAR_SLOT_HASHES_PUBKEY = new PublicKey( - 'SysvarS1otHashes111111111111111111111111111', -); - -export const SYSVAR_SLOT_HISTORY_PUBKEY = new PublicKey( - 'SysvarS1otHistory11111111111111111111111111', -); - -export const SYSVAR_STAKE_HISTORY_PUBKEY = new PublicKey( - 'SysvarStakeHistory1111111111111111111111111', -); diff --git a/packages/library-legacy/src/timing.ts b/packages/library-legacy/src/timing.ts deleted file mode 100644 index 6ba998717e02..000000000000 --- a/packages/library-legacy/src/timing.ts +++ /dev/null @@ -1,23 +0,0 @@ -// TODO: These constants should be removed in favor of reading them out of a -// Syscall account - -/** - * @internal - */ -export const NUM_TICKS_PER_SECOND = 160; - -/** - * @internal - */ -export const DEFAULT_TICKS_PER_SLOT = 64; - -/** - * @internal - */ -export const NUM_SLOTS_PER_SECOND = - NUM_TICKS_PER_SECOND / DEFAULT_TICKS_PER_SLOT; - -/** - * @internal - */ -export const MS_PER_SLOT = 1000 / NUM_SLOTS_PER_SECOND; diff --git a/packages/library-legacy/src/transaction/constants.ts b/packages/library-legacy/src/transaction/constants.ts deleted file mode 100644 index 075337e8dce1..000000000000 --- a/packages/library-legacy/src/transaction/constants.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Maximum over-the-wire size of a Transaction - * - * 1280 is IPv6 minimum MTU - * 40 bytes is the size of the IPv6 header - * 8 bytes is the size of the fragment header - */ -export const PACKET_DATA_SIZE = 1280 - 40 - 8; - -export const VERSION_PREFIX_MASK = 0x7f; - -export const SIGNATURE_LENGTH_IN_BYTES = 64; diff --git a/packages/library-legacy/src/transaction/expiry-custom-errors.ts b/packages/library-legacy/src/transaction/expiry-custom-errors.ts deleted file mode 100644 index 78c5f4dfe24c..000000000000 --- a/packages/library-legacy/src/transaction/expiry-custom-errors.ts +++ /dev/null @@ -1,48 +0,0 @@ -export class TransactionExpiredBlockheightExceededError extends Error { - signature: string; - - constructor(signature: string) { - super(`Signature ${signature} has expired: block height exceeded.`); - this.signature = signature; - } -} - -Object.defineProperty( - TransactionExpiredBlockheightExceededError.prototype, - 'name', - { - value: 'TransactionExpiredBlockheightExceededError', - }, -); - -export class TransactionExpiredTimeoutError extends Error { - signature: string; - - constructor(signature: string, timeoutSeconds: number) { - super( - `Transaction was not confirmed in ${timeoutSeconds.toFixed( - 2, - )} seconds. It is ` + - 'unknown if it succeeded or failed. Check signature ' + - `${signature} using the Solana Explorer or CLI tools.`, - ); - this.signature = signature; - } -} - -Object.defineProperty(TransactionExpiredTimeoutError.prototype, 'name', { - value: 'TransactionExpiredTimeoutError', -}); - -export class TransactionExpiredNonceInvalidError extends Error { - signature: string; - - constructor(signature: string) { - super(`Signature ${signature} has expired: the nonce is no longer valid.`); - this.signature = signature; - } -} - -Object.defineProperty(TransactionExpiredNonceInvalidError.prototype, 'name', { - value: 'TransactionExpiredNonceInvalidError', -}); diff --git a/packages/library-legacy/src/transaction/index.ts b/packages/library-legacy/src/transaction/index.ts deleted file mode 100644 index 88d1cb1700ea..000000000000 --- a/packages/library-legacy/src/transaction/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from './constants'; -export * from './expiry-custom-errors'; -export * from './legacy'; -export * from './message'; -export * from './versioned'; diff --git a/packages/library-legacy/src/transaction/legacy.ts b/packages/library-legacy/src/transaction/legacy.ts deleted file mode 100644 index 3dd3810673d5..000000000000 --- a/packages/library-legacy/src/transaction/legacy.ts +++ /dev/null @@ -1,970 +0,0 @@ -import bs58 from 'bs58'; -import {Buffer} from 'buffer'; - -import {PACKET_DATA_SIZE, SIGNATURE_LENGTH_IN_BYTES} from './constants'; -import {Connection} from '../connection'; -import {Message} from '../message'; -import {PublicKey} from '../publickey'; -import * as shortvec from '../utils/shortvec-encoding'; -import {toBuffer} from '../utils/to-buffer'; -import invariant from '../utils/assert'; -import type {Signer} from '../keypair'; -import type {Blockhash} from '../blockhash'; -import type {CompiledInstruction} from '../message'; -import {sign, verify} from '../utils/ed25519'; -import {guardedSplice} from '../utils/guarded-array-utils'; - -/** @internal */ -type MessageSignednessErrors = { - invalid?: PublicKey[]; - missing?: PublicKey[]; -}; - -/** - * Transaction signature as base-58 encoded string - */ -export type TransactionSignature = string; - -export const enum TransactionStatus { - BLOCKHEIGHT_EXCEEDED, - PROCESSED, - TIMED_OUT, - NONCE_INVALID, -} - -/** - * Default (empty) signature - */ -const DEFAULT_SIGNATURE = Buffer.alloc(SIGNATURE_LENGTH_IN_BYTES).fill(0); - -/** - * Account metadata used to define instructions - */ -export type AccountMeta = { - /** An account's public key */ - pubkey: PublicKey; - /** True if an instruction requires a transaction signature matching `pubkey` */ - isSigner: boolean; - /** True if the `pubkey` can be loaded as a read-write account. */ - isWritable: boolean; -}; - -/** - * List of TransactionInstruction object fields that may be initialized at construction - */ -export type TransactionInstructionCtorFields = { - keys: Array; - programId: PublicKey; - data?: Buffer; -}; - -/** - * Configuration object for Transaction.serialize() - */ -export type SerializeConfig = { - /** Require all transaction signatures be present (default: true) */ - requireAllSignatures?: boolean; - /** Verify provided signatures (default: true) */ - verifySignatures?: boolean; -}; - -/** - * @internal - */ -export interface TransactionInstructionJSON { - keys: { - pubkey: string; - isSigner: boolean; - isWritable: boolean; - }[]; - programId: string; - data: number[]; -} - -/** - * Transaction Instruction class - */ -export class TransactionInstruction { - /** - * Public keys to include in this transaction - * Boolean represents whether this pubkey needs to sign the transaction - */ - keys: Array; - - /** - * Program Id to execute - */ - programId: PublicKey; - - /** - * Program input - */ - data: Buffer = Buffer.alloc(0); - - constructor(opts: TransactionInstructionCtorFields) { - this.programId = opts.programId; - this.keys = opts.keys; - if (opts.data) { - this.data = opts.data; - } - } - - /** - * @internal - */ - toJSON(): TransactionInstructionJSON { - return { - keys: this.keys.map(({pubkey, isSigner, isWritable}) => ({ - pubkey: pubkey.toJSON(), - isSigner, - isWritable, - })), - programId: this.programId.toJSON(), - data: [...this.data], - }; - } -} - -/** - * Pair of signature and corresponding public key - */ -export type SignaturePubkeyPair = { - signature: Buffer | null; - publicKey: PublicKey; -}; - -/** - * List of Transaction object fields that may be initialized at construction - */ -export type TransactionCtorFields_DEPRECATED = { - /** Optional nonce information used for offline nonce'd transactions */ - nonceInfo?: NonceInformation | null; - /** The transaction fee payer */ - feePayer?: PublicKey | null; - /** One or more signatures */ - signatures?: Array; - /** A recent blockhash */ - recentBlockhash?: Blockhash; -}; - -// For backward compatibility; an unfortunate consequence of being -// forced to over-export types by the documentation generator. -// See https://github.com/solana-labs/solana/pull/25820 -export type TransactionCtorFields = TransactionCtorFields_DEPRECATED; - -/** - * Blockhash-based transactions have a lifetime that are defined by - * the blockhash they include. Any transaction whose blockhash is - * too old will be rejected. - */ -export type TransactionBlockhashCtor = { - /** The transaction fee payer */ - feePayer?: PublicKey | null; - /** One or more signatures */ - signatures?: Array; - /** A recent blockhash */ - blockhash: Blockhash; - /** the last block chain can advance to before tx is declared expired */ - lastValidBlockHeight: number; -}; - -/** - * Use these options to construct a durable nonce transaction. - */ -export type TransactionNonceCtor = { - /** The transaction fee payer */ - feePayer?: PublicKey | null; - minContextSlot: number; - nonceInfo: NonceInformation; - /** One or more signatures */ - signatures?: Array; -}; - -/** - * Nonce information to be used to build an offline Transaction. - */ -export type NonceInformation = { - /** The current blockhash stored in the nonce */ - nonce: Blockhash; - /** AdvanceNonceAccount Instruction */ - nonceInstruction: TransactionInstruction; -}; - -/** - * @internal - */ -export interface TransactionJSON { - recentBlockhash: string | null; - feePayer: string | null; - nonceInfo: { - nonce: string; - nonceInstruction: TransactionInstructionJSON; - } | null; - instructions: TransactionInstructionJSON[]; - signers: string[]; -} - -/** - * Transaction class - */ -export class Transaction { - /** - * Signatures for the transaction. Typically created by invoking the - * `sign()` method - */ - signatures: Array = []; - - /** - * The first (payer) Transaction signature - * - * @returns {Buffer | null} Buffer of payer's signature - */ - get signature(): Buffer | null { - if (this.signatures.length > 0) { - return this.signatures[0].signature; - } - return null; - } - - /** - * The transaction fee payer - */ - feePayer?: PublicKey; - - /** - * The instructions to atomically execute - */ - instructions: Array = []; - - /** - * A recent transaction id. Must be populated by the caller - */ - recentBlockhash?: Blockhash; - - /** - * the last block chain can advance to before tx is declared expired - * */ - lastValidBlockHeight?: number; - - /** - * Optional Nonce information. If populated, transaction will use a durable - * Nonce hash instead of a recentBlockhash. Must be populated by the caller - */ - nonceInfo?: NonceInformation; - - /** - * If this is a nonce transaction this represents the minimum slot from which - * to evaluate if the nonce has advanced when attempting to confirm the - * transaction. This protects against a case where the transaction confirmation - * logic loads the nonce account from an old slot and assumes the mismatch in - * nonce value implies that the nonce has been advanced. - */ - minNonceContextSlot?: number; - - /** - * @internal - */ - _message?: Message; - - /** - * @internal - */ - _json?: TransactionJSON; - - // Construct a transaction with a blockhash and lastValidBlockHeight - constructor(opts?: TransactionBlockhashCtor); - - // Construct a transaction using a durable nonce - constructor(opts?: TransactionNonceCtor); - - /** - * @deprecated `TransactionCtorFields` has been deprecated and will be removed in a future version. - * Please supply a `TransactionBlockhashCtor` instead. - */ - constructor(opts?: TransactionCtorFields_DEPRECATED); - - /** - * Construct an empty Transaction - */ - constructor( - opts?: - | TransactionBlockhashCtor - | TransactionNonceCtor - | TransactionCtorFields_DEPRECATED, - ) { - if (!opts) { - return; - } - if (opts.feePayer) { - this.feePayer = opts.feePayer; - } - if (opts.signatures) { - this.signatures = opts.signatures; - } - if (Object.prototype.hasOwnProperty.call(opts, 'nonceInfo')) { - const {minContextSlot, nonceInfo} = opts as TransactionNonceCtor; - this.minNonceContextSlot = minContextSlot; - this.nonceInfo = nonceInfo; - } else if ( - Object.prototype.hasOwnProperty.call(opts, 'lastValidBlockHeight') - ) { - const {blockhash, lastValidBlockHeight} = - opts as TransactionBlockhashCtor; - this.recentBlockhash = blockhash; - this.lastValidBlockHeight = lastValidBlockHeight; - } else { - const {recentBlockhash, nonceInfo} = - opts as TransactionCtorFields_DEPRECATED; - if (nonceInfo) { - this.nonceInfo = nonceInfo; - } - this.recentBlockhash = recentBlockhash; - } - } - - /** - * @internal - */ - toJSON(): TransactionJSON { - return { - recentBlockhash: this.recentBlockhash || null, - feePayer: this.feePayer ? this.feePayer.toJSON() : null, - nonceInfo: this.nonceInfo - ? { - nonce: this.nonceInfo.nonce, - nonceInstruction: this.nonceInfo.nonceInstruction.toJSON(), - } - : null, - instructions: this.instructions.map(instruction => instruction.toJSON()), - signers: this.signatures.map(({publicKey}) => { - return publicKey.toJSON(); - }), - }; - } - - /** - * Add one or more instructions to this Transaction - * - * @param {Array< Transaction | TransactionInstruction | TransactionInstructionCtorFields >} items - Instructions to add to the Transaction - */ - add( - ...items: Array< - Transaction | TransactionInstruction | TransactionInstructionCtorFields - > - ): Transaction { - if (items.length === 0) { - throw new Error('No instructions'); - } - - items.forEach((item: any) => { - if ('instructions' in item) { - this.instructions = this.instructions.concat(item.instructions); - } else if ('data' in item && 'programId' in item && 'keys' in item) { - this.instructions.push(item); - } else { - this.instructions.push(new TransactionInstruction(item)); - } - }); - return this; - } - - /** - * Compile transaction data - */ - compileMessage(): Message { - if ( - this._message && - JSON.stringify(this.toJSON()) === JSON.stringify(this._json) - ) { - return this._message; - } - - let recentBlockhash; - let instructions: TransactionInstruction[]; - if (this.nonceInfo) { - recentBlockhash = this.nonceInfo.nonce; - if (this.instructions[0] != this.nonceInfo.nonceInstruction) { - instructions = [this.nonceInfo.nonceInstruction, ...this.instructions]; - } else { - instructions = this.instructions; - } - } else { - recentBlockhash = this.recentBlockhash; - instructions = this.instructions; - } - if (!recentBlockhash) { - throw new Error('Transaction recentBlockhash required'); - } - - if (instructions.length < 1) { - console.warn('No instructions provided'); - } - - let feePayer: PublicKey; - if (this.feePayer) { - feePayer = this.feePayer; - } else if (this.signatures.length > 0 && this.signatures[0].publicKey) { - // Use implicit fee payer - feePayer = this.signatures[0].publicKey; - } else { - throw new Error('Transaction fee payer required'); - } - - for (let i = 0; i < instructions.length; i++) { - if (instructions[i].programId === undefined) { - throw new Error( - `Transaction instruction index ${i} has undefined program id`, - ); - } - } - - const programIds: string[] = []; - const accountMetas: AccountMeta[] = []; - instructions.forEach(instruction => { - instruction.keys.forEach(accountMeta => { - accountMetas.push({...accountMeta}); - }); - - const programId = instruction.programId.toString(); - if (!programIds.includes(programId)) { - programIds.push(programId); - } - }); - - // Append programID account metas - programIds.forEach(programId => { - accountMetas.push({ - pubkey: new PublicKey(programId), - isSigner: false, - isWritable: false, - }); - }); - - // Cull duplicate account metas - const uniqueMetas: AccountMeta[] = []; - accountMetas.forEach(accountMeta => { - const pubkeyString = accountMeta.pubkey.toString(); - const uniqueIndex = uniqueMetas.findIndex(x => { - return x.pubkey.toString() === pubkeyString; - }); - if (uniqueIndex > -1) { - uniqueMetas[uniqueIndex].isWritable = - uniqueMetas[uniqueIndex].isWritable || accountMeta.isWritable; - uniqueMetas[uniqueIndex].isSigner = - uniqueMetas[uniqueIndex].isSigner || accountMeta.isSigner; - } else { - uniqueMetas.push(accountMeta); - } - }); - - // Sort. Prioritizing first by signer, then by writable - uniqueMetas.sort(function (x, y) { - if (x.isSigner !== y.isSigner) { - // Signers always come before non-signers - return x.isSigner ? -1 : 1; - } - if (x.isWritable !== y.isWritable) { - // Writable accounts always come before read-only accounts - return x.isWritable ? -1 : 1; - } - // Otherwise, sort by pubkey, stringwise. - const options = { - localeMatcher: 'best fit', - usage: 'sort', - sensitivity: 'variant', - ignorePunctuation: false, - numeric: false, - caseFirst: 'lower', - } as Intl.CollatorOptions; - return x.pubkey - .toBase58() - .localeCompare(y.pubkey.toBase58(), 'en', options); - }); - - // Move fee payer to the front - const feePayerIndex = uniqueMetas.findIndex(x => { - return x.pubkey.equals(feePayer); - }); - if (feePayerIndex > -1) { - const [payerMeta] = uniqueMetas.splice(feePayerIndex, 1); - payerMeta.isSigner = true; - payerMeta.isWritable = true; - uniqueMetas.unshift(payerMeta); - } else { - uniqueMetas.unshift({ - pubkey: feePayer, - isSigner: true, - isWritable: true, - }); - } - - // Disallow unknown signers - for (const signature of this.signatures) { - const uniqueIndex = uniqueMetas.findIndex(x => { - return x.pubkey.equals(signature.publicKey); - }); - if (uniqueIndex > -1) { - if (!uniqueMetas[uniqueIndex].isSigner) { - uniqueMetas[uniqueIndex].isSigner = true; - console.warn( - 'Transaction references a signature that is unnecessary, ' + - 'only the fee payer and instruction signer accounts should sign a transaction. ' + - 'This behavior is deprecated and will throw an error in the next major version release.', - ); - } - } else { - throw new Error(`unknown signer: ${signature.publicKey.toString()}`); - } - } - - let numRequiredSignatures = 0; - let numReadonlySignedAccounts = 0; - let numReadonlyUnsignedAccounts = 0; - - // Split out signing from non-signing keys and count header values - const signedKeys: string[] = []; - const unsignedKeys: string[] = []; - uniqueMetas.forEach(({pubkey, isSigner, isWritable}) => { - if (isSigner) { - signedKeys.push(pubkey.toString()); - numRequiredSignatures += 1; - if (!isWritable) { - numReadonlySignedAccounts += 1; - } - } else { - unsignedKeys.push(pubkey.toString()); - if (!isWritable) { - numReadonlyUnsignedAccounts += 1; - } - } - }); - - const accountKeys = signedKeys.concat(unsignedKeys); - const compiledInstructions: CompiledInstruction[] = instructions.map( - instruction => { - const {data, programId} = instruction; - return { - programIdIndex: accountKeys.indexOf(programId.toString()), - accounts: instruction.keys.map(meta => - accountKeys.indexOf(meta.pubkey.toString()), - ), - data: bs58.encode(data), - }; - }, - ); - - compiledInstructions.forEach(instruction => { - invariant(instruction.programIdIndex >= 0); - instruction.accounts.forEach(keyIndex => invariant(keyIndex >= 0)); - }); - - return new Message({ - header: { - numRequiredSignatures, - numReadonlySignedAccounts, - numReadonlyUnsignedAccounts, - }, - accountKeys, - recentBlockhash, - instructions: compiledInstructions, - }); - } - - /** - * @internal - */ - _compile(): Message { - const message = this.compileMessage(); - const signedKeys = message.accountKeys.slice( - 0, - message.header.numRequiredSignatures, - ); - - if (this.signatures.length === signedKeys.length) { - const valid = this.signatures.every((pair, index) => { - return signedKeys[index].equals(pair.publicKey); - }); - - if (valid) return message; - } - - this.signatures = signedKeys.map(publicKey => ({ - signature: null, - publicKey, - })); - - return message; - } - - /** - * Get a buffer of the Transaction data that need to be covered by signatures - */ - serializeMessage(): Buffer { - return this._compile().serialize(); - } - - /** - * Get the estimated fee associated with a transaction - * - * @param {Connection} connection Connection to RPC Endpoint. - * - * @returns {Promise} The estimated fee for the transaction - */ - async getEstimatedFee(connection: Connection): Promise { - return (await connection.getFeeForMessage(this.compileMessage())).value; - } - - /** - * Specify the public keys which will be used to sign the Transaction. - * The first signer will be used as the transaction fee payer account. - * - * Signatures can be added with either `partialSign` or `addSignature` - * - * @deprecated Deprecated since v0.84.0. Only the fee payer needs to be - * specified and it can be set in the Transaction constructor or with the - * `feePayer` property. - */ - setSigners(...signers: Array) { - if (signers.length === 0) { - throw new Error('No signers'); - } - - const seen = new Set(); - this.signatures = signers - .filter(publicKey => { - const key = publicKey.toString(); - if (seen.has(key)) { - return false; - } else { - seen.add(key); - return true; - } - }) - .map(publicKey => ({signature: null, publicKey})); - } - - /** - * Sign the Transaction with the specified signers. Multiple signatures may - * be applied to a Transaction. The first signature is considered "primary" - * and is used identify and confirm transactions. - * - * If the Transaction `feePayer` is not set, the first signer will be used - * as the transaction fee payer account. - * - * Transaction fields should not be modified after the first call to `sign`, - * as doing so may invalidate the signature and cause the Transaction to be - * rejected. - * - * The Transaction must be assigned a valid `recentBlockhash` before invoking this method - * - * @param {Array} signers Array of signers that will sign the transaction - */ - sign(...signers: Array) { - if (signers.length === 0) { - throw new Error('No signers'); - } - - // Dedupe signers - const seen = new Set(); - const uniqueSigners = []; - for (const signer of signers) { - const key = signer.publicKey.toString(); - if (seen.has(key)) { - continue; - } else { - seen.add(key); - uniqueSigners.push(signer); - } - } - - this.signatures = uniqueSigners.map(signer => ({ - signature: null, - publicKey: signer.publicKey, - })); - - const message = this._compile(); - this._partialSign(message, ...uniqueSigners); - } - - /** - * Partially sign a transaction with the specified accounts. All accounts must - * correspond to either the fee payer or a signer account in the transaction - * instructions. - * - * All the caveats from the `sign` method apply to `partialSign` - * - * @param {Array} signers Array of signers that will sign the transaction - */ - partialSign(...signers: Array) { - if (signers.length === 0) { - throw new Error('No signers'); - } - - // Dedupe signers - const seen = new Set(); - const uniqueSigners = []; - for (const signer of signers) { - const key = signer.publicKey.toString(); - if (seen.has(key)) { - continue; - } else { - seen.add(key); - uniqueSigners.push(signer); - } - } - - const message = this._compile(); - this._partialSign(message, ...uniqueSigners); - } - - /** - * @internal - */ - _partialSign(message: Message, ...signers: Array) { - const signData = message.serialize(); - signers.forEach(signer => { - const signature = sign(signData, signer.secretKey); - this._addSignature(signer.publicKey, toBuffer(signature)); - }); - } - - /** - * Add an externally created signature to a transaction. The public key - * must correspond to either the fee payer or a signer account in the transaction - * instructions. - * - * @param {PublicKey} pubkey Public key that will be added to the transaction. - * @param {Buffer} signature An externally created signature to add to the transaction. - */ - addSignature(pubkey: PublicKey, signature: Buffer) { - this._compile(); // Ensure signatures array is populated - this._addSignature(pubkey, signature); - } - - /** - * @internal - */ - _addSignature(pubkey: PublicKey, signature: Buffer) { - invariant(signature.length === 64); - - const index = this.signatures.findIndex(sigpair => - pubkey.equals(sigpair.publicKey), - ); - if (index < 0) { - throw new Error(`unknown signer: ${pubkey.toString()}`); - } - - this.signatures[index].signature = Buffer.from(signature); - } - - /** - * Verify signatures of a Transaction - * Optional parameter specifies if we're expecting a fully signed Transaction or a partially signed one. - * If no boolean is provided, we expect a fully signed Transaction by default. - * - * @param {boolean} [requireAllSignatures=true] Require a fully signed Transaction - */ - verifySignatures(requireAllSignatures: boolean = true): boolean { - const signatureErrors = this._getMessageSignednessErrors( - this.serializeMessage(), - requireAllSignatures, - ); - return !signatureErrors; - } - - /** - * @internal - */ - _getMessageSignednessErrors( - message: Uint8Array, - requireAllSignatures: boolean, - ): MessageSignednessErrors | undefined { - const errors: MessageSignednessErrors = {}; - for (const {signature, publicKey} of this.signatures) { - if (signature === null) { - if (requireAllSignatures) { - (errors.missing ||= []).push(publicKey); - } - } else { - if (!verify(signature, message, publicKey.toBytes())) { - (errors.invalid ||= []).push(publicKey); - } - } - } - return errors.invalid || errors.missing ? errors : undefined; - } - - /** - * Serialize the Transaction in the wire format. - * - * @param {Buffer} [config] Config of transaction. - * - * @returns {Buffer} Signature of transaction in wire format. - */ - serialize(config?: SerializeConfig): Buffer { - const {requireAllSignatures, verifySignatures} = Object.assign( - {requireAllSignatures: true, verifySignatures: true}, - config, - ); - - const signData = this.serializeMessage(); - if (verifySignatures) { - const sigErrors = this._getMessageSignednessErrors( - signData, - requireAllSignatures, - ); - if (sigErrors) { - let errorMessage = 'Signature verification failed.'; - if (sigErrors.invalid) { - errorMessage += `\nInvalid signature for public key${ - sigErrors.invalid.length === 1 ? '' : '(s)' - } [\`${sigErrors.invalid.map(p => p.toBase58()).join('`, `')}\`].`; - } - if (sigErrors.missing) { - errorMessage += `\nMissing signature for public key${ - sigErrors.missing.length === 1 ? '' : '(s)' - } [\`${sigErrors.missing.map(p => p.toBase58()).join('`, `')}\`].`; - } - throw new Error(errorMessage); - } - } - - return this._serialize(signData); - } - - /** - * @internal - */ - _serialize(signData: Buffer): Buffer { - const {signatures} = this; - const signatureCount: number[] = []; - shortvec.encodeLength(signatureCount, signatures.length); - const transactionLength = - signatureCount.length + signatures.length * 64 + signData.length; - const wireTransaction = Buffer.alloc(transactionLength); - invariant(signatures.length < 256); - Buffer.from(signatureCount).copy(wireTransaction, 0); - signatures.forEach(({signature}, index) => { - if (signature !== null) { - invariant(signature.length === 64, `signature has invalid length`); - Buffer.from(signature).copy( - wireTransaction, - signatureCount.length + index * 64, - ); - } - }); - signData.copy( - wireTransaction, - signatureCount.length + signatures.length * 64, - ); - invariant( - wireTransaction.length <= PACKET_DATA_SIZE, - `Transaction too large: ${wireTransaction.length} > ${PACKET_DATA_SIZE}`, - ); - return wireTransaction; - } - - /** - * Deprecated method - * @internal - */ - get keys(): Array { - invariant(this.instructions.length === 1); - return this.instructions[0].keys.map(keyObj => keyObj.pubkey); - } - - /** - * Deprecated method - * @internal - */ - get programId(): PublicKey { - invariant(this.instructions.length === 1); - return this.instructions[0].programId; - } - - /** - * Deprecated method - * @internal - */ - get data(): Buffer { - invariant(this.instructions.length === 1); - return this.instructions[0].data; - } - - /** - * Parse a wire transaction into a Transaction object. - * - * @param {Buffer | Uint8Array | Array} buffer Signature of wire Transaction - * - * @returns {Transaction} Transaction associated with the signature - */ - static from(buffer: Buffer | Uint8Array | Array): Transaction { - // Slice up wire data - let byteArray = [...buffer]; - - const signatureCount = shortvec.decodeLength(byteArray); - let signatures = []; - for (let i = 0; i < signatureCount; i++) { - const signature = guardedSplice(byteArray, 0, SIGNATURE_LENGTH_IN_BYTES); - signatures.push(bs58.encode(Buffer.from(signature))); - } - - return Transaction.populate(Message.from(byteArray), signatures); - } - - /** - * Populate Transaction object from message and signatures - * - * @param {Message} message Message of transaction - * @param {Array} signatures List of signatures to assign to the transaction - * - * @returns {Transaction} The populated Transaction - */ - static populate( - message: Message, - signatures: Array = [], - ): Transaction { - const transaction = new Transaction(); - transaction.recentBlockhash = message.recentBlockhash; - if (message.header.numRequiredSignatures > 0) { - transaction.feePayer = message.accountKeys[0]; - } - signatures.forEach((signature, index) => { - const sigPubkeyPair = { - signature: - signature == bs58.encode(DEFAULT_SIGNATURE) - ? null - : bs58.decode(signature), - publicKey: message.accountKeys[index], - }; - transaction.signatures.push(sigPubkeyPair); - }); - - message.instructions.forEach(instruction => { - const keys = instruction.accounts.map(account => { - const pubkey = message.accountKeys[account]; - return { - pubkey, - isSigner: - transaction.signatures.some( - keyObj => keyObj.publicKey.toString() === pubkey.toString(), - ) || message.isAccountSigner(account), - isWritable: message.isAccountWritable(account), - }; - }); - - transaction.instructions.push( - new TransactionInstruction({ - keys, - programId: message.accountKeys[instruction.programIdIndex], - data: bs58.decode(instruction.data), - }), - ); - }); - - transaction._message = message; - transaction._json = transaction.toJSON(); - - return transaction; - } -} diff --git a/packages/library-legacy/src/transaction/message.ts b/packages/library-legacy/src/transaction/message.ts deleted file mode 100644 index 4f7c738d6286..000000000000 --- a/packages/library-legacy/src/transaction/message.ts +++ /dev/null @@ -1,140 +0,0 @@ -import {AccountKeysFromLookups} from '../message/account-keys'; -import assert from '../utils/assert'; -import {toBuffer} from '../utils/to-buffer'; -import {Blockhash} from '../blockhash'; -import {Message, MessageV0, VersionedMessage} from '../message'; -import {PublicKey} from '../publickey'; -import {AddressLookupTableAccount} from '../programs'; -import {AccountMeta, TransactionInstruction} from './legacy'; - -export type TransactionMessageArgs = { - payerKey: PublicKey; - instructions: Array; - recentBlockhash: Blockhash; -}; - -export type DecompileArgs = - | { - accountKeysFromLookups: AccountKeysFromLookups; - } - | { - addressLookupTableAccounts: AddressLookupTableAccount[]; - }; - -export class TransactionMessage { - payerKey: PublicKey; - instructions: Array; - recentBlockhash: Blockhash; - - constructor(args: TransactionMessageArgs) { - this.payerKey = args.payerKey; - this.instructions = args.instructions; - this.recentBlockhash = args.recentBlockhash; - } - - static decompile( - message: VersionedMessage, - args?: DecompileArgs, - ): TransactionMessage { - const {header, compiledInstructions, recentBlockhash} = message; - - const { - numRequiredSignatures, - numReadonlySignedAccounts, - numReadonlyUnsignedAccounts, - } = header; - - const numWritableSignedAccounts = - numRequiredSignatures - numReadonlySignedAccounts; - assert(numWritableSignedAccounts > 0, 'Message header is invalid'); - - const numWritableUnsignedAccounts = - message.staticAccountKeys.length - - numRequiredSignatures - - numReadonlyUnsignedAccounts; - assert(numWritableUnsignedAccounts >= 0, 'Message header is invalid'); - - const accountKeys = message.getAccountKeys(args); - const payerKey = accountKeys.get(0); - if (payerKey === undefined) { - throw new Error( - 'Failed to decompile message because no account keys were found', - ); - } - - const instructions: TransactionInstruction[] = []; - for (const compiledIx of compiledInstructions) { - const keys: AccountMeta[] = []; - - for (const keyIndex of compiledIx.accountKeyIndexes) { - const pubkey = accountKeys.get(keyIndex); - if (pubkey === undefined) { - throw new Error( - `Failed to find key for account key index ${keyIndex}`, - ); - } - - const isSigner = keyIndex < numRequiredSignatures; - - let isWritable; - if (isSigner) { - isWritable = keyIndex < numWritableSignedAccounts; - } else if (keyIndex < accountKeys.staticAccountKeys.length) { - isWritable = - keyIndex - numRequiredSignatures < numWritableUnsignedAccounts; - } else { - isWritable = - keyIndex - accountKeys.staticAccountKeys.length < - // accountKeysFromLookups cannot be undefined because we already found a pubkey for this index above - accountKeys.accountKeysFromLookups!.writable.length; - } - - keys.push({ - pubkey, - isSigner: keyIndex < header.numRequiredSignatures, - isWritable, - }); - } - - const programId = accountKeys.get(compiledIx.programIdIndex); - if (programId === undefined) { - throw new Error( - `Failed to find program id for program id index ${compiledIx.programIdIndex}`, - ); - } - - instructions.push( - new TransactionInstruction({ - programId, - data: toBuffer(compiledIx.data), - keys, - }), - ); - } - - return new TransactionMessage({ - payerKey, - instructions, - recentBlockhash, - }); - } - - compileToLegacyMessage(): Message { - return Message.compile({ - payerKey: this.payerKey, - recentBlockhash: this.recentBlockhash, - instructions: this.instructions, - }); - } - - compileToV0Message( - addressLookupTableAccounts?: AddressLookupTableAccount[], - ): MessageV0 { - return MessageV0.compile({ - payerKey: this.payerKey, - recentBlockhash: this.recentBlockhash, - instructions: this.instructions, - addressLookupTableAccounts, - }); - } -} diff --git a/packages/library-legacy/src/transaction/versioned.ts b/packages/library-legacy/src/transaction/versioned.ts deleted file mode 100644 index a810beff7986..000000000000 --- a/packages/library-legacy/src/transaction/versioned.ts +++ /dev/null @@ -1,127 +0,0 @@ -import * as BufferLayout from '@solana/buffer-layout'; - -import {Signer} from '../keypair'; -import assert from '../utils/assert'; -import {VersionedMessage} from '../message/versioned'; -import {SIGNATURE_LENGTH_IN_BYTES} from './constants'; -import * as shortvec from '../utils/shortvec-encoding'; -import * as Layout from '../layout'; -import {sign} from '../utils/ed25519'; -import {PublicKey} from '../publickey'; -import {guardedSplice} from '../utils/guarded-array-utils'; - -export type TransactionVersion = 'legacy' | 0; - -/** - * Versioned transaction class - */ -export class VersionedTransaction { - signatures: Array; - message: VersionedMessage; - - get version(): TransactionVersion { - return this.message.version; - } - - constructor(message: VersionedMessage, signatures?: Array) { - if (signatures !== undefined) { - assert( - signatures.length === message.header.numRequiredSignatures, - 'Expected signatures length to be equal to the number of required signatures', - ); - this.signatures = signatures; - } else { - const defaultSignatures = []; - for (let i = 0; i < message.header.numRequiredSignatures; i++) { - defaultSignatures.push(new Uint8Array(SIGNATURE_LENGTH_IN_BYTES)); - } - this.signatures = defaultSignatures; - } - this.message = message; - } - - serialize(): Uint8Array { - const serializedMessage = this.message.serialize(); - - const encodedSignaturesLength = Array(); - shortvec.encodeLength(encodedSignaturesLength, this.signatures.length); - - const transactionLayout = BufferLayout.struct<{ - encodedSignaturesLength: Uint8Array; - signatures: Array; - serializedMessage: Uint8Array; - }>([ - BufferLayout.blob( - encodedSignaturesLength.length, - 'encodedSignaturesLength', - ), - BufferLayout.seq( - Layout.signature(), - this.signatures.length, - 'signatures', - ), - BufferLayout.blob(serializedMessage.length, 'serializedMessage'), - ]); - - const serializedTransaction = new Uint8Array(2048); - const serializedTransactionLength = transactionLayout.encode( - { - encodedSignaturesLength: new Uint8Array(encodedSignaturesLength), - signatures: this.signatures, - serializedMessage, - }, - serializedTransaction, - ); - - return serializedTransaction.slice(0, serializedTransactionLength); - } - - static deserialize(serializedTransaction: Uint8Array): VersionedTransaction { - let byteArray = [...serializedTransaction]; - - const signatures = []; - const signaturesLength = shortvec.decodeLength(byteArray); - for (let i = 0; i < signaturesLength; i++) { - signatures.push( - new Uint8Array(guardedSplice(byteArray, 0, SIGNATURE_LENGTH_IN_BYTES)), - ); - } - - const message = VersionedMessage.deserialize(new Uint8Array(byteArray)); - return new VersionedTransaction(message, signatures); - } - - sign(signers: Array) { - const messageData = this.message.serialize(); - const signerPubkeys = this.message.staticAccountKeys.slice( - 0, - this.message.header.numRequiredSignatures, - ); - for (const signer of signers) { - const signerIndex = signerPubkeys.findIndex(pubkey => - pubkey.equals(signer.publicKey), - ); - assert( - signerIndex >= 0, - `Cannot sign with non signer key ${signer.publicKey.toBase58()}`, - ); - this.signatures[signerIndex] = sign(messageData, signer.secretKey); - } - } - - addSignature(publicKey: PublicKey, signature: Uint8Array) { - assert(signature.byteLength === 64, 'Signature must be 64 bytes long'); - const signerPubkeys = this.message.staticAccountKeys.slice( - 0, - this.message.header.numRequiredSignatures, - ); - const signerIndex = signerPubkeys.findIndex(pubkey => - pubkey.equals(publicKey), - ); - assert( - signerIndex >= 0, - `Can not add signature; \`${publicKey.toBase58()}\` is not required to sign this transaction`, - ); - this.signatures[signerIndex] = signature; - } -} diff --git a/packages/library-legacy/src/utils/assert.ts b/packages/library-legacy/src/utils/assert.ts deleted file mode 100644 index ba9e96c7f8ea..000000000000 --- a/packages/library-legacy/src/utils/assert.ts +++ /dev/null @@ -1,8 +0,0 @@ -export default function ( - condition: unknown, - message?: string, -): asserts condition { - if (!condition) { - throw new Error(message || 'Assertion failed'); - } -} diff --git a/packages/library-legacy/src/utils/bigint.ts b/packages/library-legacy/src/utils/bigint.ts deleted file mode 100644 index ae417f3f9991..000000000000 --- a/packages/library-legacy/src/utils/bigint.ts +++ /dev/null @@ -1,43 +0,0 @@ -import {Buffer} from 'buffer'; -import {blob, Layout} from '@solana/buffer-layout'; -import {toBigIntLE, toBufferLE} from 'bigint-buffer'; - -interface EncodeDecode { - decode(buffer: Buffer, offset?: number): T; - encode(src: T, buffer: Buffer, offset?: number): number; -} - -const encodeDecode = (layout: Layout): EncodeDecode => { - const decode = layout.decode.bind(layout); - const encode = layout.encode.bind(layout); - return {decode, encode}; -}; - -const bigInt = - (length: number) => - (property?: string): Layout => { - const layout = blob(length, property); - const {encode, decode} = encodeDecode(layout); - - const bigIntLayout = layout as Layout as Layout; - - bigIntLayout.decode = (buffer: Buffer, offset: number) => { - const src = decode(buffer, offset); - return toBigIntLE(Buffer.from(src)); - }; - - bigIntLayout.encode = (bigInt: bigint, buffer: Buffer, offset: number) => { - const src = toBufferLE(bigInt, length); - return encode(src, buffer, offset); - }; - - return bigIntLayout; - }; - -export const u64 = bigInt(8); - -export const u128 = bigInt(16); - -export const u192 = bigInt(24); - -export const u256 = bigInt(32); diff --git a/packages/library-legacy/src/utils/borsh-schema.ts b/packages/library-legacy/src/utils/borsh-schema.ts deleted file mode 100644 index cbceb8c2bd8e..000000000000 --- a/packages/library-legacy/src/utils/borsh-schema.ts +++ /dev/null @@ -1,38 +0,0 @@ -import {Buffer} from 'buffer'; -import {serialize, deserialize, deserializeUnchecked} from 'borsh'; - -// Class wrapping a plain object -export class Struct { - constructor(properties: any) { - Object.assign(this, properties); - } - - encode(): Buffer { - return Buffer.from(serialize(SOLANA_SCHEMA, this)); - } - - static decode(data: Buffer): any { - return deserialize(SOLANA_SCHEMA, this, data); - } - - static decodeUnchecked(data: Buffer): any { - return deserializeUnchecked(SOLANA_SCHEMA, this, data); - } -} - -// Class representing a Rust-compatible enum, since enums are only strings or -// numbers in pure JS -export class Enum extends Struct { - enum: string = ''; - constructor(properties: any) { - super(properties); - if (Object.keys(properties).length !== 1) { - throw new Error('Enum can only take single value'); - } - Object.keys(properties).map(key => { - this.enum = key; - }); - } -} - -export const SOLANA_SCHEMA: Map = new Map(); diff --git a/packages/library-legacy/src/utils/cluster.ts b/packages/library-legacy/src/utils/cluster.ts deleted file mode 100644 index 0428bfa6d3c4..000000000000 --- a/packages/library-legacy/src/utils/cluster.ts +++ /dev/null @@ -1,35 +0,0 @@ -const endpoint = { - http: { - devnet: 'http://api.devnet.solana.com', - testnet: 'http://api.testnet.solana.com', - 'mainnet-beta': 'http://api.mainnet-beta.solana.com/', - }, - https: { - devnet: 'https://api.devnet.solana.com', - testnet: 'https://api.testnet.solana.com', - 'mainnet-beta': 'https://api.mainnet-beta.solana.com/', - }, -}; - -export type Cluster = 'devnet' | 'testnet' | 'mainnet-beta'; - -/** - * Retrieves the RPC API URL for the specified cluster - * @param {Cluster} [cluster="devnet"] - The cluster name of the RPC API URL to use. Possible options: 'devnet' | 'testnet' | 'mainnet-beta' - * @param {boolean} [tls="http"] - Use TLS when connecting to cluster. - * - * @returns {string} URL string of the RPC endpoint - */ -export function clusterApiUrl(cluster?: Cluster, tls?: boolean): string { - const key = tls === false ? 'http' : 'https'; - - if (!cluster) { - return endpoint[key]['devnet']; - } - - const url = endpoint[key][cluster]; - if (!url) { - throw new Error(`Unknown ${key} cluster: ${cluster}`); - } - return url; -} diff --git a/packages/library-legacy/src/utils/ed25519.ts b/packages/library-legacy/src/utils/ed25519.ts deleted file mode 100644 index e34626b8c047..000000000000 --- a/packages/library-legacy/src/utils/ed25519.ts +++ /dev/null @@ -1,43 +0,0 @@ -import {ed25519} from '@noble/curves/ed25519'; - -/** - * A 64 byte secret key, the first 32 bytes of which is the - * private scalar and the last 32 bytes is the public key. - * Read more: https://blog.mozilla.org/warner/2011/11/29/ed25519-keys/ - */ -type Ed25519SecretKey = Uint8Array; - -/** - * Ed25519 Keypair - */ -export interface Ed25519Keypair { - publicKey: Uint8Array; - secretKey: Ed25519SecretKey; -} - -export const generatePrivateKey = ed25519.utils.randomPrivateKey; -export const generateKeypair = (): Ed25519Keypair => { - const privateScalar = ed25519.utils.randomPrivateKey(); - const publicKey = getPublicKey(privateScalar); - const secretKey = new Uint8Array(64); - secretKey.set(privateScalar); - secretKey.set(publicKey, 32); - return { - publicKey, - secretKey, - }; -}; -export const getPublicKey = ed25519.getPublicKey; -export function isOnCurve(publicKey: Uint8Array): boolean { - try { - ed25519.ExtendedPoint.fromHex(publicKey); - return true; - } catch { - return false; - } -} -export const sign = ( - message: Parameters[0], - secretKey: Ed25519SecretKey, -) => ed25519.sign(message, secretKey.slice(0, 32)); -export const verify = ed25519.verify; diff --git a/packages/library-legacy/src/utils/guarded-array-utils.ts b/packages/library-legacy/src/utils/guarded-array-utils.ts deleted file mode 100644 index 847f1f9aae43..000000000000 --- a/packages/library-legacy/src/utils/guarded-array-utils.ts +++ /dev/null @@ -1,34 +0,0 @@ -const END_OF_BUFFER_ERROR_MESSAGE = 'Reached end of buffer unexpectedly'; - -/** - * Delegates to `Array#shift`, but throws if the array is zero-length. - */ -export function guardedShift(byteArray: T[]): T { - if (byteArray.length === 0) { - throw new Error(END_OF_BUFFER_ERROR_MESSAGE); - } - return byteArray.shift() as T; -} - -/** - * Delegates to `Array#splice`, but throws if the section being spliced out extends past the end of - * the array. - */ -export function guardedSplice( - byteArray: T[], - ...args: - | [start: number, deleteCount?: number] - | [start: number, deleteCount: number, ...items: T[]] -): T[] { - const [start] = args; - if ( - args.length === 2 // Implies that `deleteCount` was supplied - ? start + (args[1] ?? 0) > byteArray.length - : start >= byteArray.length - ) { - throw new Error(END_OF_BUFFER_ERROR_MESSAGE); - } - return byteArray.splice( - ...(args as Parameters), - ); -} diff --git a/packages/library-legacy/src/utils/index.ts b/packages/library-legacy/src/utils/index.ts deleted file mode 100644 index a026363a703d..000000000000 --- a/packages/library-legacy/src/utils/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from './borsh-schema'; -export * from './cluster'; -export type {Ed25519Keypair} from './ed25519'; -export * from './send-and-confirm-raw-transaction'; -export * from './send-and-confirm-transaction'; diff --git a/packages/library-legacy/src/utils/makeWebsocketUrl.ts b/packages/library-legacy/src/utils/makeWebsocketUrl.ts deleted file mode 100644 index 21c0cfc2cac4..000000000000 --- a/packages/library-legacy/src/utils/makeWebsocketUrl.ts +++ /dev/null @@ -1,26 +0,0 @@ -const URL_RE = /^[^:]+:\/\/([^:[]+|\[[^\]]+\])(:\d+)?(.*)/i; - -export function makeWebsocketUrl(endpoint: string) { - const matches = endpoint.match(URL_RE); - if (matches == null) { - throw TypeError(`Failed to validate endpoint URL \`${endpoint}\``); - } - const [ - _, // eslint-disable-line @typescript-eslint/no-unused-vars - hostish, - portWithColon, - rest, - ] = matches; - const protocol = endpoint.startsWith('https:') ? 'wss:' : 'ws:'; - const startPort = - portWithColon == null ? null : parseInt(portWithColon.slice(1), 10); - const websocketPort = - // Only shift the port by +1 as a convention for ws(s) only if given endpoint - // is explicitly specifying the endpoint port (HTTP-based RPC), assuming - // we're directly trying to connect to agave-validator's ws listening port. - // When the endpoint omits the port, we're connecting to the protocol - // default ports: http(80) or https(443) and it's assumed we're behind a reverse - // proxy which manages WebSocket upgrade and backend port redirection. - startPort == null ? '' : `:${startPort + 1}`; - return `${protocol}//${hostish}${websocketPort}${rest}`; -} diff --git a/packages/library-legacy/src/utils/promise-timeout.ts b/packages/library-legacy/src/utils/promise-timeout.ts deleted file mode 100644 index 1d75969550dd..000000000000 --- a/packages/library-legacy/src/utils/promise-timeout.ts +++ /dev/null @@ -1,14 +0,0 @@ -export function promiseTimeout( - promise: Promise, - timeoutMs: number, -): Promise { - let timeoutId: ReturnType; - const timeoutPromise: Promise = new Promise(resolve => { - timeoutId = setTimeout(() => resolve(null), timeoutMs); - }); - - return Promise.race([promise, timeoutPromise]).then((result: T | null) => { - clearTimeout(timeoutId); - return result; - }); -} diff --git a/packages/library-legacy/src/utils/secp256k1.ts b/packages/library-legacy/src/utils/secp256k1.ts deleted file mode 100644 index fea4efa1f89c..000000000000 --- a/packages/library-legacy/src/utils/secp256k1.ts +++ /dev/null @@ -1,11 +0,0 @@ -import {secp256k1} from '@noble/curves/secp256k1'; - -export const ecdsaSign = ( - msgHash: Parameters[0], - privKey: Parameters[1], -) => { - const signature = secp256k1.sign(msgHash, privKey); - return [signature.toCompactRawBytes(), signature.recovery!] as const; -}; -export const isValidPrivateKey = secp256k1.utils.isValidPrivateKey; -export const publicKeyCreate = secp256k1.getPublicKey; diff --git a/packages/library-legacy/src/utils/send-and-confirm-raw-transaction.ts b/packages/library-legacy/src/utils/send-and-confirm-raw-transaction.ts deleted file mode 100644 index a6d9108ea99e..000000000000 --- a/packages/library-legacy/src/utils/send-and-confirm-raw-transaction.ts +++ /dev/null @@ -1,110 +0,0 @@ -import type {Buffer} from 'buffer'; - -import { - BlockheightBasedTransactionConfirmationStrategy, - Connection, - DurableNonceTransactionConfirmationStrategy, - TransactionConfirmationStrategy, -} from '../connection'; -import type {TransactionSignature} from '../transaction'; -import type {ConfirmOptions} from '../connection'; -import {SendTransactionError} from '../errors'; - -/** - * Send and confirm a raw transaction - * - * If `commitment` option is not specified, defaults to 'max' commitment. - * - * @param {Connection} connection - * @param {Buffer} rawTransaction - * @param {TransactionConfirmationStrategy} confirmationStrategy - * @param {ConfirmOptions} [options] - * @returns {Promise} - */ -export async function sendAndConfirmRawTransaction( - connection: Connection, - rawTransaction: Buffer, - confirmationStrategy: TransactionConfirmationStrategy, - options?: ConfirmOptions, -): Promise; - -/** - * @deprecated Calling `sendAndConfirmRawTransaction()` without a `confirmationStrategy` - * is no longer supported and will be removed in a future version. - */ -// eslint-disable-next-line no-redeclare -export async function sendAndConfirmRawTransaction( - connection: Connection, - rawTransaction: Buffer, - options?: ConfirmOptions, -): Promise; - -// eslint-disable-next-line no-redeclare -export async function sendAndConfirmRawTransaction( - connection: Connection, - rawTransaction: Buffer, - confirmationStrategyOrConfirmOptions: - | TransactionConfirmationStrategy - | ConfirmOptions - | undefined, - maybeConfirmOptions?: ConfirmOptions, -): Promise { - let confirmationStrategy: TransactionConfirmationStrategy | undefined; - let options: ConfirmOptions | undefined; - if ( - confirmationStrategyOrConfirmOptions && - Object.prototype.hasOwnProperty.call( - confirmationStrategyOrConfirmOptions, - 'lastValidBlockHeight', - ) - ) { - confirmationStrategy = - confirmationStrategyOrConfirmOptions as BlockheightBasedTransactionConfirmationStrategy; - options = maybeConfirmOptions; - } else if ( - confirmationStrategyOrConfirmOptions && - Object.prototype.hasOwnProperty.call( - confirmationStrategyOrConfirmOptions, - 'nonceValue', - ) - ) { - confirmationStrategy = - confirmationStrategyOrConfirmOptions as DurableNonceTransactionConfirmationStrategy; - options = maybeConfirmOptions; - } else { - options = confirmationStrategyOrConfirmOptions as - | ConfirmOptions - | undefined; - } - const sendOptions = options && { - skipPreflight: options.skipPreflight, - preflightCommitment: options.preflightCommitment || options.commitment, - minContextSlot: options.minContextSlot, - }; - - const signature = await connection.sendRawTransaction( - rawTransaction, - sendOptions, - ); - - const commitment = options && options.commitment; - const confirmationPromise = confirmationStrategy - ? connection.confirmTransaction(confirmationStrategy, commitment) - : connection.confirmTransaction(signature, commitment); - const status = (await confirmationPromise).value; - - if (status.err) { - if (signature != null) { - throw new SendTransactionError({ - action: sendOptions?.skipPreflight ? 'send' : 'simulate', - signature: signature, - transactionMessage: `Status: (${JSON.stringify(status)})`, - }); - } - throw new Error( - `Raw transaction ${signature} failed (${JSON.stringify(status)})`, - ); - } - - return signature; -} diff --git a/packages/library-legacy/src/utils/send-and-confirm-transaction.ts b/packages/library-legacy/src/utils/send-and-confirm-transaction.ts deleted file mode 100644 index 06e910f56110..000000000000 --- a/packages/library-legacy/src/utils/send-and-confirm-transaction.ts +++ /dev/null @@ -1,106 +0,0 @@ -import {Connection, SignatureResult} from '../connection'; -import {Transaction} from '../transaction'; -import type {ConfirmOptions} from '../connection'; -import type {Signer} from '../keypair'; -import type {TransactionSignature} from '../transaction'; -import {SendTransactionError} from '../errors'; - -/** - * Sign, send and confirm a transaction. - * - * If `commitment` option is not specified, defaults to 'max' commitment. - * - * @param {Connection} connection - * @param {Transaction} transaction - * @param {Array} signers - * @param {ConfirmOptions} [options] - * @returns {Promise} - */ -export async function sendAndConfirmTransaction( - connection: Connection, - transaction: Transaction, - signers: Array, - options?: ConfirmOptions & - Readonly<{ - // A signal that, when aborted, cancels any outstanding transaction confirmation operations - abortSignal?: AbortSignal; - }>, -): Promise { - const sendOptions = options && { - skipPreflight: options.skipPreflight, - preflightCommitment: options.preflightCommitment || options.commitment, - maxRetries: options.maxRetries, - minContextSlot: options.minContextSlot, - }; - - const signature = await connection.sendTransaction( - transaction, - signers, - sendOptions, - ); - - let status: SignatureResult; - if ( - transaction.recentBlockhash != null && - transaction.lastValidBlockHeight != null - ) { - status = ( - await connection.confirmTransaction( - { - abortSignal: options?.abortSignal, - signature: signature, - blockhash: transaction.recentBlockhash, - lastValidBlockHeight: transaction.lastValidBlockHeight, - }, - options && options.commitment, - ) - ).value; - } else if ( - transaction.minNonceContextSlot != null && - transaction.nonceInfo != null - ) { - const {nonceInstruction} = transaction.nonceInfo; - const nonceAccountPubkey = nonceInstruction.keys[0].pubkey; - status = ( - await connection.confirmTransaction( - { - abortSignal: options?.abortSignal, - minContextSlot: transaction.minNonceContextSlot, - nonceAccountPubkey, - nonceValue: transaction.nonceInfo.nonce, - signature, - }, - options && options.commitment, - ) - ).value; - } else { - if (options?.abortSignal != null) { - console.warn( - 'sendAndConfirmTransaction(): A transaction with a deprecated confirmation strategy was ' + - 'supplied along with an `abortSignal`. Only transactions having `lastValidBlockHeight` ' + - 'or a combination of `nonceInfo` and `minNonceContextSlot` are abortable.', - ); - } - status = ( - await connection.confirmTransaction( - signature, - options && options.commitment, - ) - ).value; - } - - if (status.err) { - if (signature != null) { - throw new SendTransactionError({ - action: 'send', - signature: signature, - transactionMessage: `Status: (${JSON.stringify(status)})`, - }); - } - throw new Error( - `Transaction ${signature} failed (${JSON.stringify(status)})`, - ); - } - - return signature; -} diff --git a/packages/library-legacy/src/utils/shortvec-encoding.ts b/packages/library-legacy/src/utils/shortvec-encoding.ts deleted file mode 100644 index ee8c727ee540..000000000000 --- a/packages/library-legacy/src/utils/shortvec-encoding.ts +++ /dev/null @@ -1,28 +0,0 @@ -export function decodeLength(bytes: Array): number { - let len = 0; - let size = 0; - for (;;) { - let elem = bytes.shift() as number; - len |= (elem & 0x7f) << (size * 7); - size += 1; - if ((elem & 0x80) === 0) { - break; - } - } - return len; -} - -export function encodeLength(bytes: Array, len: number) { - let rem_len = len; - for (;;) { - let elem = rem_len & 0x7f; - rem_len >>= 7; - if (rem_len == 0) { - bytes.push(elem); - break; - } else { - elem |= 0x80; - bytes.push(elem); - } - } -} diff --git a/packages/library-legacy/src/utils/sleep.ts b/packages/library-legacy/src/utils/sleep.ts deleted file mode 100644 index 96228f338c8e..000000000000 --- a/packages/library-legacy/src/utils/sleep.ts +++ /dev/null @@ -1,4 +0,0 @@ -// zzz -export function sleep(ms: number): Promise { - return new Promise(resolve => setTimeout(resolve, ms)); -} diff --git a/packages/library-legacy/src/utils/to-buffer.ts b/packages/library-legacy/src/utils/to-buffer.ts deleted file mode 100644 index f9a465aff3a6..000000000000 --- a/packages/library-legacy/src/utils/to-buffer.ts +++ /dev/null @@ -1,11 +0,0 @@ -import {Buffer} from 'buffer'; - -export const toBuffer = (arr: Buffer | Uint8Array | Array): Buffer => { - if (Buffer.isBuffer(arr)) { - return arr; - } else if (arr instanceof Uint8Array) { - return Buffer.from(arr.buffer, arr.byteOffset, arr.byteLength); - } else { - return Buffer.from(arr); - } -}; diff --git a/packages/library-legacy/src/validator-info.ts b/packages/library-legacy/src/validator-info.ts deleted file mode 100644 index 5caf6e5ea32c..000000000000 --- a/packages/library-legacy/src/validator-info.ts +++ /dev/null @@ -1,108 +0,0 @@ -import {Buffer} from 'buffer'; -import { - assert as assertType, - optional, - string, - type as pick, -} from 'superstruct'; - -import * as Layout from './layout'; -import * as shortvec from './utils/shortvec-encoding'; -import {PublicKey, PUBLIC_KEY_LENGTH} from './publickey'; -import {guardedShift, guardedSplice} from './utils/guarded-array-utils'; - -export const VALIDATOR_INFO_KEY = new PublicKey( - 'Va1idator1nfo111111111111111111111111111111', -); - -/** - * @internal - */ -type ConfigKey = { - publicKey: PublicKey; - isSigner: boolean; -}; - -/** - * Info used to identity validators. - */ -export type Info = { - /** validator name */ - name: string; - /** optional, validator website */ - website?: string; - /** optional, extra information the validator chose to share */ - details?: string; - /** optional, validator logo URL */ - iconUrl?: string; - /** optional, used to identify validators on keybase.io */ - keybaseUsername?: string; -}; - -const InfoString = pick({ - name: string(), - website: optional(string()), - details: optional(string()), - iconUrl: optional(string()), - keybaseUsername: optional(string()), -}); - -/** - * ValidatorInfo class - */ -export class ValidatorInfo { - /** - * validator public key - */ - key: PublicKey; - /** - * validator information - */ - info: Info; - - /** - * Construct a valid ValidatorInfo - * - * @param key validator public key - * @param info validator information - */ - constructor(key: PublicKey, info: Info) { - this.key = key; - this.info = info; - } - - /** - * Deserialize ValidatorInfo from the config account data. Exactly two config - * keys are required in the data. - * - * @param buffer config account data - * @return null if info was not found - */ - static fromConfigData( - buffer: Buffer | Uint8Array | Array, - ): ValidatorInfo | null { - let byteArray = [...buffer]; - const configKeyCount = shortvec.decodeLength(byteArray); - if (configKeyCount !== 2) return null; - - const configKeys: Array = []; - for (let i = 0; i < 2; i++) { - const publicKey = new PublicKey( - guardedSplice(byteArray, 0, PUBLIC_KEY_LENGTH), - ); - const isSigner = guardedShift(byteArray) === 1; - configKeys.push({publicKey, isSigner}); - } - - if (configKeys[0].publicKey.equals(VALIDATOR_INFO_KEY)) { - if (configKeys[1].isSigner) { - const rawInfo: any = Layout.rustString().decode(Buffer.from(byteArray)); - const info = JSON.parse(rawInfo as string); - assertType(info, InfoString); - return new ValidatorInfo(configKeys[1].publicKey, info); - } - } - - return null; - } -} diff --git a/packages/library-legacy/src/vote-account.ts b/packages/library-legacy/src/vote-account.ts deleted file mode 100644 index e7643795509c..000000000000 --- a/packages/library-legacy/src/vote-account.ts +++ /dev/null @@ -1,236 +0,0 @@ -import * as BufferLayout from '@solana/buffer-layout'; -import type {Buffer} from 'buffer'; - -import * as Layout from './layout'; -import {PublicKey} from './publickey'; -import {toBuffer} from './utils/to-buffer'; - -export const VOTE_PROGRAM_ID = new PublicKey( - 'Vote111111111111111111111111111111111111111', -); - -export type Lockout = { - slot: number; - confirmationCount: number; -}; - -/** - * History of how many credits earned by the end of each epoch - */ -export type EpochCredits = Readonly<{ - epoch: number; - credits: number; - prevCredits: number; -}>; - -export type AuthorizedVoter = Readonly<{ - epoch: number; - authorizedVoter: PublicKey; -}>; - -type AuthorizedVoterRaw = Readonly<{ - authorizedVoter: Uint8Array; - epoch: number; -}>; - -type PriorVoters = Readonly<{ - buf: PriorVoterRaw[]; - idx: number; - isEmpty: number; -}>; - -export type PriorVoter = Readonly<{ - authorizedPubkey: PublicKey; - epochOfLastAuthorizedSwitch: number; - targetEpoch: number; -}>; - -type PriorVoterRaw = Readonly<{ - authorizedPubkey: Uint8Array; - epochOfLastAuthorizedSwitch: number; - targetEpoch: number; -}>; - -export type BlockTimestamp = Readonly<{ - slot: number; - timestamp: number; -}>; - -type VoteAccountData = Readonly<{ - authorizedVoters: AuthorizedVoterRaw[]; - authorizedWithdrawer: Uint8Array; - commission: number; - epochCredits: EpochCredits[]; - lastTimestamp: BlockTimestamp; - nodePubkey: Uint8Array; - priorVoters: PriorVoters; - rootSlot: number; - rootSlotValid: number; - votes: Lockout[]; -}>; - -/** - * See https://github.com/solana-labs/solana/blob/8a12ed029cfa38d4a45400916c2463fb82bbec8c/programs/vote_api/src/vote_state.rs#L68-L88 - * - * @internal - */ -const VoteAccountLayout = BufferLayout.struct([ - Layout.publicKey('nodePubkey'), - Layout.publicKey('authorizedWithdrawer'), - BufferLayout.u8('commission'), - BufferLayout.nu64(), // votes.length - BufferLayout.seq( - BufferLayout.struct([ - BufferLayout.nu64('slot'), - BufferLayout.u32('confirmationCount'), - ]), - BufferLayout.offset(BufferLayout.u32(), -8), - 'votes', - ), - BufferLayout.u8('rootSlotValid'), - BufferLayout.nu64('rootSlot'), - BufferLayout.nu64(), // authorizedVoters.length - BufferLayout.seq( - BufferLayout.struct([ - BufferLayout.nu64('epoch'), - Layout.publicKey('authorizedVoter'), - ]), - BufferLayout.offset(BufferLayout.u32(), -8), - 'authorizedVoters', - ), - BufferLayout.struct( - [ - BufferLayout.seq( - BufferLayout.struct([ - Layout.publicKey('authorizedPubkey'), - BufferLayout.nu64('epochOfLastAuthorizedSwitch'), - BufferLayout.nu64('targetEpoch'), - ]), - 32, - 'buf', - ), - BufferLayout.nu64('idx'), - BufferLayout.u8('isEmpty'), - ], - 'priorVoters', - ), - BufferLayout.nu64(), // epochCredits.length - BufferLayout.seq( - BufferLayout.struct([ - BufferLayout.nu64('epoch'), - BufferLayout.nu64('credits'), - BufferLayout.nu64('prevCredits'), - ]), - BufferLayout.offset(BufferLayout.u32(), -8), - 'epochCredits', - ), - BufferLayout.struct( - [BufferLayout.nu64('slot'), BufferLayout.nu64('timestamp')], - 'lastTimestamp', - ), -]); - -type VoteAccountArgs = { - nodePubkey: PublicKey; - authorizedWithdrawer: PublicKey; - commission: number; - rootSlot: number | null; - votes: Lockout[]; - authorizedVoters: AuthorizedVoter[]; - priorVoters: PriorVoter[]; - epochCredits: EpochCredits[]; - lastTimestamp: BlockTimestamp; -}; - -/** - * VoteAccount class - */ -export class VoteAccount { - nodePubkey: PublicKey; - authorizedWithdrawer: PublicKey; - commission: number; - rootSlot: number | null; - votes: Lockout[]; - authorizedVoters: AuthorizedVoter[]; - priorVoters: PriorVoter[]; - epochCredits: EpochCredits[]; - lastTimestamp: BlockTimestamp; - - /** - * @internal - */ - constructor(args: VoteAccountArgs) { - this.nodePubkey = args.nodePubkey; - this.authorizedWithdrawer = args.authorizedWithdrawer; - this.commission = args.commission; - this.rootSlot = args.rootSlot; - this.votes = args.votes; - this.authorizedVoters = args.authorizedVoters; - this.priorVoters = args.priorVoters; - this.epochCredits = args.epochCredits; - this.lastTimestamp = args.lastTimestamp; - } - - /** - * Deserialize VoteAccount from the account data. - * - * @param buffer account data - * @return VoteAccount - */ - static fromAccountData( - buffer: Buffer | Uint8Array | Array, - ): VoteAccount { - const versionOffset = 4; - const va = VoteAccountLayout.decode(toBuffer(buffer), versionOffset); - - let rootSlot: number | null = va.rootSlot; - if (!va.rootSlotValid) { - rootSlot = null; - } - - return new VoteAccount({ - nodePubkey: new PublicKey(va.nodePubkey), - authorizedWithdrawer: new PublicKey(va.authorizedWithdrawer), - commission: va.commission, - votes: va.votes, - rootSlot, - authorizedVoters: va.authorizedVoters.map(parseAuthorizedVoter), - priorVoters: getPriorVoters(va.priorVoters), - epochCredits: va.epochCredits, - lastTimestamp: va.lastTimestamp, - }); - } -} - -function parseAuthorizedVoter({ - authorizedVoter, - epoch, -}: AuthorizedVoterRaw): AuthorizedVoter { - return { - epoch, - authorizedVoter: new PublicKey(authorizedVoter), - }; -} - -function parsePriorVoters({ - authorizedPubkey, - epochOfLastAuthorizedSwitch, - targetEpoch, -}: PriorVoterRaw): PriorVoter { - return { - authorizedPubkey: new PublicKey(authorizedPubkey), - epochOfLastAuthorizedSwitch, - targetEpoch, - }; -} - -function getPriorVoters({buf, idx, isEmpty}: PriorVoters): PriorVoter[] { - if (isEmpty) { - return []; - } - - return [ - ...buf.slice(idx + 1).map(parsePriorVoters), - ...buf.slice(0, idx).map(parsePriorVoters), - ]; -} diff --git a/packages/library-legacy/test/.gitignore b/packages/library-legacy/test/.gitignore deleted file mode 100644 index 1521c8b7652b..000000000000 --- a/packages/library-legacy/test/.gitignore +++ /dev/null @@ -1 +0,0 @@ -dist diff --git a/packages/library-legacy/test/__shadow-jest-types.d.ts b/packages/library-legacy/test/__shadow-jest-types.d.ts deleted file mode 100644 index 7e359774df37..000000000000 --- a/packages/library-legacy/test/__shadow-jest-types.d.ts +++ /dev/null @@ -1 +0,0 @@ -declare module '@types/jest'; diff --git a/packages/library-legacy/test/account.test.ts b/packages/library-legacy/test/account.test.ts deleted file mode 100644 index 991c1ae9e72a..000000000000 --- a/packages/library-legacy/test/account.test.ts +++ /dev/null @@ -1,24 +0,0 @@ -import {expect} from 'chai'; -import {Buffer} from 'buffer'; - -import {Account} from '../src/account'; - -describe('Account', () => { - it('generate new account', () => { - const account = new Account(); - expect(account.secretKey).to.have.length(64); - }); - - it('account from secret key', () => { - const secretKey = Buffer.from([ - 153, 218, 149, 89, 225, 94, 145, 62, 233, 171, 46, 83, 227, 223, 173, 87, - 93, 163, 59, 73, 190, 17, 37, 187, 146, 46, 51, 73, 79, 73, 136, 40, 27, - 47, 73, 9, 110, 62, 93, 189, 15, 207, 169, 192, 192, 205, 146, 217, 171, - 59, 33, 84, 75, 52, 213, 221, 74, 101, 217, 139, 135, 139, 153, 34, - ]); - const account = new Account(secretKey); - expect(account.publicKey.toBase58()).to.eq( - '2q7pyhPwAwZ3QMfZrnAbDhnh9mDUqycszcpf86VgQxhF', - ); - }); -}); diff --git a/packages/library-legacy/test/cluster.test.ts b/packages/library-legacy/test/cluster.test.ts deleted file mode 100644 index 8acf6c370706..000000000000 --- a/packages/library-legacy/test/cluster.test.ts +++ /dev/null @@ -1,22 +0,0 @@ -import {expect} from 'chai'; - -import {clusterApiUrl} from '../src/utils/cluster'; - -describe('Cluster Util', () => { - it('invalid', () => { - expect(() => { - clusterApiUrl('abc123' as any); - }).to.throw(); - }); - - it('devnet', () => { - expect(clusterApiUrl()).to.eq('https://api.devnet.solana.com'); - expect(clusterApiUrl('devnet')).to.eq('https://api.devnet.solana.com'); - expect(clusterApiUrl('devnet', true)).to.eq( - 'https://api.devnet.solana.com', - ); - expect(clusterApiUrl('devnet', false)).to.eq( - 'http://api.devnet.solana.com', - ); - }); -}); diff --git a/packages/library-legacy/test/connection-subscriptions.test.ts b/packages/library-legacy/test/connection-subscriptions.test.ts deleted file mode 100644 index 270a52001272..000000000000 --- a/packages/library-legacy/test/connection-subscriptions.test.ts +++ /dev/null @@ -1,958 +0,0 @@ -import {expect, use} from 'chai'; -import {stub, SinonStubbedInstance, SinonSpy, spy} from 'sinon'; -import sinonChai from 'sinon-chai'; - -import { - AccountChangeCallback, - Commitment, - Connection, - LogsCallback, - ProgramAccountChangeCallback, - PublicKey, - RootChangeCallback, - SignatureResultCallback, - SlotChangeCallback, - SlotUpdateCallback, -} from '../src'; -import type Client from '../src/rpc-websocket'; -import {url} from './url'; - -use(sinonChai); - -function stubRpcWebSocket( - connection: Connection, -): SinonStubbedInstance { - const socket = connection._rpcWebSocket; - let mockOpen = false; - stub(socket, 'connect').callsFake(() => { - if (!mockOpen) { - mockOpen = true; - connection._rpcWebSocket.emit('open'); - } - }); - stub(socket, 'close').callsFake(() => { - if (mockOpen) { - mockOpen = false; - connection._rpcWebSocket.emit('close'); - } - }); - stub(socket, 'call'); - return socket as unknown as SinonStubbedInstance; -} - -describe('Subscriptions', () => { - let connection: Connection; - let stubbedSocket: SinonStubbedInstance; - const subscriptionMethodsConfig = { - accountSubscribe: { - getExpectedAlternateParams: () => [ - 'C2jDL4pcwpE2pP5EryTGn842JJUJTcurPGZUquQjySxK', - { - commitment: connection.commitment || 'finalized', - encoding: 'base64', - }, - ], - getExpectedParams: () => [ - PublicKey.default.toBase58(), - { - commitment: connection.commitment || 'finalized', - encoding: 'base64', - }, - ], - setupAlternateListener(callback: AccountChangeCallback): number { - return connection.onAccountChange( - new PublicKey('C2jDL4pcwpE2pP5EryTGn842JJUJTcurPGZUquQjySxK'), - callback, - ); - }, - setupListener(callback: AccountChangeCallback): number { - return connection.onAccountChange(PublicKey.default, callback); - }, - setupListenerWithDefaultsOmitted( - callback: AccountChangeCallback, - ): number { - return connection.onAccountChange(PublicKey.default, callback); - }, - setupListenerWithDefaultableParamsSetToTheirDefaults( - callback: AccountChangeCallback, - ): number { - return connection.onAccountChange( - PublicKey.default, - callback, - connection.commitment || 'finalized', - ); - }, - publishNotificationForServerSubscriptionId( - socket: Client, - serverSubscriptionId: number, - ) { - socket.emit('accountNotification', { - subscription: serverSubscriptionId, - result: { - context: {slot: 11}, - value: { - data: Buffer.from(''), - executable: false, - lamports: 0, - owner: PublicKey.default.toBase58(), - rentEpoch: 0, - space: 0, - }, - }, - }); - }, - teardownListener( - ...args: Parameters - ) { - return connection.removeAccountChangeListener(...args); - }, - }, - logsSubscribe: { - getExpectedAlternateParams: () => [ - {mentions: ['C2jDL4pcwpE2pP5EryTGn842JJUJTcurPGZUquQjySxK']}, - {commitment: connection.commitment || 'finalized'}, - ], - getExpectedParams: () => [ - {mentions: [PublicKey.default.toBase58()]}, - {commitment: connection.commitment || 'finalized'}, - ], - setupAlternateListener(callback: LogsCallback): number { - return connection.onLogs( - new PublicKey('C2jDL4pcwpE2pP5EryTGn842JJUJTcurPGZUquQjySxK'), - callback, - ); - }, - setupListener(callback: LogsCallback): number { - return connection.onLogs(PublicKey.default, callback); - }, - setupListenerWithDefaultsOmitted(callback: LogsCallback): number { - return connection.onLogs(PublicKey.default, callback); - }, - setupListenerWithDefaultableParamsSetToTheirDefaults( - callback: LogsCallback, - ): number { - return connection.onLogs( - PublicKey.default, - callback, - connection.commitment || 'finalized', - ); - }, - publishNotificationForServerSubscriptionId( - socket: Client, - serverSubscriptionId: number, - ) { - socket.emit('logsNotification', { - subscription: serverSubscriptionId, - result: { - context: {slot: 11}, - value: { - err: null, - logs: [ - 'SBF program 83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri success', - ], - signature: - '5h6xBEauJ3PK6SWCZ1PGjBvj8vDdWG3KpwATGy1ARAXFSDwt8GFXM7W5Ncn16wmqokgpiKRLuS83KUxyZyv2sUYv', - }, - }, - }); - }, - teardownListener( - ...args: Parameters - ) { - return connection.removeOnLogsListener(...args); - }, - }, - programSubscribe: { - getExpectedAlternateParams: () => [ - 'C2jDL4pcwpE2pP5EryTGn842JJUJTcurPGZUquQjySxK', - { - commitment: connection.commitment || 'finalized', - encoding: 'base64', - }, - ], - getExpectedParams: () => [ - PublicKey.default.toBase58(), - { - commitment: connection.commitment || 'finalized', - encoding: 'base64', - }, - ], - setupAlternateListener(callback: ProgramAccountChangeCallback): number { - return connection.onProgramAccountChange( - new PublicKey('C2jDL4pcwpE2pP5EryTGn842JJUJTcurPGZUquQjySxK'), - callback, - ); - }, - setupListener(callback: ProgramAccountChangeCallback): number { - return connection.onProgramAccountChange(PublicKey.default, callback); - }, - setupListenerWithDefaultsOmitted( - callback: ProgramAccountChangeCallback, - ): number { - return connection.onProgramAccountChange(PublicKey.default, callback); - }, - setupListenerWithDefaultableParamsSetToTheirDefaults( - callback: ProgramAccountChangeCallback, - ): number { - return connection.onProgramAccountChange( - PublicKey.default, - callback, - connection.commitment || 'finalized', - ); - }, - publishNotificationForServerSubscriptionId( - socket: Client, - serverSubscriptionId: number, - ) { - socket.emit('programNotification', { - subscription: serverSubscriptionId, - result: { - context: {slot: 11}, - value: { - pubkey: PublicKey.default.toBase58(), - account: { - data: Buffer.from(''), - executable: false, - lamports: 0, - owner: PublicKey.default.toBase58(), - rentEpoch: 0, - space: 0, - }, - }, - }, - }); - }, - teardownListener( - ...args: Parameters< - typeof connection.removeProgramAccountChangeListener - > - ) { - return connection.removeProgramAccountChangeListener(...args); - }, - }, - rootSubscribe: { - getExpectedAlternateParams: () => [], - getExpectedParams: () => [], - setupAlternateListener: undefined, - setupListener(callback: RootChangeCallback): number { - return connection.onRootChange(callback); - }, - setupListenerWithDefaultsOmitted: undefined, - setupListenerWithDefaultableParamsSetToTheirDefaults: undefined, - publishNotificationForServerSubscriptionId( - socket: Client, - serverSubscriptionId: number, - ) { - socket.emit('rootNotification', { - subscription: serverSubscriptionId, - result: 101, - }); - }, - teardownListener( - ...args: Parameters - ) { - return connection.removeRootChangeListener(...args); - }, - }, - - signatureSubscribe: { - getExpectedAlternateParams: () => [ - 'C2jDL4pcwpE2pP5EryTGn842JJUJTcurPGZUquQjySxK', - {commitment: connection.commitment || 'finalized'}, - ], - getExpectedParams: () => [ - PublicKey.default.toBase58(), - {commitment: connection.commitment || 'finalized'}, - ], - setupAlternateListener(callback: SignatureResultCallback): number { - return connection.onSignature( - new PublicKey( - 'C2jDL4pcwpE2pP5EryTGn842JJUJTcurPGZUquQjySxK', - ).toBase58(), - callback, - ); - }, - setupListener(callback: SignatureResultCallback): number { - return connection.onSignature(PublicKey.default.toBase58(), callback); - }, - setupListenerWithDefaultsOmitted( - callback: SignatureResultCallback, - ): number { - return connection.onSignature(PublicKey.default.toBase58(), callback); - }, - setupListenerWithDefaultableParamsSetToTheirDefaults( - callback: SignatureResultCallback, - ): number { - return connection.onSignature( - PublicKey.default.toBase58(), - callback, - connection.commitment || 'finalized', - ); - }, - publishNotificationForServerSubscriptionId( - socket: Client, - serverSubscriptionId: number, - ) { - socket.emit('signatureNotification', { - subscription: serverSubscriptionId, - result: { - context: {slot: 11}, - value: {err: null}, - }, - }); - }, - teardownListener( - ...args: Parameters - ) { - return connection.removeSignatureListener(...args); - }, - }, - slotSubscribe: { - getExpectedAlternateParams: () => [], - getExpectedParams: () => [], - setupAlternateListener: undefined, - setupListener(callback: SlotChangeCallback): number { - return connection.onSlotChange(callback); - }, - setupListenerWithDefaultsOmitted: undefined, - setupListenerWithDefaultableParamsSetToTheirDefaults: undefined, - publishNotificationForServerSubscriptionId( - socket: Client, - serverSubscriptionId: number, - ) { - socket.emit('slotNotification', { - subscription: serverSubscriptionId, - result: {parent: 1, slot: 2, root: 0}, - }); - }, - teardownListener( - ...args: Parameters - ) { - return connection.removeSlotChangeListener(...args); - }, - }, - slotsUpdatesSubscribe: { - getExpectedAlternateParams: () => [], - getExpectedParams: () => [], - setupAlternateListener: undefined, - setupListener(callback: SlotUpdateCallback): number { - return connection.onSlotUpdate(callback); - }, - setupListenerWithDefaultsOmitted: undefined, - setupListenerWithDefaultableParamsSetToTheirDefaults: undefined, - publishNotificationForServerSubscriptionId( - socket: Client, - serverSubscriptionId: number, - ) { - socket.emit('slotsUpdatesNotification', { - subscription: serverSubscriptionId, - result: { - type: 'root', - slot: 0, - timestamp: 322992000000, - }, - }); - }, - teardownListener( - ...args: Parameters - ) { - return connection.removeSlotUpdateListener(...args); - }, - }, - }; - beforeEach(() => { - connection = new Connection(url); - stubbedSocket = stubRpcWebSocket(connection); - }); - afterEach(() => { - stubbedSocket.close(); - }); - Object.entries(subscriptionMethodsConfig).forEach( - ([ - subscriptionMethod, - { - getExpectedAlternateParams, - getExpectedParams, - publishNotificationForServerSubscriptionId, - setupAlternateListener, - setupListener, - teardownListener, - }, - ]) => { - describe(`The \`${subscriptionMethod}\` RPC method`, () => { - describe('attaching the first notification listener', () => { - let clientSubscriptionId: number; - let listenerCallback: SinonSpy; - let acknowledgeSubscription = ( - // eslint-disable-next-line @typescript-eslint/no-unused-vars - _serverSubscriptionId: number, - ): void => { - expect.fail( - 'Expected a function to have been assigned to `acknowledgeSubscription` in the test.', - ); - }; - let fatalSubscription = (): void => { - expect.fail( - 'Expected a function to have been assigned to `fatalSubscription` in the test.', - ); - }; - const serverSubscriptionId = 0; - beforeEach(() => { - stubbedSocket.call - .withArgs(subscriptionMethod, getExpectedParams()) - .callsFake( - () => - // Defer the acknowledgement. - new Promise((resolve, reject) => { - acknowledgeSubscription = resolve; - fatalSubscription = reject; - }), - ); - listenerCallback = spy(); - clientSubscriptionId = setupListener(listenerCallback); - }); - it('results in a subscription request being made to the RPC', () => { - expect(stubbedSocket.call).to.have.been.calledOnceWithExactly( - subscriptionMethod, - getExpectedParams(), - ); - }); - describe('then unsubscribing that listener before the subscription has been acknowledged by the server', () => { - beforeEach(async () => { - stubbedSocket.call.resetHistory(); - await teardownListener(clientSubscriptionId); - }); - describe('once the subscription has been acknowledged by the server', () => { - beforeEach(async () => { - await acknowledgeSubscription(serverSubscriptionId); - }); - it('results in the subscription being torn down immediately', () => { - expect(stubbedSocket.call).to.have.been.calledOnceWithExactly( - subscriptionMethod.replace('Subscribe', 'Unsubscribe'), - [serverSubscriptionId], - ); - }); - }); - }); - describe('once the subscription has been acknowledged by the server', () => { - beforeEach(async () => { - await acknowledgeSubscription(serverSubscriptionId); - }); - describe('when a notification is published', () => { - beforeEach(() => { - publishNotificationForServerSubscriptionId( - stubbedSocket as unknown as Client, - serverSubscriptionId, - ); - }); - it('fires the listener callback', () => { - expect(listenerCallback).to.have.been.calledOnce; - }); - }); - describe('then unsubscribing that listener', () => { - let acknowledgeUnsubscribe = (): void => { - expect.fail( - 'Expected a function to have been assigned to `acknowledgeUnsubscribe` in the test', - ); - }; - let fatalUnsubscribe = (): void => { - expect.fail( - 'Expected a function to have been assigned to `fatalUnsubscribe` in the test', - ); - }; - beforeEach(() => { - stubbedSocket.call.resetHistory(); - stubbedSocket.call - .withArgs( - subscriptionMethod.replace('Subscribe', 'Unsubscribe'), - [serverSubscriptionId], - ) - .callsFake( - () => - // Defer the acknowledgement. - new Promise((resolve, reject) => { - acknowledgeUnsubscribe = resolve; - fatalUnsubscribe = reject; - }), - ); - teardownListener(clientSubscriptionId); - }); - it('results in an unsubscribe request being made to the RPC', () => { - expect(stubbedSocket.call).to.have.been.calledOnceWithExactly( - subscriptionMethod.replace('Subscribe', 'Unsubscribe'), - [serverSubscriptionId], - ); - }); - describe('if a new listener is added before the unsubscribe is acknowledged by the server', () => { - beforeEach(() => { - stubbedSocket.call.resetHistory(); - setupListener(spy()); - }); - describe('once that unsubscribe is acknowledged by the server', () => { - beforeEach(async () => { - await acknowledgeUnsubscribe(); - }); - it('results in a new subscription request being made to the RPC', () => { - expect( - stubbedSocket.call, - ).to.have.been.calledOnceWithExactly( - subscriptionMethod, - getExpectedParams(), - ); - }); - }); - }); - describe('when a notification is published before the unsubscribe is acknowledged by the server', () => { - beforeEach(() => { - publishNotificationForServerSubscriptionId( - stubbedSocket as unknown as Client, - serverSubscriptionId, - ); - }); - it('does not fire the listener callback', () => { - expect(listenerCallback).not.to.have.been.called; - }); - }); - describe('if that unsubscribe throws an exception', () => { - beforeEach(async () => { - stubbedSocket.call.resetHistory(); - await fatalUnsubscribe(); - }); - it('results in a retry unsubscribe request being made to the RPC', () => { - expect(stubbedSocket.call).to.have.been.calledOnceWithExactly( - subscriptionMethod.replace('Subscribe', 'Unsubscribe'), - [serverSubscriptionId], - ); - }); - }); - describe('then having the socket connection error', () => { - beforeEach(() => { - stubbedSocket.emit( - 'error', - new Error('A bad thing happened to the socket'), - ); - }); - describe('making another subscription while disconnected', () => { - beforeEach(() => { - stubbedSocket.call.resetHistory(); - setupListener(spy()); - }); - it('does not issue an RPC call', () => { - expect(stubbedSocket.call).not.to.have.been.called; - }); - }); - }); - describe('then having the socket connection drop unexpectedly', () => { - beforeEach(() => { - stubbedSocket.emit('close'); - }); - describe('making another subscription while disconnected', () => { - beforeEach(() => { - stubbedSocket.call.resetHistory(); - setupListener(spy()); - }); - it('does not issue an RPC call', () => { - expect(stubbedSocket.call).not.to.have.been.called; - }); - }); - describe('upon the socket connection reopening', () => { - let fatalPriorUnubscribe: () => void; - beforeEach(() => { - fatalPriorUnubscribe = fatalUnsubscribe; - stubbedSocket.call.resetHistory(); - stubbedSocket.emit('open'); - }); - it('does not result in a new unsubscription request being made to the RPC', () => { - expect(stubbedSocket.call).not.to.have.been.called; - }); - describe('then upon the prior unsubscribe fataling (eg. because its timeout triggers)', () => { - beforeEach(async () => { - stubbedSocket.call.resetHistory(); - await fatalPriorUnubscribe(); - }); - it('does not result in a new unsubscription request being made to the RPC', () => { - expect(stubbedSocket.call).not.to.have.been.called; - }); - }); - }); - }); - }); - describe('attaching a second notification listener with the same params', () => { - let secondListenerCallback: SinonSpy; - beforeEach(() => { - stubbedSocket.call.resetHistory(); - secondListenerCallback = spy(); - setupListener(secondListenerCallback); - }); - it('does not result in a second subscription request to the RPC', () => { - expect(stubbedSocket.call).not.to.have.been.called; - }); - describe('when a notification is published', () => { - beforeEach(() => { - publishNotificationForServerSubscriptionId( - stubbedSocket as unknown as Client, - serverSubscriptionId, - ); - }); - it("fires the first listener's callback", () => { - expect(listenerCallback).to.have.been.calledOnce; - }); - it("fires the second listener's callback", () => { - expect(secondListenerCallback).to.have.been.calledOnce; - }); - }); - describe('then unsubscribing the first listener', () => { - beforeEach(async () => { - stubbedSocket.call.resetHistory(); - await teardownListener(clientSubscriptionId); - }); - it('does not result in an unsubscribe request being made to the RPC', () => { - expect(stubbedSocket.call).not.to.have.been.called; - }); - describe('when a notification is published', () => { - beforeEach(() => { - publishNotificationForServerSubscriptionId( - stubbedSocket as unknown as Client, - serverSubscriptionId, - ); - }); - it("does not fire the first listener's callback", () => { - expect(listenerCallback).not.to.have.been.called; - }); - it("fires the second listener's callback", () => { - expect(secondListenerCallback).to.have.been.calledOnce; - }); - }); - }); - }); - if (setupAlternateListener) { - describe('attaching a second notification listener with different params', () => { - let alternateListenerCallback: SinonSpy; - const secondServerSubscriptionId = 1; - beforeEach(() => { - stubbedSocket.call - .withArgs(subscriptionMethod, getExpectedAlternateParams()) - .resolves(secondServerSubscriptionId); - alternateListenerCallback = spy(); - setupAlternateListener(alternateListenerCallback); - }); - it('results in a second subscription request being made to the RPC', () => { - expect(stubbedSocket.call).to.have.been.calledWithExactly( - subscriptionMethod, - getExpectedAlternateParams(), - ); - }); - describe('when a notification for the first subscription is published', () => { - beforeEach(() => { - publishNotificationForServerSubscriptionId( - stubbedSocket as unknown as Client, - serverSubscriptionId, - ); - }); - it("fires the first listener's callback", () => { - expect(listenerCallback).to.have.been.called; - }); - it("does not fire the second listener's callback", () => { - expect(alternateListenerCallback).not.to.have.been.called; - }); - }); - describe('when a notification for the second subscription is published', () => { - beforeEach(() => { - publishNotificationForServerSubscriptionId( - stubbedSocket as unknown as Client, - secondServerSubscriptionId, - ); - }); - it("does not fire the first listener's callback", () => { - expect(listenerCallback).not.to.have.been.called; - }); - it("fires the second listener's callback", () => { - expect(alternateListenerCallback).to.have.been.called; - }); - }); - }); - } - }); - describe('if that subscription throws an exception', () => { - beforeEach(async () => { - stubbedSocket.call.resetHistory(); - await fatalSubscription(); - }); - it('results in a retry subscription request being made to the RPC', () => { - expect(stubbedSocket.call).to.have.been.calledOnceWithExactly( - subscriptionMethod, - getExpectedParams(), - ); - }); - }); - describe('then having the socket connection drop unexpectedly', () => { - beforeEach(() => { - stubbedSocket.emit('close'); - }); - describe('then unsubscribing that listener', () => { - beforeEach(async () => { - await teardownListener(clientSubscriptionId); - }); - describe('upon the socket connection reopening', () => { - beforeEach(() => { - stubbedSocket.call.resetHistory(); - stubbedSocket.emit('open'); - }); - it('does not result in a new subscription request being made to the RPC', () => { - expect(stubbedSocket.call).not.to.have.been.called; - }); - }); - }); - describe('upon the socket connection reopening', () => { - let fatalPriorSubscription: () => void; - beforeEach(() => { - fatalPriorSubscription = fatalSubscription; - stubbedSocket.call.resetHistory(); - stubbedSocket.emit('open'); - }); - it('results in a new subscription request being made to the RPC', () => { - expect(stubbedSocket.call).to.have.been.calledOnceWithExactly( - subscriptionMethod, - getExpectedParams(), - ); - }); - describe('then upon the prior subscription fataling (eg. because its timeout triggers)', () => { - beforeEach(async () => { - stubbedSocket.call.resetHistory(); - await fatalPriorSubscription(); - }); - it('does not result in a new subscription request being made to the RPC', () => { - expect(stubbedSocket.call).not.to.have.been.called; - }); - describe('once the new subscription has been acknowledged by the server', () => { - beforeEach(async () => { - stubbedSocket.call.resetHistory(); - await acknowledgeSubscription(serverSubscriptionId); - }); - describe('when a notification is published', () => { - beforeEach(() => { - publishNotificationForServerSubscriptionId( - stubbedSocket as unknown as Client, - serverSubscriptionId, - ); - }); - it('fires the listener callback', () => { - expect(listenerCallback).to.have.been.calledOnce; - }); - }); - }); - }); - }); - }); - }); - }); - }, - ); - /** - * Special case. - * After a signature is processed, RPCs automatically dispose of the - * subscription on the server side. This test asserts that RPC - * unsubscribe request are only made before such a subscription has - * received a notification which it knows to be final and indicative - * that the RPC has auto-disposed the subscription. - * - * NOTE: There is a proposal to eliminate this special case, here: - * https://github.com/solana-labs/solana/issues/18892 - */ - describe('auto-disposing subscriptions', () => { - let clientSubscriptionId: number; - const serverSubscriptionId = 0; - const testSignature = 'C2jDL4pcwpE2pP5EryTGn842JJUJTcurPGZUquQjySxK'; - const getExpectedParams = () => [ - testSignature, - {commitment: connection.commitment || 'finalized'}, - ]; - // This type of notification *is* indicative of auto-disposal. - const FINAL_NOTIFICATION_RESULT = { - context: {slot: 11}, - value: {err: null}, - }; - // This type of notification is *not* indicative of auto-disposal. - const NON_FINAL_NOTIFICATION_RESULT = { - context: {slot: 11}, - value: 'receivedSignature', - }; - beforeEach(() => { - stubbedSocket.call - .withArgs('signatureSubscribe', getExpectedParams()) - .resolves(serverSubscriptionId); - clientSubscriptionId = connection.onSignature(testSignature, spy()); - }); - describe('before an auto-disposing subscription has published any notification', () => { - describe('then unsubscribing the listener', () => { - beforeEach(async () => { - stubbedSocket.call.resetHistory(); - await connection.removeSignatureListener(clientSubscriptionId); - }); - it('results in an unsubscribe request being made to the RPC', () => { - expect(stubbedSocket.call).to.have.been.calledWith( - 'signatureUnsubscribe', - [serverSubscriptionId], - ); - }); - }); - }); - describe('after an auto-disposing subscription has published a non-final notification', () => { - beforeEach(() => { - stubbedSocket.emit('signatureNotification', { - subscription: serverSubscriptionId, - result: NON_FINAL_NOTIFICATION_RESULT, - }); - }); - it('should not result in an unsubscribe request being made to the RPC', () => { - expect(stubbedSocket.call).not.to.have.been.calledWith( - 'signatureUnsubscribe', - [serverSubscriptionId], - ); - }); - describe('then unsubscribing the listener', () => { - beforeEach(async () => { - stubbedSocket.call.resetHistory(); - await connection.removeSignatureListener(clientSubscriptionId); - }); - it('results in an unsubscribe request being made to the RPC', () => { - expect(stubbedSocket.call).to.have.been.calledWith( - 'signatureUnsubscribe', - [serverSubscriptionId], - ); - }); - }); - }); - describe('after an auto-disposing subscription has published its final notification', () => { - beforeEach(() => { - stubbedSocket.emit('signatureNotification', { - subscription: serverSubscriptionId, - result: FINAL_NOTIFICATION_RESULT, - }); - }); - it('should not result in an unsubscribe request being made to the RPC', () => { - expect(stubbedSocket.call).not.to.have.been.calledWith( - 'signatureUnsubscribe', - [serverSubscriptionId], - ); - }); - describe('then unsubscribing the listener', () => { - beforeEach(async () => { - stubbedSocket.call.resetHistory(); - await connection.removeSignatureListener(clientSubscriptionId); - }); - it('should not result in an unsubscribe request being made to the RPC', () => { - expect(stubbedSocket.call).not.to.have.been.called; - }); - }); - }); - }); - [ - undefined, // Let `Connection` use the default commitment - 'processed' as Commitment, // Override `Connection's` commitment - ].forEach((maybeOverrideCommitment: Commitment | undefined) => { - describe(`given a Connection with ${ - maybeOverrideCommitment - ? `its commitment overridden to \`${maybeOverrideCommitment}\`` - : 'an unspecified commitment override' - }`, () => { - Object.entries(subscriptionMethodsConfig).forEach( - ([ - subscriptionMethod, - { - getExpectedParams, - setupListenerWithDefaultableParamsSetToTheirDefaults, - setupListenerWithDefaultsOmitted, - }, - ]) => { - beforeEach(() => { - connection = new Connection(url, maybeOverrideCommitment); - stubbedSocket = stubRpcWebSocket(connection); - }); - afterEach(() => { - stubbedSocket.close(); - }); - if ( - setupListenerWithDefaultsOmitted && - setupListenerWithDefaultableParamsSetToTheirDefaults - ) { - describe('making a subscription with defaulted params omitted', () => { - beforeEach(() => { - setupListenerWithDefaultsOmitted(spy()); - }); - it('results in a subscription request being made to the RPC', () => { - expect(stubbedSocket.call).to.have.been.calledWithExactly( - subscriptionMethod, - getExpectedParams(), - ); - }); - describe('then making the same subscription with the defaultable params set to their defaults', () => { - beforeEach(() => { - stubbedSocket.call.resetHistory(); - setupListenerWithDefaultableParamsSetToTheirDefaults(spy()); - }); - it('does not result in a subscription request being made to the RPC', () => { - expect(stubbedSocket.call).not.to.have.been.called; - }); - }); - }); - } - }, - ); - }); - }); - describe('during state machine updates', () => { - beforeEach(() => { - stubbedSocket.connect.callsFake(() => {}); - stubbedSocket.close.callsFake(() => {}); - }); - afterEach(() => { - stubbedSocket.emit('close'); - }); - /** - * This is a regression test for the case described here: - * https://github.com/solana-labs/solana/pull/24473#discussion_r858437090 - * - * Essentially, you want to make sure that the state processor, as it recurses - * always processes the latest version of every subscription. Depending on how - * you craft the loop inside the processor, you can end up in this situation. - * - * 1A (pending subscription with zero callbacks; gets deleted then recurses) - * L 2B (pending subscription; transitions to subscribing and makes network call) - * 2A (old version of subscription 2; transitions again and makes 2nd network call) - * - * The fact that subscription 2 made two network calls is the bug there. - * What you want is this: - * - * 1A (pending subscription with zero callbacks; gets deleted then recurses) - * L 2B (pending subscription; transitions to subscribing and makes network call) - * 2A (now in the subscribing state; skipped by the processor) - * - * Below is a test that tries to replicate this exact scenario. - */ - it('the processor always operates over the most up-to-date state of a given subscription', () => { - // Add two subscriptions. - const clientSubscriptionIdA = connection.onAccountChange( - new PublicKey('C2jDL4pcwpE2pP5EryTGn842JJUJTcurPGZUquQjySxK'), - () => {}, - ); - connection.onAccountChange( - new PublicKey('27Y78XJXG9A13pnPajrB1VYU6EF8uNSoojPZBmhKsi8C'), - () => {}, - ); - // Then remove the first one before the connection opens. - connection.removeAccountChangeListener(clientSubscriptionIdA); - // Then open the connection. - stubbedSocket.emit('open'); - // Despite recursion inside the state machine, ensure that the second - // subscription only makes *one* connection attempt. - expect(stubbedSocket.call).to.have.been.calledOnceWithExactly( - 'accountSubscribe', - [ - '27Y78XJXG9A13pnPajrB1VYU6EF8uNSoojPZBmhKsi8C', - {commitment: 'finalized', encoding: 'base64'}, - ], - ); - }); - }); -}); diff --git a/packages/library-legacy/test/connection.test.ts b/packages/library-legacy/test/connection.test.ts deleted file mode 100644 index fa44de3837fa..000000000000 --- a/packages/library-legacy/test/connection.test.ts +++ /dev/null @@ -1,6523 +0,0 @@ -import bs58 from 'bs58'; -import {Buffer} from 'buffer'; -import {expect, use} from 'chai'; -import chaiAsPromised from 'chai-as-promised'; -import {Agent as HttpAgent} from 'http'; -import {Agent as HttpsAgent} from 'https'; -import {match, mock, spy, stub, useFakeTimers, SinonFakeTimers} from 'sinon'; -import sinonChai from 'sinon-chai'; -import {fail} from 'assert'; - -import { - Authorized, - Connection, - EpochSchedule, - SystemProgram, - Transaction, - LAMPORTS_PER_SOL, - Lockup, - PublicKey, - StakeProgram, - sendAndConfirmTransaction, - Keypair, - Message, - AddressLookupTableProgram, - SYSTEM_INSTRUCTION_LAYOUTS, - NONCE_ACCOUNT_LENGTH, - MessageAddressTableLookup, - sendAndConfirmRawTransaction, - SendTransactionError, -} from '../src'; -import invariant from '../src/utils/assert'; -import {toBuffer} from '../src/utils/to-buffer'; -import {MOCK_PORT, url, Node14Controller, nodeVersion} from './url'; -import { - AccountInfo, - BLOCKHASH_CACHE_TIMEOUT_MS, - BlockResponse, - BlockSignatures, - Commitment, - ConfirmedBlock, - Context, - EpochInfo, - InflationGovernor, - InflationRate, - Logs, - SignatureResult, - SlotInfo, -} from '../src/connection'; -import {sleep} from '../src/utils/sleep'; -import { - helpers, - mockErrorMessage, - mockErrorResponse, - mockRpcBatchResponse, - mockRpcResponse, - mockServer, -} from './mocks/rpc-http'; -import { - stubRpcWebSocket, - restoreRpcWebSocket, - mockRpcMessage, -} from './mocks/rpc-websocket'; -import { - NonceInformation, - TransactionInstruction, - TransactionSignature, - TransactionExpiredBlockheightExceededError, - TransactionExpiredNonceInvalidError, - TransactionExpiredTimeoutError, - TransactionMessage, -} from '../src/transaction'; -import type { - SignatureStatus, - TransactionError, - KeyedAccountInfo, -} from '../src/connection'; -import {VersionedTransaction} from '../src/transaction/versioned'; -import {MessageV0} from '../src/message/v0'; -import {encodeData} from '../src/instruction'; - -use(chaiAsPromised); -use(sinonChai); - -async function waitForSlot( - this: Mocha.Context, - connection: Connection, - minSlot: number = 0, -): Promise { - while ((await connection.getSlot()) <= minSlot) { - if (process.env.TEST_LIVE) { - // If the test validator is newly spawned, it may not have formed a root yet. Since we're - // going to have to wait up to 32 slots for a root, let's increase the timeout of this test. - this.timeout( - 2000 + - 400 * // ms per slot - (32 + minSlot) * // Max confirmations - 1.25, // Fudge factor to leave time for rest of test - ); - } - continue; - } -} -async function mockNonceAccountResponse( - nonceAccountPubkey: string, - nonceValue: string, - nonceAuthority: string, - slot?: number, -) { - const mockNonceAccountData = Buffer.alloc(NONCE_ACCOUNT_LENGTH); - mockNonceAccountData.fill(0); - // Authority starts after 4 version bytes and 4 state bytes. - mockNonceAccountData.set(bs58.decode(nonceAuthority), 4 + 4); - // Nonce hash starts 32 bytes after the authority. - mockNonceAccountData.set(bs58.decode(nonceValue), 4 + 4 + 32); - await mockRpcResponse({ - method: 'getAccountInfo', - params: [nonceAccountPubkey, {encoding: 'base64'}], - value: { - owner: SystemProgram.programId.toBase58(), - lamports: LAMPORTS_PER_SOL, - data: [mockNonceAccountData.toString('base64'), 'base64'], - executable: false, - rentEpoch: 20, - space: 0, - }, - slot, - withContext: true, - }); -} - -const verifySignatureStatus = ( - status: SignatureStatus | null, - err?: TransactionError, -): SignatureStatus => { - if (status === null) { - expect(status).not.to.be.null; - throw new Error(); // unreachable - } - - const expectedErr = err || null; - expect(status.err).to.eql(expectedErr); - expect(status.slot).to.be.at.least(0); - if (expectedErr !== null) return status; - - const confirmations = status.confirmations; - if (typeof confirmations === 'number') { - expect(confirmations).to.be.at.least(0); - } else { - expect(confirmations).to.be.null; - } - return status; -}; - -describe('Connection', function () { - let connection: Connection; - beforeEach(() => { - connection = new Connection(url); - }); - - if (mockServer) { - const server = mockServer; - beforeEach(() => { - server.start(MOCK_PORT); - stubRpcWebSocket(connection); - }); - - afterEach(() => { - server.stop(); - restoreRpcWebSocket(connection); - }); - } - - if (mockServer) { - it('should pass HTTP headers to RPC', async () => { - const headers = { - Authorization: 'Bearer 123', - }; - - let connection = new Connection(url, { - httpHeaders: headers, - }); - - await mockRpcResponse({ - method: 'getVersion', - params: [], - value: {'solana-core': '0.20.4'}, - withHeaders: headers, - }); - - expect(await connection.getVersion()).to.be.not.null; - }); - - it('should allow middleware to augment request', async () => { - let connection = new Connection(url, { - fetchMiddleware: (url, options, fetch) => { - if (options) { - options.headers = Object.assign(options.headers!, { - Authorization: 'Bearer 123', - }); - - fetch(url, options); - } else { - fail('options must be defined!'); - } - }, - }); - - await mockRpcResponse({ - method: 'getVersion', - params: [], - value: {'solana-core': '0.20.4'}, - withHeaders: { - Authorization: 'Bearer 123', - }, - }); - - expect(await connection.getVersion()).to.be.not.null; - }); - } - - describe('override HTTP agent', () => { - let previousBrowserEnv: string | undefined; - beforeEach(() => { - previousBrowserEnv = process.env.BROWSER; - delete process.env.BROWSER; - }); - afterEach(() => { - process.env.BROWSER = previousBrowserEnv; - }); - - it('uses no agent with fetch when `overrideAgent` is `false`', () => { - const fetch = spy(); - const c = new Connection(url, {httpAgent: false, fetch}); - c.getBlock(0); - expect(fetch).to.have.been.calledWith( - match.any, - match({agent: undefined}), - ); - }); - - it('uses the supplied `overrideAgent` with fetch', () => { - const fetch = spy(); - const httpAgent = new HttpsAgent(); - const c = new Connection('https://example.com', {httpAgent, fetch}); - c.getBlock(0); - expect(fetch).to.have.been.calledWith( - match.any, - match({agent: httpAgent}), - ); - }); - - it('throws when the supplied `overrideAgent` is http but the endpoint is https', () => { - expect(() => { - new Connection('https://example.com', {httpAgent: new HttpAgent()}); - }).to.throw; - }); - - it('throws when the supplied `overrideAgent` is https but the endpoint is http', () => { - expect(() => { - new Connection('http://example.com', {httpAgent: new HttpsAgent()}); - }).to.throw; - }); - }); - - it('should attribute middleware fatals to the middleware', async () => { - let connection = new Connection(url, { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - fetchMiddleware: (_url, _options, _fetch) => { - throw new Error('This middleware experienced a fatal error'); - }, - }); - const error = await expect(connection.getVersion()).to.be.rejectedWith( - 'This middleware experienced a fatal error', - ); - expect(error) - .to.be.an.instanceOf(Error) - .and.to.have.property('stack') - .that.include('fetchMiddleware'); - }); - - it('should not attribute fetch errors to the middleware', async () => { - let connection = new Connection(url, { - fetchMiddleware: (url, _options, fetch) => { - fetch(url, { - body: 'An `Object` was expected here; this is a `TypeError`.', - }); - }, - }); - const error = await expect(connection.getVersion()).to.be.rejected; - expect(error) - .to.be.an.instanceOf(Error) - .and.to.have.property('stack') - .that.does.not.include('fetchMiddleware'); - }); - - it('get account info - not found', async () => { - const account = Keypair.generate(); - - await mockRpcResponse({ - method: 'getAccountInfo', - params: [account.publicKey.toBase58(), {encoding: 'base64'}], - value: null, - withContext: true, - }); - - expect(await connection.getAccountInfo(account.publicKey)).to.be.null; - - await mockRpcResponse({ - method: 'getAccountInfo', - params: [account.publicKey.toBase58(), {encoding: 'jsonParsed'}], - value: null, - withContext: true, - }); - - expect((await connection.getParsedAccountInfo(account.publicKey)).value).to - .be.null; - }); - - it('get multiple accounts info', async () => { - const account1 = Keypair.generate(); - const account2 = Keypair.generate(); - - { - await helpers.airdrop({ - connection, - address: account1.publicKey, - amount: LAMPORTS_PER_SOL, - }); - - await helpers.airdrop({ - connection, - address: account2.publicKey, - amount: LAMPORTS_PER_SOL, - }); - } - - const value = [ - { - owner: '11111111111111111111111111111111', - lamports: LAMPORTS_PER_SOL, - data: ['', 'base64'], - executable: false, - rentEpoch: 18446744073709552000, - space: 0, - }, - { - owner: '11111111111111111111111111111111', - lamports: LAMPORTS_PER_SOL, - data: ['', 'base64'], - executable: false, - rentEpoch: 18446744073709552000, - space: 0, - }, - ]; - - await mockRpcResponse({ - method: 'getMultipleAccounts', - params: [ - [account1.publicKey.toBase58(), account2.publicKey.toBase58()], - {encoding: 'base64'}, - ], - value: value, - withContext: true, - }); - - const res = await connection.getMultipleAccountsInfo( - [account1.publicKey, account2.publicKey], - 'confirmed', - ); - - const expectedValue = [ - { - owner: new PublicKey('11111111111111111111111111111111'), - lamports: LAMPORTS_PER_SOL, - data: Buffer.from([]), - executable: false, - rentEpoch: 18446744073709552000, - space: 0, - }, - { - owner: new PublicKey('11111111111111111111111111111111'), - lamports: LAMPORTS_PER_SOL, - data: Buffer.from([]), - executable: false, - rentEpoch: 18446744073709552000, - space: 0, - }, - ]; - - expect(res).to.eql(expectedValue); - }); - - it('get program accounts', async () => { - const account0 = Keypair.generate(); - const account1 = Keypair.generate(); - const programId = Keypair.generate(); - - { - await helpers.airdrop({ - connection, - address: account0.publicKey, - amount: LAMPORTS_PER_SOL, - }); - - const transaction = new Transaction().add( - SystemProgram.assign({ - accountPubkey: account0.publicKey, - programId: programId.publicKey, - }), - ); - - await helpers.processTransaction({ - connection, - transaction, - signers: [account0], - commitment: 'confirmed', - }); - } - - { - await helpers.airdrop({ - connection, - address: account1.publicKey, - amount: 0.5 * LAMPORTS_PER_SOL, - }); - - const transaction = new Transaction().add( - SystemProgram.assign({ - accountPubkey: account1.publicKey, - programId: programId.publicKey, - }), - ); - - await helpers.processTransaction({ - connection, - transaction, - signers: [account1], - commitment: 'confirmed', - }); - } - - const feeCalculator = (await helpers.recentBlockhash({connection})) - .feeCalculator; - - { - await mockRpcResponse({ - method: 'getProgramAccounts', - params: [ - programId.publicKey.toBase58(), - {commitment: 'confirmed', encoding: 'base64'}, - ], - value: [ - { - account: { - data: ['', 'base64'], - executable: false, - lamports: LAMPORTS_PER_SOL - feeCalculator.lamportsPerSignature, - owner: programId.publicKey.toBase58(), - rentEpoch: 20, - space: 0, - }, - pubkey: account0.publicKey.toBase58(), - }, - { - account: { - data: ['', 'base64'], - executable: false, - lamports: - 0.5 * LAMPORTS_PER_SOL - feeCalculator.lamportsPerSignature, - owner: programId.publicKey.toBase58(), - rentEpoch: 20, - space: 0, - }, - pubkey: account1.publicKey.toBase58(), - }, - ], - }); - - const programAccounts = await connection.getProgramAccounts( - programId.publicKey, - { - commitment: 'confirmed', - }, - ); - expect(programAccounts).to.have.length(2); - programAccounts.forEach(function (keyedAccount) { - if (keyedAccount.pubkey.equals(account0.publicKey)) { - expect(keyedAccount.account.lamports).to.eq( - LAMPORTS_PER_SOL - feeCalculator.lamportsPerSignature, - ); - } else { - expect(keyedAccount.pubkey).to.eql(account1.publicKey); - expect(keyedAccount.account.lamports).to.eq( - 0.5 * LAMPORTS_PER_SOL - feeCalculator.lamportsPerSignature, - ); - } - }); - } - - { - await mockRpcResponse({ - method: 'getProgramAccounts', - params: [ - programId.publicKey.toBase58(), - {commitment: 'confirmed', encoding: 'base64'}, - ], - value: [ - { - account: { - data: ['', 'base64'], - executable: false, - lamports: LAMPORTS_PER_SOL - feeCalculator.lamportsPerSignature, - owner: programId.publicKey.toBase58(), - rentEpoch: 20, - space: 0, - }, - pubkey: account0.publicKey.toBase58(), - }, - { - account: { - data: ['', 'base64'], - executable: false, - lamports: - 0.5 * LAMPORTS_PER_SOL - feeCalculator.lamportsPerSignature, - owner: programId.publicKey.toBase58(), - rentEpoch: 20, - space: 0, - }, - pubkey: account1.publicKey.toBase58(), - }, - ], - }); - - const programAccounts = await connection.getProgramAccounts( - programId.publicKey, - 'confirmed', - ); - expect(programAccounts).to.have.length(2); - programAccounts.forEach(function (keyedAccount) { - if (keyedAccount.pubkey.equals(account0.publicKey)) { - expect(keyedAccount.account.lamports).to.eq( - LAMPORTS_PER_SOL - feeCalculator.lamportsPerSignature, - ); - } else { - expect(keyedAccount.pubkey).to.eql(account1.publicKey); - expect(keyedAccount.account.lamports).to.eq( - 0.5 * LAMPORTS_PER_SOL - feeCalculator.lamportsPerSignature, - ); - } - }); - } - - { - await mockRpcResponse({ - method: 'getProgramAccounts', - params: [ - programId.publicKey.toBase58(), - { - commitment: 'confirmed', - encoding: 'base64', - filters: [ - { - dataSize: 0, - }, - ], - }, - ], - value: [ - { - account: { - data: ['', 'base64'], - executable: false, - lamports: LAMPORTS_PER_SOL - feeCalculator.lamportsPerSignature, - owner: programId.publicKey.toBase58(), - rentEpoch: 20, - space: 0, - }, - pubkey: account0.publicKey.toBase58(), - }, - { - account: { - data: ['', 'base64'], - executable: false, - lamports: - 0.5 * LAMPORTS_PER_SOL - feeCalculator.lamportsPerSignature, - owner: programId.publicKey.toBase58(), - rentEpoch: 20, - space: 0, - }, - pubkey: account1.publicKey.toBase58(), - }, - ], - }); - - const programAccountsDoMatchFilter = await connection.getProgramAccounts( - programId.publicKey, - { - commitment: 'confirmed', - encoding: 'base64', - filters: [{dataSize: 0}], - }, - ); - expect(programAccountsDoMatchFilter).to.have.length(2); - } - - { - await mockRpcResponse({ - method: 'getProgramAccounts', - params: [ - programId.publicKey.toBase58(), - { - commitment: 'confirmed', - encoding: 'base64', - filters: [ - { - memcmp: { - encoding: 'base58', - offset: 0, - bytes: 'XzdZ3w', - }, - }, - ], - }, - ], - value: [], - }); - - const programAccountsDontMatchFilter = - await connection.getProgramAccounts(programId.publicKey, { - commitment: 'confirmed', - filters: [ - { - memcmp: { - offset: 0, - bytes: 'XzdZ3w', - }, - }, - ], - }); - expect(programAccountsDontMatchFilter).to.have.length(0); - } - - { - await mockRpcResponse({ - method: 'getProgramAccounts', - params: [ - programId.publicKey.toBase58(), - {commitment: 'confirmed', encoding: 'jsonParsed'}, - ], - value: [ - { - account: { - data: ['', 'base64'], - executable: false, - lamports: LAMPORTS_PER_SOL - feeCalculator.lamportsPerSignature, - owner: programId.publicKey.toBase58(), - rentEpoch: 20, - space: 0, - }, - pubkey: account0.publicKey.toBase58(), - }, - { - account: { - data: ['', 'base64'], - executable: false, - lamports: - 0.5 * LAMPORTS_PER_SOL - feeCalculator.lamportsPerSignature, - owner: programId.publicKey.toBase58(), - rentEpoch: 20, - space: 0, - }, - pubkey: account1.publicKey.toBase58(), - }, - ], - }); - - const programAccounts = await connection.getParsedProgramAccounts( - programId.publicKey, - { - commitment: 'confirmed', - }, - ); - expect(programAccounts).to.have.length(2); - - programAccounts.forEach(function (element) { - if (element.pubkey.equals(account0.publicKey)) { - expect(element.account.lamports).to.eq( - LAMPORTS_PER_SOL - feeCalculator.lamportsPerSignature, - ); - } else { - expect(element.pubkey).to.eql(account1.publicKey); - expect(element.account.lamports).to.eq( - 0.5 * LAMPORTS_PER_SOL - feeCalculator.lamportsPerSignature, - ); - } - }); - } - - { - await mockRpcResponse({ - method: 'getProgramAccounts', - params: [ - programId.publicKey.toBase58(), - { - commitment: 'confirmed', - encoding: 'jsonParsed', - filters: [ - { - dataSize: 2, - }, - ], - }, - ], - value: [], - }); - - const programAccountsDontMatchFilter = - await connection.getParsedProgramAccounts(programId.publicKey, { - commitment: 'confirmed', - filters: [{dataSize: 2}], - }); - expect(programAccountsDontMatchFilter).to.have.length(0); - } - - { - await mockRpcResponse({ - method: 'getProgramAccounts', - params: [ - programId.publicKey.toBase58(), - { - commitment: 'confirmed', - encoding: 'jsonParsed', - filters: [ - { - memcmp: { - encoding: 'base58', - offset: 0, - bytes: '', - }, - }, - ], - }, - ], - value: [ - { - account: { - data: ['', 'base64'], - executable: false, - lamports: LAMPORTS_PER_SOL - feeCalculator.lamportsPerSignature, - owner: programId.publicKey.toBase58(), - rentEpoch: 20, - space: 0, - }, - pubkey: account0.publicKey.toBase58(), - }, - { - account: { - data: ['', 'base64'], - executable: false, - lamports: - 0.5 * LAMPORTS_PER_SOL - feeCalculator.lamportsPerSignature, - owner: programId.publicKey.toBase58(), - rentEpoch: 20, - space: 0, - }, - pubkey: account1.publicKey.toBase58(), - }, - ], - }); - - const programAccountsDoMatchFilter = - await connection.getParsedProgramAccounts(programId.publicKey, { - commitment: 'confirmed', - filters: [ - { - memcmp: { - offset: 0, - bytes: '', - }, - }, - ], - }); - expect(programAccountsDoMatchFilter).to.have.length(2); - } - - { - await mockRpcResponse({ - method: 'getProgramAccounts', - params: [ - programId.publicKey.toBase58(), - { - commitment: 'confirmed', - withContext: true, - }, - ], - value: { - context: { - slot: 11, - }, - value: [], - }, - }); - const programAccountsWithContext = await connection.getProgramAccounts( - programId.publicKey, - { - commitment: 'confirmed', - withContext: true, - }, - ); - expect(programAccountsWithContext).to.have.nested.property( - 'context.slot', - ); - expect(programAccountsWithContext).to.have.property('value'); - } - }).timeout(30 * 1000); - - it('get balance', async () => { - const account = Keypair.generate(); - - await mockRpcResponse({ - method: 'getBalance', - params: [account.publicKey.toBase58()], - value: { - context: { - slot: 11, - }, - value: 0, - }, - }); - - const balance = await connection.getBalance(account.publicKey); - expect(balance).to.be.at.least(0); - }); - - it('get inflation', async () => { - await mockRpcResponse({ - method: 'getInflationGovernor', - params: [], - value: { - foundation: 0.05, - foundationTerm: 7.0, - initial: 0.15, - taper: 0.15, - terminal: 0.015, - }, - }); - - const inflation = await connection.getInflationGovernor(); - const inflationKeys: (keyof InflationGovernor)[] = [ - 'initial', - 'terminal', - 'taper', - 'foundation', - 'foundationTerm', - ]; - - for (const key of inflationKeys) { - expect(inflation).to.have.property(key); - expect(inflation[key]).to.be.greaterThan(0); - } - }); - - it('get inflation reward', async () => { - if (mockServer) { - await mockRpcResponse({ - method: 'getInflationReward', - params: [ - [ - '7GHnTRB8Rz14qZQhDXf8ox1Kfu7mPcPLpKaBJJirmYj2', - 'CrinLuHjVGDDcQfrEoCmM4k31Ni9sMoTCEEvNSUSh7Jg', - ], - { - epoch: 0, - }, - ], - value: [ - { - amount: 3646143, - effectiveSlot: 432000, - epoch: 0, - postBalance: 30504783, - commission: 0, - }, - null, - ], - }); - - const inflationReward = await connection.getInflationReward( - [ - new PublicKey('7GHnTRB8Rz14qZQhDXf8ox1Kfu7mPcPLpKaBJJirmYj2'), - new PublicKey('CrinLuHjVGDDcQfrEoCmM4k31Ni9sMoTCEEvNSUSh7Jg'), - ], - 0, - ); - - expect(inflationReward).to.have.lengthOf(2); - } - }); - - it('get inflation rate', async () => { - await mockRpcResponse({ - method: 'getInflationRate', - params: [], - value: { - total: 0.08, - validator: 0.076, - foundation: 0.004, - epoch: 1, - }, - }); - - const inflation = await connection.getInflationRate(); - const inflationKeys: (keyof InflationRate)[] = [ - 'total', - 'validator', - 'foundation', - 'epoch', - ]; - - for (const key of inflationKeys) { - expect(inflation).to.have.property(key); - if (mockServer) { - expect(inflation[key]).to.be.greaterThan(0); - } else { - expect(inflation[key]).to.be.at.least(0); - } - } - }); - - it('get epoch info', async () => { - await mockRpcResponse({ - method: 'getEpochInfo', - params: [{commitment: 'confirmed'}], - value: { - epoch: 0, - slotIndex: 1, - slotsInEpoch: 8192, - absoluteSlot: 1, - blockHeight: 1, - }, - }); - - const epochInfo = await connection.getEpochInfo('confirmed'); - const epochInfoKeys: (keyof EpochInfo)[] = [ - 'epoch', - 'slotIndex', - 'slotsInEpoch', - 'absoluteSlot', - 'blockHeight', - ]; - - for (const key of epochInfoKeys) { - expect(epochInfo).to.have.property(key); - expect(epochInfo[key]).to.be.at.least(0); - } - }); - - it('get epoch schedule', async () => { - await mockRpcResponse({ - method: 'getEpochSchedule', - params: [], - value: { - firstNormalEpoch: 8, - firstNormalSlot: 8160, - leaderScheduleSlotOffset: 8192, - slotsPerEpoch: 8192, - warmup: true, - }, - }); - - const epochSchedule = await connection.getEpochSchedule(); - const epochScheduleKeys: (keyof EpochSchedule)[] = [ - 'firstNormalEpoch', - 'firstNormalSlot', - 'leaderScheduleSlotOffset', - 'slotsPerEpoch', - ]; - - for (const key of epochScheduleKeys) { - expect(epochSchedule).to.have.property('warmup'); - expect(epochSchedule).to.have.property(key); - if (epochSchedule.warmup) { - expect(epochSchedule[key]).to.be.greaterThan(0); - } - } - }); - - it('get leader schedule', async () => { - await mockRpcResponse({ - method: 'getLeaderSchedule', - params: [], - value: { - '123vij84ecQEKUvQ7gYMKxKwKF6PbYSzCzzURYA4xULY': [0, 1, 2, 3], - '8PTjAikKoAybKXcEPnDSoy8wSNNikUBJ1iKawJKQwXnB': [4, 5, 6, 7], - }, - }); - - const leaderSchedule = await connection.getLeaderSchedule(); - expect(Object.keys(leaderSchedule).length).to.be.at.least(1); - for (const key in leaderSchedule) { - const slots = leaderSchedule[key]; - expect(Array.isArray(slots)).to.be.true; - expect(slots.length).to.be.at.least(4); - } - }).timeout(30 * 1000); - - it('get slot', async () => { - await mockRpcResponse({ - method: 'getSlot', - params: [], - value: 123, - }); - - const slot = await connection.getSlot(); - if (mockServer) { - expect(slot).to.eq(123); - } else { - // No idea what the correct slot value should be on a live cluster, so - // just check the type - expect(typeof slot).to.eq('number'); - } - }); - - it('get slot leader', async () => { - await mockRpcResponse({ - method: 'getSlotLeader', - params: [], - value: '11111111111111111111111111111111', - }); - - const slotLeader = await connection.getSlotLeader(); - if (mockServer) { - expect(slotLeader).to.eq('11111111111111111111111111111111'); - } else { - // No idea what the correct slotLeader value should be on a live cluster, so - // just check the type - expect(typeof slotLeader).to.eq('string'); - } - }); - - it('get slot leaders', async () => { - await mockRpcResponse({ - method: 'getSlotLeaders', - params: [0, 1], - value: ['11111111111111111111111111111111'], - }); - - const slotLeaders = await connection.getSlotLeaders(0, 1); - expect(slotLeaders).to.have.length(1); - expect(slotLeaders[0]).to.be.instanceOf(PublicKey); - }); - - it('get cluster nodes', async () => { - await mockRpcResponse({ - method: 'getClusterNodes', - params: [], - value: [ - { - pubkey: '11111111111111111111111111111111', - gossip: '127.0.0.0:1234', - tpu: '127.0.0.0:1235', - rpc: null, - version: '1.1.10', - }, - ], - }); - - const clusterNodes = await connection.getClusterNodes(); - if (mockServer) { - expect(clusterNodes).to.have.length(1); - expect(clusterNodes[0].pubkey).to.eq('11111111111111111111111111111111'); - expect(typeof clusterNodes[0].gossip).to.eq('string'); - expect(typeof clusterNodes[0].tpu).to.eq('string'); - expect(clusterNodes[0].rpc).to.be.null; - } else { - // There should be at least one node (the node that we're talking to) - expect(clusterNodes.length).to.be.greaterThan(0); - } - }); - - if (process.env.TEST_LIVE) { - it('get vote accounts', async () => { - const voteAccounts = await connection.getVoteAccounts(); - expect( - voteAccounts.current.concat(voteAccounts.delinquent).length, - ).to.be.greaterThan(0); - }); - } - - if (process.env.TEST_LIVE) { - describe('transaction sending error logs', () => { - it('sendAndConfirmTransaction skipPreflight: false', async () => { - const keypair = Keypair.generate(); - const destinationKeypair = Keypair.generate(); - - connection = new Connection(url, 'confirmed'); - let confirmOptions = { - skipPreflight: false, - commitment: connection.commitment, - preflightCommitment: connection.commitment, - maxRetries: 5, - minContextSlot: 0, - }; - - await connection.confirmTransaction( - await connection.requestAirdrop(keypair.publicKey, LAMPORTS_PER_SOL), - ); - - const transferSolTransaction = new Transaction().add( - SystemProgram.transfer({ - fromPubkey: keypair.publicKey, - toPubkey: destinationKeypair.publicKey, - lamports: 2 * LAMPORTS_PER_SOL, - }), - ); - - const sendPromise = sendAndConfirmTransaction( - connection, - transferSolTransaction, - [keypair], - confirmOptions, - ); - - await Promise.all([ - await expect(sendPromise).to.eventually.be.rejectedWith( - SendTransactionError, - /Transfer: insufficient lamports/, - ), - await expect(sendPromise).to.eventually.be.rejectedWith( - SendTransactionError, - /Program 11111111111111111111111111111111 failed: custom program error: 0x1/, - ), - ]); - }); - - it('sendAndConfirmTransaction skipPreflight: true', async () => { - const keypair = Keypair.generate(); - const destinationKeypair = Keypair.generate(); - - connection = new Connection(url, 'confirmed'); - let confirmOptions = { - skipPreflight: true, - commitment: connection.commitment, - preflightCommitment: connection.commitment, - maxRetries: 5, - minContextSlot: 0, - }; - - await connection.confirmTransaction( - await connection.requestAirdrop(keypair.publicKey, LAMPORTS_PER_SOL), - ); - - const transferSolTransaction = new Transaction().add( - SystemProgram.transfer({ - fromPubkey: keypair.publicKey, - toPubkey: destinationKeypair.publicKey, - lamports: 2 * LAMPORTS_PER_SOL, - }), - ); - - try { - await sendAndConfirmTransaction( - connection, - transferSolTransaction, - [keypair], - confirmOptions, - ); - throw new Error('Expected an error but did not get one'); - } catch (error) { - if (error instanceof SendTransactionError) { - const logsPromise: Promise = error.getLogs(connection); - - await Promise.all([ - expect(logsPromise).to.eventually.satisfy((logs: string[]) => - logs.some(log => - log.includes('Transfer: insufficient lamports'), - ), - ), - expect(logsPromise).to.eventually.satisfy((logs: string[]) => - logs.some(log => - log.includes( - 'Program 11111111111111111111111111111111 failed: custom program error: 0x1', - ), - ), - ), - ]); - } - } - }); - - it('sendAndConfirmRawTransaction skipPreflight: true', async () => { - const keypair = Keypair.generate(); - const destinationKeypair = Keypair.generate(); - - connection = new Connection(url, 'confirmed'); - let confirmOptions = { - skipPreflight: true, - commitment: connection.commitment, - preflightCommitment: connection.commitment, - maxRetries: 5, - minContextSlot: 0, - }; - - await connection.confirmTransaction( - await connection.requestAirdrop(keypair.publicKey, LAMPORTS_PER_SOL), - ); - - const transferSolTransaction = new Transaction().add( - SystemProgram.transfer({ - fromPubkey: keypair.publicKey, - toPubkey: destinationKeypair.publicKey, - lamports: 2 * LAMPORTS_PER_SOL, - }), - ); - - transferSolTransaction.recentBlockhash = ( - await connection.getRecentBlockhash('confirmed') - ).blockhash; - transferSolTransaction.sign(keypair); - - try { - await sendAndConfirmRawTransaction( - connection, - transferSolTransaction.serialize(), - confirmOptions, - ); - } catch (error) { - if (error instanceof SendTransactionError) { - const logsPromise: Promise = error.getLogs(connection); - - await Promise.all([ - expect(logsPromise).to.eventually.satisfy((logs: string[]) => - logs.some(log => - log.includes('Transfer: insufficient lamports'), - ), - ), - expect(logsPromise).to.eventually.satisfy((logs: string[]) => - logs.some(log => - log.includes( - 'Program 11111111111111111111111111111111 failed: custom program error: 0x1', - ), - ), - ), - ]); - } - } - }); - - it('sendAndConfirmRawTransaction skipPreflight: false', async () => { - const keypair = Keypair.generate(); - const destinationKeypair = Keypair.generate(); - - connection = new Connection(url, 'confirmed'); - let confirmOptions = { - skipPreflight: false, - commitment: connection.commitment, - preflightCommitment: connection.commitment, - maxRetries: 5, - minContextSlot: 0, - }; - - await connection.confirmTransaction( - await connection.requestAirdrop(keypair.publicKey, LAMPORTS_PER_SOL), - ); - - const transferSolTransaction = new Transaction().add( - SystemProgram.transfer({ - fromPubkey: keypair.publicKey, - toPubkey: destinationKeypair.publicKey, - lamports: 2 * LAMPORTS_PER_SOL, - }), - ); - - transferSolTransaction.recentBlockhash = ( - await connection.getRecentBlockhash('confirmed') - ).blockhash; - transferSolTransaction.sign(keypair); - - const sendPromise = sendAndConfirmRawTransaction( - connection, - transferSolTransaction.serialize(), - confirmOptions, - ); - - await Promise.all([ - await expect(sendPromise).to.eventually.be.rejectedWith( - SendTransactionError, - /Transfer: insufficient lamports/, - ), - await expect(sendPromise).to.eventually.be.rejectedWith( - SendTransactionError, - /Program 11111111111111111111111111111111 failed: custom program error: 0x1/, - ), - ]); - }); - - it('Simulate transaction contains logs', async () => { - const keypair = Keypair.generate(); - const destinationKeypair = Keypair.generate(); - - connection = new Connection(url, 'confirmed'); - - await connection.confirmTransaction( - await connection.requestAirdrop(keypair.publicKey, LAMPORTS_PER_SOL), - ); - - const transferSolTransaction = new Transaction().add( - SystemProgram.transfer({ - fromPubkey: keypair.publicKey, - toPubkey: destinationKeypair.publicKey, - lamports: 2 * LAMPORTS_PER_SOL, - }), - ); - - transferSolTransaction.recentBlockhash = ( - await connection.getRecentBlockhash('confirmed') - ).blockhash; - transferSolTransaction.sign(keypair); - - const simulationResultPromise = connection.simulateTransaction( - transferSolTransaction, - [keypair], - ); - - await Promise.all([ - expect(simulationResultPromise) - .to.eventually.have.nested.property('value.logs') - .that.satisfies((logs: string[]) => - logs.some(log => log.includes('Transfer: insufficient lamports')), - ), - expect(simulationResultPromise) - .to.eventually.have.nested.property('value.logs') - .that.satisfies((logs: string[]) => - logs.some(log => - log.includes( - 'Program 11111111111111111111111111111111 failed: custom program error: 0x1', - ), - ), - ), - ]); - }); - }); - } - - if (process.env.TEST_LIVE) { - describe('transaction confirmation (live)', () => { - let connection: Connection; - beforeEach(() => { - connection = new Connection(url, 'confirmed'); - }); - - describe('blockheight based transaction confirmation', () => { - let latestBlockhash: { - blockhash: string; - lastValidBlockHeight: number; - }; - let signature: string; - - beforeEach(async function () { - this.timeout(60 * 1000); - const keypair = Keypair.generate(); - const [ - // eslint-disable-next-line @typescript-eslint/no-unused-vars - _, - blockhash, - ] = await Promise.all([ - connection.confirmTransaction( - await connection.requestAirdrop( - keypair.publicKey, - LAMPORTS_PER_SOL, - ), - ), - helpers.latestBlockhash({connection}), - ]); - latestBlockhash = blockhash; - const ix = new TransactionInstruction({ - keys: [ - { - pubkey: keypair.publicKey, - isSigner: true, - isWritable: true, - }, - ], - programId: new PublicKey( - 'MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr', - ), - data: Buffer.from('Hello world', 'utf8'), - }); - - const transaction = new Transaction({ - ...latestBlockhash, - }); - transaction.add(ix); - transaction.sign(keypair); - signature = await connection.sendTransaction(transaction, [keypair]); - }); - - it('confirms transactions using the last valid blockheight strategy', async () => { - let result = await connection.confirmTransaction( - { - signature, - ...latestBlockhash, - }, - 'processed', - ); - expect(result.value).to.have.property('err', null); - }).timeout(60 * 1000); - - it('throws when confirming using a blockhash whose last valid blockheight has passed', async () => { - const confirmationPromise = connection.confirmTransaction({ - signature, - ...latestBlockhash, - lastValidBlockHeight: (await connection.getBlockHeight()) - 1, // Simulate the blockheight having passed. - }); - expect(confirmationPromise).to.eventually.be.rejectedWith( - TransactionExpiredBlockheightExceededError, - ); - }).timeout(60 * 1000); - }); - - describe('nonce-based transaction confirmation', () => { - let keypair: Keypair; - let minContextSlot: number; - let nonceInfo: NonceInformation; - let nonceKeypair: Keypair; - let transaction: Transaction; - - beforeEach(async function () { - this.timeout(60 * 1000); - keypair = Keypair.generate(); - nonceKeypair = Keypair.generate(); - const [ - // eslint-disable-next-line @typescript-eslint/no-unused-vars - _, - blockhash, - minimumNonceAccountRentLamports, - ] = await Promise.all([ - connection.confirmTransaction( - await connection.requestAirdrop( - keypair.publicKey, - LAMPORTS_PER_SOL, - ), - ), - helpers.latestBlockhash({connection}), - connection.getMinimumBalanceForRentExemption(NONCE_ACCOUNT_LENGTH), - ]); - const createNonceAccountTransaction = - SystemProgram.createNonceAccount({ - authorizedPubkey: keypair.publicKey, - fromPubkey: keypair.publicKey, - lamports: minimumNonceAccountRentLamports, - noncePubkey: nonceKeypair.publicKey, - }); - createNonceAccountTransaction.recentBlockhash = blockhash.blockhash; - createNonceAccountTransaction.feePayer = keypair.publicKey; - const createNonceAccountTransactionSignature = - await connection.sendTransaction(createNonceAccountTransaction, [ - keypair, - nonceKeypair, - ]); - const {context} = await connection.confirmTransaction({ - ...blockhash, - signature: createNonceAccountTransactionSignature, - }); - minContextSlot = context.slot; - const nonceAccount = await connection.getNonce( - nonceKeypair.publicKey, - {minContextSlot}, - ); - nonceInfo = { - nonce: nonceAccount!.nonce, - nonceInstruction: SystemProgram.nonceAdvance({ - authorizedPubkey: keypair.publicKey, - noncePubkey: nonceKeypair.publicKey, - }), - }; - invariant( - nonceAccount, - 'Expected a nonce account to have been created in the test setup', - ); - const ix = new TransactionInstruction({ - keys: [ - { - pubkey: keypair.publicKey, - isSigner: true, - isWritable: true, - }, - ], - programId: new PublicKey( - 'MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr', - ), - data: Buffer.from('Hello world', 'utf8'), - }); - transaction = new Transaction({minContextSlot, nonceInfo}); - transaction.add(ix); - transaction.sign(keypair); - }); - - it('confirms transactions using the durable nonce strategy', async () => { - const signature = await connection.sendTransaction(transaction, [ - keypair, - ]); - const result = await connection.confirmTransaction( - { - minContextSlot, - nonceAccountPubkey: nonceKeypair.publicKey, - nonceValue: nonceInfo.nonce, - signature, - }, - 'processed', - ); - expect(result.value).to.have.property('err', null); - }).timeout(60 * 1000); - - it('throws when confirming using a nonce that is no longer valid', async () => { - // Advance the nonce. - const blockhash = await connection.getLatestBlockhash(); - await sendAndConfirmTransaction( - connection, - new Transaction({feePayer: keypair.publicKey, ...blockhash}).add( - nonceInfo.nonceInstruction, - ), - [keypair], - ); - const [currentSlot, signature] = await Promise.all([ - connection.getSlot(), - connection.sendTransaction(transaction, [keypair], { - skipPreflight: true, - }), - ]); - const confirmationPromise = connection.confirmTransaction({ - minContextSlot: currentSlot, - nonceAccountPubkey: nonceKeypair.publicKey, - nonceValue: nonceInfo.nonce, // The old nonce. - signature, - }); - await expect(confirmationPromise).to.eventually.be.rejectedWith( - TransactionExpiredNonceInvalidError, - ); - }).timeout(60 * 1000); - }); - }); - } - - if (!process.env.TEST_LIVE) { - describe('transaction confirmation (mock)', () => { - let clock: SinonFakeTimers; - beforeEach(() => { - clock = useFakeTimers(); - }); - - afterEach(() => { - clock.restore(); - }); - - describe('timeout strategy (deprecated)', () => { - it('throws a `TransactionExpiredTimeoutError` when the timer elapses without a signature confirmation', async () => { - const mockSignature = - 'w2Zeq8YkpyB463DttvfzARD7k9ZxGEwbsEw4boEK7jDp3pfoxZbTdLFSsEPhzXhpCcjGi2kHtHFobgX49MMhbWt'; - - await mockRpcMessage({ - method: 'signatureSubscribe', - params: [mockSignature, {commitment: 'finalized'}], - result: new Promise(() => {}), - }); - const timeoutPromise = connection.confirmTransaction(mockSignature); - - // Advance the clock past all waiting timers, notably the expiry timer. - clock.runAllAsync(); - - await expect(timeoutPromise).to.be.rejectedWith( - TransactionExpiredTimeoutError, - ); - }); - }); - - describe('block height strategy', () => { - it('rejects if called with an already-aborted `abortSignal`', () => { - const mockSignature = - 'w2Zeq8YkpyB463DttvfzARD7k9ZxGEwbsEw4boEK7jDp3pfoxZbTdLFSsEPhzXhpCcjGi2kHtHFobgX49MMhbWt'; - const abortController: any = - nodeVersion >= 16 ? new AbortController() : Node14Controller(); - abortController.abort(); - expect( - connection.confirmTransaction({ - abortSignal: abortController.signal, - blockhash: 'sampleBlockhash', - lastValidBlockHeight: 1, - signature: mockSignature, - }), - ).to.eventually.be.rejectedWith('AbortError'); - }); - - it('rejects upon receiving an abort signal', async () => { - const mockSignature = - 'w2Zeq8YkpyB463DttvfzARD7k9ZxGEwbsEw4boEK7jDp3pfoxZbTdLFSsEPhzXhpCcjGi2kHtHFobgX49MMhbWt'; - const abortController: any = - nodeVersion >= 16 ? new AbortController() : Node14Controller(); - // Keep the subscription from ever returning data. - await mockRpcMessage({ - method: 'signatureSubscribe', - params: [mockSignature, {commitment: 'finalized'}], - result: new Promise(() => {}), // Never resolve. - }); - clock.runAllAsync(); - const confirmationPromise = connection.confirmTransaction({ - abortSignal: abortController.signal, - blockhash: 'sampleBlockhash', - lastValidBlockHeight: 1, - signature: mockSignature, - }); - clock.runAllAsync(); - expect(confirmationPromise).not.to.have.been.rejected; - abortController.abort(); - await expect(confirmationPromise).to.eventually.be.rejected; - }); - - it('throws a `TransactionExpiredBlockheightExceededError` when the block height advances past the last valid one for this transaction without a signature confirmation', async () => { - const mockSignature = - '4oCEqwGrMdBeMxpzuWiukCYqSfV4DsSKXSiVVCh1iJ6pS772X7y219JZP3mgqBz5PhsvprpKyhzChjYc3VSBQXzG'; - - await mockRpcMessage({ - method: 'signatureSubscribe', - params: [mockSignature, {commitment: 'finalized'}], - result: new Promise(() => {}), // Never resolve this = never get a response. - }); - - const lastValidBlockHeight = 3; - - // Start the block height at `lastValidBlockHeight - 1`. - await mockRpcResponse({ - method: 'getBlockHeight', - params: [], - value: lastValidBlockHeight - 1, - }); - - const confirmationPromise = connection.confirmTransaction({ - signature: mockSignature, - blockhash: 'sampleBlockhash', - lastValidBlockHeight, - }); - clock.runAllAsync(); - - // Advance the block height to the `lastValidBlockHeight`. - await mockRpcResponse({ - method: 'getBlockHeight', - params: [], - value: lastValidBlockHeight, - }); - clock.runAllAsync(); - - // Advance the block height to `lastValidBlockHeight + 1`, - // past the last valid blockheight for this transaction. - await mockRpcResponse({ - method: 'getBlockHeight', - params: [], - value: lastValidBlockHeight + 1, - }); - clock.runAllAsync(); - await expect(confirmationPromise).to.be.rejectedWith( - TransactionExpiredBlockheightExceededError, - ); - }); - - it('when the `getBlockHeight` method throws an error it does not timeout but rather keeps waiting for a confirmation', async () => { - const mockSignature = - 'LPJ18iiyfz3G1LpNNbcBnBtaS4dVBdPHKrnELqikjER2DcvB4iyTgz43nKQJH3JQAJHuZdM1xVh5Cnc5Hc7LrqC'; - - let resolveResultPromise = function (result: SignatureResult): any { - return result; - }; - - await mockRpcMessage({ - method: 'signatureSubscribe', - params: [mockSignature, {commitment: 'finalized'}], - result: new Promise(resolve => { - resolveResultPromise = resolve; - }), - }); - - // Simulate a failure to fetch the block height. - let rejectBlockheightPromise = function (): void {}; - await mockRpcResponse({ - method: 'getBlockHeight', - params: [], - value: (() => { - const p = new Promise((_, reject) => { - rejectBlockheightPromise = reject; - }); - p.catch(() => {}); - return p; - })(), - }); - - const confirmationPromise = connection.confirmTransaction({ - signature: mockSignature, - blockhash: 'sampleBlockhash', - lastValidBlockHeight: 3, - }); - - rejectBlockheightPromise(); - clock.runToLastAsync(); - resolveResultPromise({err: null}); - clock.runToLastAsync(); - - expect(confirmationPromise).not.to.eventually.be.rejected; - }); - - it('confirms the transaction if the signature confirmation is received before the block height is exceeded', async () => { - const mockSignature = - 'LPJ18iiyfz3G1LpNNbcBnBtaS4dVBdPHKrnELqikjER2DcvB4iyTgz43nKQJH3JQAJHuZdM1xVh5Cnc5Hc7LrqC'; - - let resolveResultPromise = function (result: SignatureResult): any { - return result; - }; - await mockRpcMessage({ - method: 'signatureSubscribe', - params: [mockSignature, {commitment: 'finalized'}], - result: new Promise(resolve => { - resolveResultPromise = resolve; - }), - }); - - const lastValidBlockHeight = 3; - - // Advance the block height to the `lastValidBlockHeight`. - await mockRpcResponse({ - method: 'getBlockHeight', - params: [], - value: lastValidBlockHeight, - }); - - const confirmationPromise = connection.confirmTransaction({ - signature: mockSignature, - blockhash: 'sampleBlockhash', - lastValidBlockHeight, - }); - clock.runAllAsync(); - - // Return a signature result in the nick of time. - resolveResultPromise({err: null}); - - await expect(confirmationPromise).to.eventually.deep.equal({ - context: {slot: 11}, - value: {err: null}, - }); - }); - }); - - describe('nonce strategy', () => { - it('rejects if called with an already-aborted `abortSignal`', () => { - const mockSignature = - 'w2Zeq8YkpyB463DttvfzARD7k9ZxGEwbsEw4boEK7jDp3pfoxZbTdLFSsEPhzXhpCcjGi2kHtHFobgX49MMhbWt'; - const abortController: any = - nodeVersion >= 16 ? new AbortController() : Node14Controller(); - abortController.abort(); - expect( - connection.confirmTransaction({ - abortSignal: abortController.signal, - minContextSlot: 1, - nonceAccountPubkey: new PublicKey(1), - nonceValue: 'fakenonce', - signature: mockSignature, - }), - ).to.eventually.be.rejectedWith('AbortError'); - }); - - it('rejects upon receiving an abort signal', async () => { - const mockSignature = - 'w2Zeq8YkpyB463DttvfzARD7k9ZxGEwbsEw4boEK7jDp3pfoxZbTdLFSsEPhzXhpCcjGi2kHtHFobgX49MMhbWt'; - const abortController: any = - nodeVersion >= 16 ? new AbortController() : Node14Controller(); - // Keep the subscription from ever returning data. - await mockRpcMessage({ - method: 'signatureSubscribe', - params: [mockSignature, {commitment: 'finalized'}], - result: new Promise(() => {}), // Never resolve. - }); - clock.runAllAsync(); - const confirmationPromise = connection.confirmTransaction({ - abortSignal: abortController.signal, - minContextSlot: 1, - nonceAccountPubkey: new PublicKey(1), - nonceValue: 'fakenonce', - signature: mockSignature, - }); - clock.runAllAsync(); - expect(confirmationPromise).not.to.have.been.rejected; - abortController.abort(); - await expect(confirmationPromise).to.eventually.be.rejected; - }); - - it('confirms the transaction if the signature confirmation is received before the nonce is advanced', async () => { - const mockSignature = - '4oCEqwGrMdBeMxpzuWiukCYqSfV4DsSKXSiVVCh1iJ6pS772X7y219JZP3mgqBz5PhsvprpKyhzChjYc3VSBQXzG'; - - let resolveResultPromise = function (result: SignatureResult): any { - return result; - }; - await mockRpcMessage({ - method: 'signatureSubscribe', - params: [mockSignature, {commitment: 'finalized'}], - result: new Promise(resolve => { - resolveResultPromise = resolve; - }), - }); - - const nonceAccountPubkey = new PublicKey(1); - const nonceValue = new PublicKey(2).toBase58(); - const authority = new PublicKey(3); - - // Start with the nonce account matching the nonce used to sign the transaction. - await mockNonceAccountResponse( - nonceAccountPubkey.toBase58(), - nonceValue, - authority.toBase58(), - ); - - const confirmationPromise = connection.confirmTransaction({ - minContextSlot: 0, - nonceAccountPubkey, - nonceValue, - signature: mockSignature, - }); - clock.runAllAsync(); - - // Respond, a second time, with the same nonce hash. - await mockNonceAccountResponse( - nonceAccountPubkey.toBase58(), - nonceValue, - authority.toBase58(), - ); - clock.runAllAsync(); - - // Return a signature result in the nick of time. - resolveResultPromise({err: null}); - - await expect(confirmationPromise).to.eventually.deep.equal({ - context: {slot: 11}, - value: {err: null}, - }); - }); - - it('succeeds if double-checking the signature after the nonce-advances demonstrates that the transaction is confirmed', async () => { - const mockSignature = - 'LPJ18iiyfz3G1LpNNbcBnBtaS4dVBdPHKrnELqikjER2DcvB4iyTgz43nKQJH3JQAJHuZdM1xVh5Cnc5Hc7LrqC'; - - await mockRpcMessage({ - method: 'signatureSubscribe', - params: [mockSignature, {commitment: 'finalized'}], - result: new Promise(() => {}), // Never resolve this = never get a response. - }); - - const nonceAccountPubkey = new PublicKey(1); - const nonceValue = new PublicKey(2).toBase58(); - const authority = new PublicKey(3); - - const confirmationPromise = connection.confirmTransaction({ - minContextSlot: 0, - nonceAccountPubkey, - nonceValue, - signature: mockSignature, - }); - - // Simulate the nonce advancing but the double-check of the signature status succeeding. - await mockNonceAccountResponse( - nonceAccountPubkey.toBase58(), - new PublicKey(4).toBase58(), // A new nonce. - authority.toBase58(), - ); - await mockRpcResponse({ - method: 'getSignatureStatuses', - params: [[mockSignature]], - value: [ - { - err: null, - confirmations: 0, - confirmationStatus: 'finalized', // Demonstrate that the transaction is, in fact, confirmed. - slot: 0, - }, - ], - withContext: true, - }); - clock.runToLastAsync(); - - await expect(confirmationPromise).to.eventually.deep.equal({ - context: {slot: 11}, - value: {err: null}, - }); - }); - - it('keeps double-checking the signature after the nonce-advances until a signature from the minimum allowable slot is obtained', async () => { - const mockSignature = - 'LPJ18iiyfz3G1LpNNbcBnBtaS4dVBdPHKrnELqikjER2DcvB4iyTgz43nKQJH3JQAJHuZdM1xVh5Cnc5Hc7LrqC'; - - await mockRpcMessage({ - method: 'signatureSubscribe', - params: [mockSignature, {commitment: 'finalized'}], - result: new Promise(() => {}), // Never resolve this = never get a response. - }); - - const nonceAccountPubkey = new PublicKey(1); - const nonceValue = new PublicKey(2).toBase58(); - const authority = new PublicKey(3); - - const confirmationPromise = connection.confirmTransaction({ - minContextSlot: 11, - nonceAccountPubkey, - nonceValue, - signature: mockSignature, - }); - - // Simulate the nonce advancing but the double-check of the signature status succeeding. - await mockNonceAccountResponse( - nonceAccountPubkey.toBase58(), - new PublicKey(4).toBase58(), // A new nonce. - authority.toBase58(), - ); - - // Simulate getting a response from an old slot. - await mockRpcResponse({ - method: 'getSignatureStatuses', - params: [[mockSignature]], - value: [ - { - err: null, - confirmations: 0, - confirmationStatus: 'processed', // A non-finalized value from an old slot. - slot: 10, - }, - ], - slot: 10, - withContext: true, - }); - - // Then obtain a response from the minimum allowable slot. - await mockRpcResponse({ - method: 'getSignatureStatuses', - params: [[mockSignature]], - value: [ - { - err: null, - confirmations: 32, - confirmationStatus: 'finalized', // Demonstrate that the transaction is, in fact, confirmed. - slot: 11, - }, - ], - slot: 11, - withContext: true, - }); - clock.runAllAsync(); - - await expect(confirmationPromise).to.eventually.deep.equal({ - context: {slot: 11}, - value: {err: null}, - }); - }); - - it('throws a `TransactionExpiredNonceInvalidError` when the nonce is no longer the one with which this transaction was signed', async () => { - const mockSignature = - 'LPJ18iiyfz3G1LpNNbcBnBtaS4dVBdPHKrnELqikjER2DcvB4iyTgz43nKQJH3JQAJHuZdM1xVh5Cnc5Hc7LrqC'; - - await mockRpcMessage({ - method: 'signatureSubscribe', - params: [mockSignature, {commitment: 'finalized'}], - result: new Promise(() => {}), // Never resolve this = never get a response. - }); - - const nonceAccountPubkey = new PublicKey(1); - const nonceValue = new PublicKey(2).toBase58(); - const authority = new PublicKey(3); - - const confirmationPromise = connection.confirmTransaction({ - minContextSlot: 0, - nonceAccountPubkey, - nonceValue, - signature: mockSignature, - }); - - // Simulate the nonce advancing but the double-check of the signature status succeeding. - await mockNonceAccountResponse( - nonceAccountPubkey.toBase58(), - new PublicKey(4).toBase58(), // A new nonce. - authority.toBase58(), - ); - await mockRpcResponse({ - method: 'getSignatureStatuses', - params: [[mockSignature]], - value: [ - { - err: null, - confirmations: 0, - confirmationStatus: 'processed', // Demonstrate that the transaction is, in fact, not confirmed. - slot: 0, - }, - ], - withContext: true, - }); - clock.runToLastAsync(); - - await expect(confirmationPromise).to.eventually.be.rejectedWith( - TransactionExpiredNonceInvalidError, - ); - }); - - it('when fetching the nonce account throws an error it does not timeout but rather keeps waiting for a confirmation', async () => { - const mockSignature = - 'LPJ18iiyfz3G1LpNNbcBnBtaS4dVBdPHKrnELqikjER2DcvB4iyTgz43nKQJH3JQAJHuZdM1xVh5Cnc5Hc7LrqC'; - - let resolveResultPromise = function (result: SignatureResult): any { - return result; - }; - await mockRpcMessage({ - method: 'signatureSubscribe', - params: [mockSignature, {commitment: 'finalized'}], - result: new Promise(resolve => { - resolveResultPromise = resolve; - }), - }); - - // Simulate a failure to fetch the nonce account. - let rejectNonceAccountFetchPromise = function (): void {}; - await mockRpcResponse({ - method: 'getAccountInfo', - params: [], - value: (() => { - const p = new Promise((_, reject) => { - rejectNonceAccountFetchPromise = reject; - }); - p.catch(() => {}); - return p; - })(), - }); - - const nonceAccountPubkey = new PublicKey(1); - const nonceValue = new PublicKey(2).toBase58(); - - const confirmationPromise = connection.confirmTransaction({ - minContextSlot: 0, - nonceAccountPubkey, - nonceValue, - signature: mockSignature, - }); - - rejectNonceAccountFetchPromise(); - clock.runToLastAsync(); - resolveResultPromise({err: null}); - clock.runToLastAsync(); - - await expect(confirmationPromise).to.eventually.deep.equal({ - context: {slot: 11}, - value: {err: null}, - }); - }); - - it('throws `TransactionExpiredNonceInvalidError` when the nonce account does not exist', async () => { - const mockSignature = - 'LPJ18iiyfz3G1LpNNbcBnBtaS4dVBdPHKrnELqikjER2DcvB4iyTgz43nKQJH3JQAJHuZdM1xVh5Cnc5Hc7LrqC'; - - await mockRpcMessage({ - method: 'signatureSubscribe', - params: [mockSignature, {commitment: 'finalized'}], - result: new Promise(() => {}), // Never resolve this = never get a response. - }); - - const nonceAccountPubkey = new PublicKey(1); - const nonceValue = new PublicKey(2).toBase58(); - - const confirmationPromise = connection.confirmTransaction({ - minContextSlot: 0, - nonceAccountPubkey, - nonceValue, - signature: mockSignature, - }); - - // Simulate a non-existent nonce account. - await mockRpcResponse({ - method: 'getAccountInfo', - params: [], - value: null, - withContext: true, - }); - clock.runToLastAsync(); - await mockRpcResponse({ - method: 'getSignatureStatuses', - params: [[mockSignature]], - value: [ - { - err: null, - confirmations: 0, - confirmationStatus: 'processed', // Demonstrate that the transaction is, in fact, not confirmed. - slot: 0, - }, - ], - withContext: true, - }); - clock.runToLastAsync(); - - await expect(confirmationPromise).to.eventually.be.rejectedWith( - TransactionExpiredNonceInvalidError, - ); - }); - - it('when the nonce account data fails to deserialize', async () => { - const mockSignature = - 'LPJ18iiyfz3G1LpNNbcBnBtaS4dVBdPHKrnELqikjER2DcvB4iyTgz43nKQJH3JQAJHuZdM1xVh5Cnc5Hc7LrqC'; - - let resolveResultPromise = function (result: SignatureResult): any { - return result; - }; - await mockRpcMessage({ - method: 'signatureSubscribe', - params: [mockSignature, {commitment: 'finalized'}], - result: new Promise(resolve => { - resolveResultPromise = resolve; - }), - }); - - const nonceAccountPubkey = new PublicKey(1); - const nonceValue = new PublicKey(2).toBase58(); - - // Simulate a failure to deserialize the nonce. - await mockRpcResponse({ - method: 'getAccountInfo', - params: [nonceAccountPubkey.toBase58(), {encoding: 'base64'}], - value: { - owner: SystemProgram.programId.toBase58(), - lamports: LAMPORTS_PER_SOL, - data: ['JUNK_DATA', 'base64'], - executable: false, - rentEpoch: 20, - space: 0, - }, - withContext: true, - }); - - const confirmationPromise = connection.confirmTransaction({ - minContextSlot: 0, - nonceAccountPubkey, - nonceValue, - signature: mockSignature, - }); - clock.runToLastAsync(); - - resolveResultPromise({err: null}); - clock.runToLastAsync(); - - await expect(confirmationPromise).to.eventually.deep.equal({ - context: {slot: 11}, - value: {err: null}, - }); - }); - }); - - it('confirm transaction - does not check the signature status before the signature subscription comes alive', async () => { - const mockSignature = - 'w2Zeq8YkpyB463DttvfzARD7k9ZxGEwbsEw4boEK7jDp3pfoxZbTdLFSsEPhzXhpCcjGi2kHtHFobgX49MMhbWt'; - - await mockRpcMessage({ - method: 'signatureSubscribe', - params: [mockSignature, {commitment: 'finalized'}], - result: {err: null}, - subscriptionEstablishmentPromise: new Promise(() => {}), // Never resolve. - }); - const getSignatureStatusesExpectation = mock(connection) - .expects('getSignatureStatuses') - .never(); - connection.confirmTransaction(mockSignature); - getSignatureStatusesExpectation.verify(); - }); - - it('confirm transaction - checks the signature status once the signature subscription comes alive', async () => { - const mockSignature = - 'w2Zeq8YkpyB463DttvfzARD7k9ZxGEwbsEw4boEK7jDp3pfoxZbTdLFSsEPhzXhpCcjGi2kHtHFobgX49MMhbWt'; - - await mockRpcMessage({ - method: 'signatureSubscribe', - params: [mockSignature, {commitment: 'finalized'}], - result: {err: null}, - }); - const getSignatureStatusesExpectation = mock(connection) - .expects('getSignatureStatuses') - .once(); - - const confirmationPromise = - connection.confirmTransaction(mockSignature); - clock.runAllAsync(); - - await expect(confirmationPromise).to.eventually.deep.equal({ - context: {slot: 11}, - value: {err: null}, - }); - getSignatureStatusesExpectation.verify(); - }); - - // FIXME: This test does not work. - // it('confirm transaction - confirms transaction when signature status check yields confirmation before signature subscription does', async () => { - // const mockSignature = - // 'w2Zeq8YkpyB463DttvfzARD7k9ZxGEwbsEw4boEK7jDp3pfoxZbTdLFSsEPhzXhpCcjGi2kHtHFobgX49MMhbWt'; - - // // Keep the subscription from ever returning data. - // await mockRpcMessage({ - // method: 'signatureSubscribe', - // params: [mockSignature, {commitment: 'finalized'}], - // result: new Promise(() => {}), // Never resolve. - // }); - // clock.runAllAsync(); - - // const confirmationPromise = - // connection.confirmTransaction(mockSignature); - // clock.runAllAsync(); - - // // Return a signature status through the RPC API. - // await mockRpcResponse({ - // method: 'getSignatureStatuses', - // params: [[mockSignature]], - // value: [ - // { - // slot: 0, - // confirmations: 11, - // status: {Ok: null}, - // err: null, - // }, - // ], - // }); - // clock.runAllAsync(); - - // await expect(confirmationPromise).to.eventually.deep.equal({ - // context: {slot: 11}, - // value: {err: null}, - // }); - // }); - - it('confirm transaction - does not confirm the transaction when signature status check yields confirmation for a lower commitment before signature subscription confirms the transaction', async () => { - const mockSignature = - 'w2Zeq8YkpyB463DttvfzARD7k9ZxGEwbsEw4boEK7jDp3pfoxZbTdLFSsEPhzXhpCcjGi2kHtHFobgX49MMhbWt'; - - // Keep the subscription from ever returning data. - await mockRpcMessage({ - method: 'signatureSubscribe', - params: [mockSignature, {commitment: 'finalized'}], - result: new Promise(() => {}), // Never resolve. - }); - clock.runAllAsync(); - - const confirmationPromise = - connection.confirmTransaction(mockSignature); - clock.runAllAsync(); - - // Return a signature status with a lower finality through the RPC API. - await mockRpcResponse({ - method: 'getSignatureStatuses', - params: [[mockSignature]], - value: [ - { - slot: 0, - confirmations: null, - confirmationStatus: 'processed', // Lower than we expect - err: null, - }, - ], - }); - clock.runAllAsync(); - - await expect(confirmationPromise).to.be.rejectedWith( - TransactionExpiredTimeoutError, - ); - }); - }); - } - - describe('transaction confirmation', () => { - it('confirm transaction - error', async () => { - const badTransactionSignature = 'bad transaction signature'; - - await expect( - connection.confirmTransaction({ - blockhash: 'sampleBlockhash', - lastValidBlockHeight: 9999, - signature: badTransactionSignature, - }), - ).to.be.rejectedWith('signature must be base58 encoded'); - - await mockRpcResponse({ - method: 'getSignatureStatuses', - params: [[badTransactionSignature]], - error: mockErrorResponse, - }); - - await expect( - connection.getSignatureStatus(badTransactionSignature), - ).to.be.rejectedWith(mockErrorMessage); - }); - }); - - it('get transaction count', async () => { - await mockRpcResponse({ - method: 'getTransactionCount', - params: [], - value: 1000000, - }); - - const count = await connection.getTransactionCount(); - expect(count).to.be.at.least(0); - }); - - it('get total supply', async () => { - await mockRpcResponse({ - method: 'getSupply', - params: [], - value: { - total: 1000000, - circulating: 100000, - nonCirculating: 900000, - nonCirculatingAccounts: [], - }, - withContext: true, - }); - - const count = await connection.getTotalSupply(); - expect(count).to.be.at.least(0); - }); - - it('get minimum balance for rent exemption', async () => { - await mockRpcResponse({ - method: 'getMinimumBalanceForRentExemption', - params: [512], - value: 1000000, - }); - - const count = await connection.getMinimumBalanceForRentExemption(512); - expect(count).to.be.at.least(0); - }); - - it('get confirmed signatures for address', async function () { - const connection = new Connection(url); - - await mockRpcResponse({ - method: 'getSlot', - params: [], - value: 2, - }); - - await waitForSlot.call(this, connection, 1); - - await mockRpcResponse({ - method: 'getConfirmedBlock', - params: [1], - value: { - blockTime: 1614281964, - blockhash: '57zQNBZBEiHsCZFqsaY6h176ioXy5MsSLmcvHkEyaLGy', - previousBlockhash: 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo', - parentSlot: 0, - transactions: [ - { - meta: { - fee: 10000, - postBalances: [499260347380, 15298080, 1, 1, 1], - preBalances: [499260357380, 15298080, 1, 1, 1], - status: {Ok: null}, - err: null, - }, - transaction: { - message: { - accountKeys: [ - 'va12u4o9DipLEB2z4fuoHszroq1U9NcAB9aooFDPJSf', - '57zQNBZBEiHsCZFqsaY6h176ioXy5MsSLmcvHkEyaLGy', - 'SysvarS1otHashes111111111111111111111111111', - 'SysvarC1ock11111111111111111111111111111111', - 'Vote111111111111111111111111111111111111111', - ], - header: { - numReadonlySignedAccounts: 0, - numReadonlyUnsignedAccounts: 3, - numRequiredSignatures: 2, - }, - instructions: [ - { - accounts: [1, 2, 3], - data: '37u9WtQpcm6ULa3VtWDFAWoQc1hUvybPrA3dtx99tgHvvcE7pKRZjuGmn7VX2tC3JmYDYGG7', - programIdIndex: 4, - }, - ], - recentBlockhash: 'GeyAFFRY3WGpmam2hbgrKw4rbU2RKzfVLm5QLSeZwTZE', - }, - signatures: [ - 'w2Zeq8YkpyB463DttvfzARD7k9ZxGEwbsEw4boEK7jDp3pfoxZbTdLFSsEPhzXhpCcjGi2kHtHFobgX49MMhbWt', - '4oCEqwGrMdBeMxpzuWiukCYqSfV4DsSKXSiVVCh1iJ6pS772X7y219JZP3mgqBz5PhsvprpKyhzChjYc3VSBQXzG', - ], - }, - }, - ], - }, - }); - - // Find a block that has a transaction. - await mockRpcResponse({ - method: 'getFirstAvailableBlock', - params: [], - value: 1, - }); - let slot = await connection.getFirstAvailableBlock(); - - let address: PublicKey | undefined; - let expectedSignature: string | undefined; - while (!address || !expectedSignature) { - const block = await connection.getConfirmedBlock(slot); - if (block.transactions.length > 0) { - const {signature, publicKey} = - block.transactions[0].transaction.signatures[0]; - if (signature) { - address = publicKey; - expectedSignature = bs58.encode(signature); - break; - } - } - slot++; - } - - // getConfirmedSignaturesForAddress tests... - await mockRpcResponse({ - method: 'getFirstAvailableBlock', - params: [], - value: 0, - }); - const mockSignature = - '5SHZ9NwpnS9zYnauN7pnuborKf39zGMr11XpMC59VvRSeDJNcnYLecmdxXCVuBFPNQLdCBBjyZiNCL4KoHKr3tvz'; - await mockRpcResponse({ - method: 'getConfirmedBlock', - params: [slot, {transactionDetails: 'signatures', rewards: false}], - value: { - blockTime: 1614281964, - blockhash: 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo', - previousBlockhash: 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo', - parentSlot: 1, - signatures: [mockSignature], - }, - }); - await mockRpcResponse({ - method: 'getSlot', - params: [], - value: 123, - }); - await mockRpcResponse({ - method: 'getConfirmedBlock', - params: [slot + 2, {transactionDetails: 'signatures', rewards: false}], - value: { - blockTime: 1614281964, - blockhash: 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo', - previousBlockhash: 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo', - parentSlot: 1, - signatures: [mockSignature], - }, - }); - await mockRpcResponse({ - method: 'getConfirmedSignaturesForAddress2', - params: [address.toBase58(), {before: mockSignature}], - value: [ - { - signature: expectedSignature, - slot, - err: null, - memo: null, - }, - ], - }); - - const confirmedSignatures = - await connection.getConfirmedSignaturesForAddress( - address, - slot, - slot + 1, - ); - expect(confirmedSignatures.includes(expectedSignature)).to.be.true; - - const badSlot = Number.MAX_SAFE_INTEGER - 1; - await mockRpcResponse({ - method: 'getConfirmedBlock', - params: [badSlot - 1, {transactionDetails: 'signatures', rewards: false}], - error: {message: 'Block not available for slot ' + badSlot}, - }); - expect( - connection.getConfirmedSignaturesForAddress( - address, - badSlot, - badSlot + 1, - ), - ).to.be.rejected; - - // getConfirmedSignaturesForAddress2 tests... - await mockRpcResponse({ - method: 'getConfirmedSignaturesForAddress2', - params: [address.toBase58(), {limit: 1}], - value: [ - { - signature: expectedSignature, - slot, - err: null, - memo: null, - }, - ], - }); - - const confirmedSignatures2 = - await connection.getConfirmedSignaturesForAddress2(address, {limit: 1}); - expect(confirmedSignatures2).to.have.length(1); - if (mockServer) { - expect(confirmedSignatures2[0].signature).to.eq(expectedSignature); - expect(confirmedSignatures2[0].slot).to.eq(slot); - expect(confirmedSignatures2[0].err).to.be.null; - expect(confirmedSignatures2[0].memo).to.be.null; - } - }); - - it('get signatures for address', async function () { - const connection = new Connection(url); - - await mockRpcResponse({ - method: 'getSlot', - params: [], - value: 2, - }); - - await waitForSlot.call(this, connection, 1); - - await mockRpcResponse({ - method: 'getConfirmedBlock', - params: [1], - value: { - blockTime: 1614281964, - blockhash: '57zQNBZBEiHsCZFqsaY6h176ioXy5MsSLmcvHkEyaLGy', - previousBlockhash: 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo', - parentSlot: 0, - transactions: [ - { - meta: { - fee: 10000, - postBalances: [499260347380, 15298080, 1, 1, 1], - preBalances: [499260357380, 15298080, 1, 1, 1], - status: {Ok: null}, - err: null, - }, - transaction: { - message: { - accountKeys: [ - 'va12u4o9DipLEB2z4fuoHszroq1U9NcAB9aooFDPJSf', - '57zQNBZBEiHsCZFqsaY6h176ioXy5MsSLmcvHkEyaLGy', - 'SysvarS1otHashes111111111111111111111111111', - 'SysvarC1ock11111111111111111111111111111111', - 'Vote111111111111111111111111111111111111111', - ], - header: { - numReadonlySignedAccounts: 0, - numReadonlyUnsignedAccounts: 3, - numRequiredSignatures: 2, - }, - instructions: [ - { - accounts: [1, 2, 3], - data: '37u9WtQpcm6ULa3VtWDFAWoQc1hUvybPrA3dtx99tgHvvcE7pKRZjuGmn7VX2tC3JmYDYGG7', - programIdIndex: 4, - }, - ], - recentBlockhash: 'GeyAFFRY3WGpmam2hbgrKw4rbU2RKzfVLm5QLSeZwTZE', - }, - signatures: [ - 'w2Zeq8YkpyB463DttvfzARD7k9ZxGEwbsEw4boEK7jDp3pfoxZbTdLFSsEPhzXhpCcjGi2kHtHFobgX49MMhbWt', - '4oCEqwGrMdBeMxpzuWiukCYqSfV4DsSKXSiVVCh1iJ6pS772X7y219JZP3mgqBz5PhsvprpKyhzChjYc3VSBQXzG', - ], - }, - }, - ], - }, - }); - - // Find a block that has a transaction. - await mockRpcResponse({ - method: 'getFirstAvailableBlock', - params: [], - value: 1, - }); - let slot = await connection.getFirstAvailableBlock(); - - let address: PublicKey | undefined; - let expectedSignature: string | undefined; - while (!address || !expectedSignature) { - const block = await connection.getConfirmedBlock(slot); - if (block.transactions.length > 0) { - const {signature, publicKey} = - block.transactions[0].transaction.signatures[0]; - if (signature) { - address = publicKey; - expectedSignature = bs58.encode(signature); - break; - } - } - slot++; - } - - // getSignaturesForAddress tests... - await mockRpcResponse({ - method: 'getSignaturesForAddress', - params: [address.toBase58(), {limit: 1}], - value: [ - { - signature: expectedSignature, - slot, - err: null, - memo: null, - }, - ], - }); - - const signatures = await connection.getSignaturesForAddress(address, { - limit: 1, - }); - expect(signatures).to.have.length(1); - if (mockServer) { - expect(signatures[0].signature).to.eq(expectedSignature); - expect(signatures[0].slot).to.eq(slot); - expect(signatures[0].err).to.be.null; - expect(signatures[0].memo).to.be.null; - } - }); - - it('get parsed confirmed transactions', async function () { - await mockRpcResponse({ - method: 'getSlot', - params: [], - value: 2, - }); - - await waitForSlot.call(this, connection, 1); - - await mockRpcResponse({ - method: 'getConfirmedBlock', - params: [1], - value: { - blockTime: 1614281964, - blockhash: '57zQNBZBEiHsCZFqsaY6h176ioXy5MsSLmcvHkEyaLGy', - previousBlockhash: 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo', - parentSlot: 0, - transactions: [ - { - meta: { - fee: 10000, - postBalances: [499260347380, 15298080, 1, 1, 1], - preBalances: [499260357380, 15298080, 1, 1, 1], - status: {Ok: null}, - err: null, - }, - transaction: { - message: { - accountKeys: [ - 'va12u4o9DipLEB2z4fuoHszroq1U9NcAB9aooFDPJSf', - '57zQNBZBEiHsCZFqsaY6h176ioXy5MsSLmcvHkEyaLGy', - 'SysvarS1otHashes111111111111111111111111111', - 'SysvarC1ock11111111111111111111111111111111', - 'Vote111111111111111111111111111111111111111', - ], - header: { - numReadonlySignedAccounts: 0, - numReadonlyUnsignedAccounts: 3, - numRequiredSignatures: 2, - }, - instructions: [ - { - accounts: [1, 2, 3], - data: '37u9WtQpcm6ULa3VtWDFAWoQc1hUvybPrA3dtx99tgHvvcE7pKRZjuGmn7VX2tC3JmYDYGG7', - programIdIndex: 4, - }, - ], - recentBlockhash: 'GeyAFFRY3WGpmam2hbgrKw4rbU2RKzfVLm5QLSeZwTZE', - }, - signatures: [ - 'w2Zeq8YkpyB463DttvfzARD7k9ZxGEwbsEw4boEK7jDp3pfoxZbTdLFSsEPhzXhpCcjGi2kHtHFobgX49MMhbWt', - '4oCEqwGrMdBeMxpzuWiukCYqSfV4DsSKXSiVVCh1iJ6pS772X7y219JZP3mgqBz5PhsvprpKyhzChjYc3VSBQXzG', - ], - }, - }, - ], - }, - }); - - // Find a block that has a transaction. - await mockRpcResponse({ - method: 'getFirstAvailableBlock', - params: [], - value: 1, - }); - let slot = await connection.getFirstAvailableBlock(); - - let confirmedTransaction: string | undefined; - while (!confirmedTransaction) { - const block = await connection.getConfirmedBlock(slot); - for (const tx of block.transactions) { - if (tx.transaction.signature) { - confirmedTransaction = bs58.encode(tx.transaction.signature); - break; - } - } - slot++; - } - - await mockRpcBatchResponse({ - batch: [ - { - methodName: 'getConfirmedTransaction', - args: [], - }, - ], - result: [ - { - blockTime: 1616102519, - meta: { - err: null, - fee: 5000, - innerInstructions: [], - logMessages: [ - 'Program Vote111111111111111111111111111111111111111 invoke [1]', - 'Program Vote111111111111111111111111111111111111111 success', - ], - postBalances: [499999995000, 26858640, 1, 1, 1], - postTokenBalances: [], - preBalances: [500000000000, 26858640, 1, 1, 1], - preTokenBalances: [], - status: { - Ok: null, - }, - }, - slot: 2, - transaction: { - message: { - accountKeys: [ - { - pubkey: 'jcU4R7JccGEvDpe1i6bahvHpe47XahMXacG73EzE198', - signer: true, - writable: true, - }, - { - pubkey: 'GfBcnCAU7kWfAYqKRCNyWEHjdEJZmzRZvEcX5bbzEQqt', - signer: false, - writable: true, - }, - { - pubkey: 'SysvarS1otHashes111111111111111111111111111', - signer: false, - writable: false, - }, - { - pubkey: 'SysvarC1ock11111111111111111111111111111111', - signer: false, - writable: false, - }, - { - pubkey: 'Vote111111111111111111111111111111111111111', - signer: false, - writable: false, - }, - ], - instructions: [ - { - parsed: { - info: { - clockSysvar: - 'SysvarC1ock11111111111111111111111111111111', - slotHashesSysvar: - 'SysvarS1otHashes111111111111111111111111111', - vote: { - hash: 'GuCya3AAGxn1qhoqxqy3WEdZdZUkXKpa9pthQ3tqvbpx', - slots: [1], - timestamp: 1616102669, - }, - voteAccount: - 'GfBcnCAU7kWfAYqKRCNyWEHjdEJZmzRZvEcX5bbzEQqt', - voteAuthority: - 'jcU4R7JccGEvDpe1i6bahvHpe47XahMXacG73EzE198', - }, - type: 'vote', - }, - program: 'vote', - programId: 'Vote111111111111111111111111111111111111111', - }, - ], - recentBlockhash: 'G9ywjV5CVgMtLXruXtrE7af4QgFKYNXgDTw4jp7SWcSo', - }, - signatures: [ - '4G4rTqnUdzrmBHsdKJSiMtonpQLWSw1avJ8YxWQ95jE6iFFHFsEkBnoYycxnkBS9xHWRc6EarDsrFG9USFBbjfjx', - ], - }, - }, - { - blockTime: 1616102519, - meta: { - err: null, - fee: 5000, - innerInstructions: [], - logMessages: [ - 'Program Vote111111111111111111111111111111111111111 invoke [1]', - 'Program Vote111111111111111111111111111111111111111 success', - ], - postBalances: [499999995000, 26858640, 1, 1, 1], - postTokenBalances: [], - preBalances: [500000000000, 26858640, 1, 1, 1], - preTokenBalances: [], - status: { - Ok: null, - }, - }, - slot: 2, - transaction: { - message: { - accountKeys: [ - { - pubkey: 'jcU4R7JccGEvDpe1i6bahvHpe47XahMXacG73EzE198', - signer: true, - writable: true, - }, - { - pubkey: 'GfBcnCAU7kWfAYqKRCNyWEHjdEJZmzRZvEcX5bbzEQqt', - signer: false, - writable: true, - }, - { - pubkey: 'SysvarS1otHashes111111111111111111111111111', - signer: false, - writable: false, - }, - { - pubkey: 'SysvarC1ock11111111111111111111111111111111', - signer: false, - writable: false, - }, - { - pubkey: 'Vote111111111111111111111111111111111111111', - signer: false, - writable: false, - }, - ], - instructions: [ - { - parsed: { - info: { - clockSysvar: - 'SysvarC1ock11111111111111111111111111111111', - slotHashesSysvar: - 'SysvarS1otHashes111111111111111111111111111', - vote: { - hash: 'GuCya3AAGxn1qhoqxqy3WEdZdZUkXKpa9pthQ3tqvbpx', - slots: [1], - timestamp: 1616102669, - }, - voteAccount: - 'GfBcnCAU7kWfAYqKRCNyWEHjdEJZmzRZvEcX5bbzEQqt', - voteAuthority: - 'jcU4R7JccGEvDpe1i6bahvHpe47XahMXacG73EzE198', - }, - type: 'vote', - }, - program: 'vote', - programId: 'Vote111111111111111111111111111111111111111', - }, - ], - recentBlockhash: 'G9ywjV5CVgMtLXruXtrE7af4QgFKYNXgDTw4jp7SWcSo', - }, - signatures: [ - '4G4rTqnUdzrmBHsdKJSiMtonpQLWSw1avJ8YxWQ95jE6iFFHFsEkBnoYycxnkBS9xHWRc6EarDsrFG9USFBbjfjx', - ], - }, - }, - ], - }); - - let result = await connection.getParsedConfirmedTransactions([ - confirmedTransaction, - confirmedTransaction, - ]); - - if (!result) { - expect(result).to.be.ok; - return; - } - - expect(result).to.be.length(2); - expect(result[0]).to.not.be.null; - expect(result[1]).to.not.be.null; - if (result[0] !== null) { - expect(result[0].transaction.signatures).not.to.be.null; - } - if (result[1] !== null) { - expect(result[1].transaction.signatures).not.to.be.null; - } - - result = await connection.getParsedConfirmedTransactions([]); - if (!result) { - expect(result).to.be.ok; - return; - } - - expect(result).to.be.empty; - }); - - it('get block height', async () => { - await mockRpcResponse({ - method: 'getBlockHeight', - params: [{commitment: 'confirmed'}], - value: 10, - }); - - const blockHeight = await connection.getBlockHeight('confirmed'); - expect(blockHeight).to.be.a('number'); - }); - - if (!process.env.TEST_LIVE) { - it('identical get block height calls get coalesced', async () => { - // This is equivalent to asserting that `getBlockHeight` only gets called once. - await mockRpcResponse({ - method: 'getBlockHeight', - params: [{commitment: 'confirmed'}], - value: 10, - }); - - const [blockHeightA, blockHeightB, blockHeightC] = await Promise.all([ - connection.getBlockHeight('confirmed'), - connection.getBlockHeight({commitment: 'confirmed'}), - connection.getBlockHeight('confirmed'), - ]); - expect(blockHeightA).to.be.a('number'); - expect(blockHeightB).to.be.a('number'); - expect(blockHeightC).to.be.a('number'); - }); - - it('get block height calls whose args are in different orders but functionally identical get coalesced', async () => { - // This is equivalent to asserting that `getBlockHeight` only gets called once. - await mockRpcResponse({ - method: 'getBlockHeight', - params: [{commitment: 'confirmed', minContextSlot: 5}], - value: 10, - }); - - const [blockHeightA, blockHeightB] = await Promise.all([ - connection.getBlockHeight({commitment: 'confirmed', minContextSlot: 5}), - connection.getBlockHeight({minContextSlot: 5, commitment: 'confirmed'}), - ]); - expect(blockHeightA).to.be.a('number'); - expect(blockHeightB).to.be.a('number'); - }); - - it('get block height calls with different params do not get coalesced', async () => { - // This is equivalent to asserting that `getBlockHeight` gets called three times. - await mockRpcResponse({ - method: 'getBlockHeight', - params: [{commitment: 'confirmed'}], - value: 10, - }); - await mockRpcResponse({ - method: 'getBlockHeight', - params: [{commitment: 'finalized'}], - value: 10, - }); - await mockRpcResponse({ - method: 'getBlockHeight', - params: [{commitment: 'confirmed', minContextSlot: 5}], - value: 10, - }); - - const [blockHeightA, blockHeightB, blockHeightC] = await Promise.all([ - connection.getBlockHeight('confirmed'), - connection.getBlockHeight('finalized'), - connection.getBlockHeight({commitment: 'confirmed', minContextSlot: 5}), - ]); - expect(blockHeightA).to.be.a('number'); - expect(blockHeightB).to.be.a('number'); - expect(blockHeightC).to.be.a('number'); - }); - - it('get block height calls that fail bubble up to each coalesced caller', async () => { - // This is equivalent to asserting that `getBlockHeight` only gets called once. - await mockRpcResponse({ - method: 'getBlockHeight', - params: [{commitment: 'confirmed'}], - error: { - message: 'Something bad happened', - }, - }); - - const blockHeightPromiseA = connection.getBlockHeight('confirmed'); - const blockHeightPromiseB = connection.getBlockHeight({ - commitment: 'confirmed', - }); - const blockHeightPromiseC = connection.getBlockHeight('confirmed'); - await expect(blockHeightPromiseA).to.eventually.be.rejected; - await expect(blockHeightPromiseB).to.eventually.be.rejected; - await expect(blockHeightPromiseC).to.eventually.be.rejected; - }); - - it('follow on calls to get block height generate new network requests', async () => { - await mockRpcResponse({ - method: 'getBlockHeight', - params: [{commitment: 'confirmed'}], - value: 10, - }); - await expect(connection.getBlockHeight('confirmed')).to.eventually.eq(10); - // Second call with identical options should make a *new* request, since the first has completed - await mockRpcResponse({ - method: 'getBlockHeight', - params: [{commitment: 'confirmed'}], - error: { - message: 'Try again', - }, - }); - await expect(connection.getBlockHeight('confirmed')).to.be.rejected; - // Third call identical to the second, failed one, should also make a new request. - await mockRpcResponse({ - method: 'getBlockHeight', - params: [{commitment: 'confirmed'}], - value: 11, - }); - await expect(connection.getBlockHeight('confirmed')).to.eventually.eq(11); - }); - } - - it('get block production', async () => { - const commitment: Commitment = 'processed'; - - // Find slot of the lowest confirmed block - await mockRpcResponse({ - method: 'getFirstAvailableBlock', - params: [], - value: 1, - }); - let firstSlot = await connection.getFirstAvailableBlock(); - - // Find current block height - await mockRpcResponse({ - method: 'getBlockHeight', - params: [{commitment: commitment}], - value: 10, - }); - let lastSlot = await connection.getBlockHeight(commitment); - - const blockProductionConfig = { - commitment: commitment, - range: { - firstSlot, - lastSlot, - }, - }; - - const blockProductionRet = { - byIdentity: { - '85iYT5RuzRTDgjyRa3cP8SYhM2j21fj7NhfJ3peu1DPr': [12, 10], - }, - range: { - firstSlot, - lastSlot, - }, - }; - - //mock RPC call with config specified - await mockRpcResponse({ - method: 'getBlockProduction', - params: [blockProductionConfig], - value: blockProductionRet, - withContext: true, - }); - - //mock RPC call with commitment only - await mockRpcResponse({ - method: 'getBlockProduction', - params: [{commitment: commitment}], - value: blockProductionRet, - withContext: true, - }); - - const result = await connection.getBlockProduction(blockProductionConfig); - - if (!result) { - expect(result).to.be.ok; - return; - } - - expect(result.context).to.be.ok; - expect(result.value).to.be.ok; - - const resultContextSlot = result.context.slot; - expect(resultContextSlot).to.be.a('number'); - - const resultIdentityDictionary = result.value.byIdentity; - expect(resultIdentityDictionary).to.be.a('object'); - - for (var key in resultIdentityDictionary) { - expect(key).to.be.a('string'); - expect(resultIdentityDictionary[key]).to.be.a('array'); - expect(resultIdentityDictionary[key][0]).to.be.a('number'); - expect(resultIdentityDictionary[key][1]).to.be.a('number'); - } - - const resultSlotRange = result.value.range; - expect(resultSlotRange.firstSlot).to.equal(firstSlot); - expect(resultSlotRange.lastSlot).to.equal(lastSlot); - - const resultCommitmentOnly = - await connection.getBlockProduction(commitment); - - if (!resultCommitmentOnly) { - expect(resultCommitmentOnly).to.be.ok; - return; - } - expect(resultCommitmentOnly.context).to.be.ok; - expect(resultCommitmentOnly.value).to.be.ok; - - const resultCOContextSlot = result.context.slot; - expect(resultCOContextSlot).to.be.a('number'); - - const resultCOIdentityDictionary = result.value.byIdentity; - expect(resultCOIdentityDictionary).to.be.a('object'); - - for (var property in resultCOIdentityDictionary) { - expect(property).to.be.a('string'); - expect(resultCOIdentityDictionary[property]).to.be.a('array'); - expect(resultCOIdentityDictionary[property][0]).to.be.a('number'); - expect(resultCOIdentityDictionary[property][1]).to.be.a('number'); - } - - const resultCOSlotRange = result.value.range; - expect(resultCOSlotRange.firstSlot).to.equal(firstSlot); - expect(resultCOSlotRange.lastSlot).to.equal(lastSlot); - }); - - it('get transaction', async function () { - await mockRpcResponse({ - method: 'getSlot', - params: [], - value: 2, - }); - - await waitForSlot.call(this, connection, 1); - - await mockRpcResponse({ - method: 'getBlock', - params: [1], - value: { - blockHeight: 0, - blockTime: 1614281964, - blockhash: '57zQNBZBEiHsCZFqsaY6h176ioXy5MsSLmcvHkEyaLGy', - previousBlockhash: 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo', - parentSlot: 0, - transactions: [ - { - meta: { - fee: 10000, - postBalances: [499260347380, 15298080, 1, 1, 1], - preBalances: [499260357380, 15298080, 1, 1, 1], - status: {Ok: null}, - err: null, - }, - transaction: { - message: { - accountKeys: [ - 'va12u4o9DipLEB2z4fuoHszroq1U9NcAB9aooFDPJSf', - '57zQNBZBEiHsCZFqsaY6h176ioXy5MsSLmcvHkEyaLGy', - 'SysvarS1otHashes111111111111111111111111111', - 'SysvarC1ock11111111111111111111111111111111', - 'Vote111111111111111111111111111111111111111', - ], - header: { - numReadonlySignedAccounts: 0, - numReadonlyUnsignedAccounts: 3, - numRequiredSignatures: 2, - }, - instructions: [ - { - accounts: [1, 2, 3], - data: '37u9WtQpcm6ULa3VtWDFAWoQc1hUvybPrA3dtx99tgHvvcE7pKRZjuGmn7VX2tC3JmYDYGG7', - programIdIndex: 4, - }, - ], - recentBlockhash: 'GeyAFFRY3WGpmam2hbgrKw4rbU2RKzfVLm5QLSeZwTZE', - }, - signatures: [ - 'w2Zeq8YkpyB463DttvfzARD7k9ZxGEwbsEw4boEK7jDp3pfoxZbTdLFSsEPhzXhpCcjGi2kHtHFobgX49MMhbWt', - '4oCEqwGrMdBeMxpzuWiukCYqSfV4DsSKXSiVVCh1iJ6pS772X7y219JZP3mgqBz5PhsvprpKyhzChjYc3VSBQXzG', - ], - }, - }, - ], - }, - }); - - // Find a block that has a transaction. - await mockRpcResponse({ - method: 'getFirstAvailableBlock', - params: [], - value: 1, - }); - let slot = await connection.getFirstAvailableBlock(); - - let transaction: string | undefined; - while (!transaction) { - const block = await connection.getBlock(slot); - if (block && block.transactions.length > 0) { - transaction = block.transactions[0].transaction.signatures[0]; - continue; - } - slot++; - } - - await mockRpcResponse({ - method: 'getTransaction', - params: [transaction], - value: { - slot, - transaction: { - message: { - accountKeys: [ - 'va12u4o9DipLEB2z4fuoHszroq1U9NcAB9aooFDPJSf', - '57zQNBZBEiHsCZFqsaY6h176ioXy5MsSLmcvHkEyaLGy', - 'SysvarS1otHashes111111111111111111111111111', - 'SysvarC1ock11111111111111111111111111111111', - 'Vote111111111111111111111111111111111111111', - ], - header: { - numReadonlySignedAccounts: 0, - numReadonlyUnsignedAccounts: 3, - numRequiredSignatures: 2, - }, - instructions: [ - { - accounts: [1, 2, 3], - data: '37u9WtQpcm6ULa3VtWDFAWoQc1hUvybPrA3dtx99tgHvvcE7pKRZjuGmn7VX2tC3JmYDYGG7', - programIdIndex: 4, - }, - ], - recentBlockhash: 'GeyAFFRY3WGpmam2hbgrKw4rbU2RKzfVLm5QLSeZwTZE', - }, - signatures: [ - 'w2Zeq8YkpyB463DttvfzARD7k9ZxGEwbsEw4boEK7jDp3pfoxZbTdLFSsEPhzXhpCcjGi2kHtHFobgX49MMhbWt', - '4oCEqwGrMdBeMxpzuWiukCYqSfV4DsSKXSiVVCh1iJ6pS772X7y219JZP3mgqBz5PhsvprpKyhzChjYc3VSBQXzG', - ], - }, - meta: { - fee: 10000, - postBalances: [499260347380, 15298080, 1, 1, 1], - preBalances: [499260357380, 15298080, 1, 1, 1], - status: {Ok: null}, - err: null, - }, - }, - }); - - const result = await connection.getTransaction(transaction); - - if (!result) { - expect(result).to.be.ok; - return; - } - - const resultSignature = result.transaction.signatures[0]; - expect(resultSignature).to.eq(transaction); - - const newAddress = Keypair.generate().publicKey; - const recentSignature = await helpers.airdrop({ - connection, - address: newAddress, - amount: 1, - }); - - await mockRpcResponse({ - method: 'getTransaction', - params: [recentSignature], - value: null, - }); - - // Signature hasn't been finalized yet - const nullResponse = await connection.getTransaction(recentSignature); - expect(nullResponse).to.be.null; - }); - - it('get confirmed transaction', async function () { - await mockRpcResponse({ - method: 'getSlot', - params: [], - value: 2, - }); - - await waitForSlot.call(this, connection, 1); - - await mockRpcResponse({ - method: 'getConfirmedBlock', - params: [1], - value: { - blockTime: 1614281964, - blockhash: '57zQNBZBEiHsCZFqsaY6h176ioXy5MsSLmcvHkEyaLGy', - previousBlockhash: 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo', - parentSlot: 0, - transactions: [ - { - meta: { - fee: 10000, - postBalances: [499260347380, 15298080, 1, 1, 1], - preBalances: [499260357380, 15298080, 1, 1, 1], - status: {Ok: null}, - err: null, - }, - transaction: { - message: { - accountKeys: [ - 'va12u4o9DipLEB2z4fuoHszroq1U9NcAB9aooFDPJSf', - '57zQNBZBEiHsCZFqsaY6h176ioXy5MsSLmcvHkEyaLGy', - 'SysvarS1otHashes111111111111111111111111111', - 'SysvarC1ock11111111111111111111111111111111', - 'Vote111111111111111111111111111111111111111', - ], - header: { - numReadonlySignedAccounts: 0, - numReadonlyUnsignedAccounts: 3, - numRequiredSignatures: 2, - }, - instructions: [ - { - accounts: [1, 2, 3], - data: '37u9WtQpcm6ULa3VtWDFAWoQc1hUvybPrA3dtx99tgHvvcE7pKRZjuGmn7VX2tC3JmYDYGG7', - programIdIndex: 4, - }, - ], - recentBlockhash: 'GeyAFFRY3WGpmam2hbgrKw4rbU2RKzfVLm5QLSeZwTZE', - }, - signatures: [ - 'w2Zeq8YkpyB463DttvfzARD7k9ZxGEwbsEw4boEK7jDp3pfoxZbTdLFSsEPhzXhpCcjGi2kHtHFobgX49MMhbWt', - '4oCEqwGrMdBeMxpzuWiukCYqSfV4DsSKXSiVVCh1iJ6pS772X7y219JZP3mgqBz5PhsvprpKyhzChjYc3VSBQXzG', - ], - }, - }, - ], - }, - }); - - // Find a block that has a transaction. - await mockRpcResponse({ - method: 'getFirstAvailableBlock', - params: [], - value: 1, - }); - let slot = await connection.getFirstAvailableBlock(); - - let confirmedTransaction: string | undefined; - while (!confirmedTransaction) { - const block = await connection.getConfirmedBlock(slot); - for (const tx of block.transactions) { - if (tx.transaction.signature) { - confirmedTransaction = bs58.encode(tx.transaction.signature); - break; - } - } - slot++; - } - - await mockRpcResponse({ - method: 'getConfirmedTransaction', - params: [confirmedTransaction], - value: { - slot, - transaction: { - message: { - accountKeys: [ - 'va12u4o9DipLEB2z4fuoHszroq1U9NcAB9aooFDPJSf', - '57zQNBZBEiHsCZFqsaY6h176ioXy5MsSLmcvHkEyaLGy', - 'SysvarS1otHashes111111111111111111111111111', - 'SysvarC1ock11111111111111111111111111111111', - 'Vote111111111111111111111111111111111111111', - ], - header: { - numReadonlySignedAccounts: 0, - numReadonlyUnsignedAccounts: 3, - numRequiredSignatures: 2, - }, - instructions: [ - { - accounts: [1, 2, 3], - data: '37u9WtQpcm6ULa3VtWDFAWoQc1hUvybPrA3dtx99tgHvvcE7pKRZjuGmn7VX2tC3JmYDYGG7', - programIdIndex: 4, - }, - ], - recentBlockhash: 'GeyAFFRY3WGpmam2hbgrKw4rbU2RKzfVLm5QLSeZwTZE', - }, - signatures: [ - 'w2Zeq8YkpyB463DttvfzARD7k9ZxGEwbsEw4boEK7jDp3pfoxZbTdLFSsEPhzXhpCcjGi2kHtHFobgX49MMhbWt', - '4oCEqwGrMdBeMxpzuWiukCYqSfV4DsSKXSiVVCh1iJ6pS772X7y219JZP3mgqBz5PhsvprpKyhzChjYc3VSBQXzG', - ], - }, - meta: { - fee: 10000, - postBalances: [499260347380, 15298080, 1, 1, 1], - preBalances: [499260357380, 15298080, 1, 1, 1], - status: {Ok: null}, - err: null, - }, - }, - }); - - const result = - await connection.getConfirmedTransaction(confirmedTransaction); - - if (!result) { - expect(result).to.be.ok; - return; - } - - if (result.transaction.signature === null) { - expect(result.transaction.signature).not.to.be.null; - return; - } - - const resultSignature = bs58.encode(result.transaction.signature); - expect(resultSignature).to.eq(confirmedTransaction); - - const newAddress = Keypair.generate().publicKey; - const recentSignature = await helpers.airdrop({ - connection, - address: newAddress, - amount: 1, - }); - - await mockRpcResponse({ - method: 'getConfirmedTransaction', - params: [recentSignature], - value: null, - }); - - // Signature hasn't been finalized yet - const nullResponse = - await connection.getConfirmedTransaction(recentSignature); - expect(nullResponse).to.be.null; - }); - - it('get transactions', async function () { - await mockRpcResponse({ - method: 'getSlot', - params: [], - value: 2, - }); - - await waitForSlot.call(this, connection, 1); - - await mockRpcResponse({ - method: 'getBlock', - params: [1], - value: { - blockHeight: 0, - blockTime: 1614281964, - blockhash: '57zQNBZBEiHsCZFqsaY6h176ioXy5MsSLmcvHkEyaLGy', - previousBlockhash: 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo', - parentSlot: 0, - transactions: [ - { - meta: { - fee: 10000, - postBalances: [499260347380, 15298080, 1, 1, 1], - preBalances: [499260357380, 15298080, 1, 1, 1], - status: {Ok: null}, - err: null, - }, - transaction: { - message: { - accountKeys: [ - 'va12u4o9DipLEB2z4fuoHszroq1U9NcAB9aooFDPJSf', - '57zQNBZBEiHsCZFqsaY6h176ioXy5MsSLmcvHkEyaLGy', - 'SysvarS1otHashes111111111111111111111111111', - 'SysvarC1ock11111111111111111111111111111111', - 'Vote111111111111111111111111111111111111111', - ], - header: { - numReadonlySignedAccounts: 0, - numReadonlyUnsignedAccounts: 3, - numRequiredSignatures: 2, - }, - instructions: [ - { - accounts: [1, 2, 3], - data: '37u9WtQpcm6ULa3VtWDFAWoQc1hUvybPrA3dtx99tgHvvcE7pKRZjuGmn7VX2tC3JmYDYGG7', - programIdIndex: 4, - }, - ], - recentBlockhash: 'GeyAFFRY3WGpmam2hbgrKw4rbU2RKzfVLm5QLSeZwTZE', - }, - signatures: [ - 'w2Zeq8YkpyB463DttvfzARD7k9ZxGEwbsEw4boEK7jDp3pfoxZbTdLFSsEPhzXhpCcjGi2kHtHFobgX49MMhbWt', - '4oCEqwGrMdBeMxpzuWiukCYqSfV4DsSKXSiVVCh1iJ6pS772X7y219JZP3mgqBz5PhsvprpKyhzChjYc3VSBQXzG', - ], - }, - }, - ], - }, - }); - - // Find a block that has a transaction. - await mockRpcResponse({ - method: 'getFirstAvailableBlock', - params: [], - value: 1, - }); - let slot = await connection.getFirstAvailableBlock(); - - let transaction: string | undefined; - while (!transaction) { - const block = await connection.getBlock(slot); - if (block && block.transactions.length > 0) { - transaction = block.transactions[0].transaction.signatures[0]; - continue; - } - slot++; - } - - await mockRpcBatchResponse({ - batch: [ - { - methodName: 'getTransaction', - args: [transaction], - }, - ], - result: [ - { - slot, - transaction: { - message: { - accountKeys: [ - 'va12u4o9DipLEB2z4fuoHszroq1U9NcAB9aooFDPJSf', - '57zQNBZBEiHsCZFqsaY6h176ioXy5MsSLmcvHkEyaLGy', - 'SysvarS1otHashes111111111111111111111111111', - 'SysvarC1ock11111111111111111111111111111111', - 'Vote111111111111111111111111111111111111111', - ], - header: { - numReadonlySignedAccounts: 0, - numReadonlyUnsignedAccounts: 3, - numRequiredSignatures: 2, - }, - instructions: [ - { - accounts: [1, 2, 3], - data: '37u9WtQpcm6ULa3VtWDFAWoQc1hUvybPrA3dtx99tgHvvcE7pKRZjuGmn7VX2tC3JmYDYGG7', - programIdIndex: 4, - }, - ], - recentBlockhash: 'GeyAFFRY3WGpmam2hbgrKw4rbU2RKzfVLm5QLSeZwTZE', - }, - signatures: [ - 'w2Zeq8YkpyB463DttvfzARD7k9ZxGEwbsEw4boEK7jDp3pfoxZbTdLFSsEPhzXhpCcjGi2kHtHFobgX49MMhbWt', - '4oCEqwGrMdBeMxpzuWiukCYqSfV4DsSKXSiVVCh1iJ6pS772X7y219JZP3mgqBz5PhsvprpKyhzChjYc3VSBQXzG', - ], - }, - meta: { - fee: 10000, - postBalances: [499260347380, 15298080, 1, 1, 1], - preBalances: [499260357380, 15298080, 1, 1, 1], - status: {Ok: null}, - err: null, - }, - }, - ], - }); - const [firstResult] = await connection.getTransactions([transaction]); - if (firstResult == null) { - expect.fail('Expected `getTransactions()` to return one result'); - } - expect(firstResult.transaction.message.isAccountSigner(0)).to.be.true; - }); - - if (mockServer) { - it('get parsed confirmed transaction coerces public keys of inner instructions', async () => { - const confirmedTransaction: TransactionSignature = - '4ADvAUQYxkh4qWKYE9QLW8gCLomGG94QchDLG4quvpBz1WqARYvzWQDDitKduAKspuy1DjcbnaDAnCAfnKpJYs48'; - - function getMockData(inner: any) { - return { - slot: 353050305, - transaction: { - message: { - accountKeys: [ - { - pubkey: 'va12u4o9DipLEB2z4fuoHszroq1U9NcAB9aooFDPJSf', - signer: true, - writable: true, - }, - ], - instructions: [ - { - accounts: ['va12u4o9DipLEB2z4fuoHszroq1U9NcAB9aooFDPJSf'], - data: '37u9WtQpcm6ULa3VtWDFAWoQc1hUvybPrA3dtx99tgHvvcE7pKRZjuGmn7VX2tC3JmYDYGG7', - programId: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', - }, - ], - recentBlockhash: 'GeyAFFRY3WGpmam2hbgrKw4rbU2RKzfVLm5QLSeZwTZE', - }, - signatures: [ - 'w2Zeq8YkpyB463DttvfzARD7k9ZxGEwbsEw4boEK7jDp3pfoxZbTdLFSsEPhzXhpCcjGi2kHtHFobgX49MMhbWt', - '4oCEqwGrMdBeMxpzuWiukCYqSfV4DsSKXSiVVCh1iJ6pS772X7y219JZP3mgqBz5PhsvprpKyhzChjYc3VSBQXzG', - ], - }, - meta: { - fee: 10000, - postBalances: [499260347380, 15298080, 1, 1, 1], - preBalances: [499260357380, 15298080, 1, 1, 1], - innerInstructions: [ - { - index: 0, - instructions: [inner], - }, - ], - status: {Ok: null}, - err: null, - }, - }; - } - - await mockRpcResponse({ - method: 'getConfirmedTransaction', - params: [confirmedTransaction, {encoding: 'jsonParsed'}], - value: getMockData({ - parsed: {}, - program: 'spl-token', - programId: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', - }), - }); - - const result = - await connection.getParsedConfirmedTransaction(confirmedTransaction); - - if (result && result.meta && result.meta.innerInstructions) { - const innerInstructions = result.meta.innerInstructions; - const firstIx = innerInstructions[0].instructions[0]; - expect(firstIx.programId).to.be.instanceOf(PublicKey); - } - - await mockRpcResponse({ - method: 'getConfirmedTransaction', - params: [confirmedTransaction, {encoding: 'jsonParsed'}], - value: getMockData({ - accounts: [ - 'EeJqWk5pczNjsqqY3jia9xfFNG1dD68te4s8gsdCuEk7', - '6tVrjJhFm5SAvvdh6tysjotQurCSELpxuW3JaAAYeC1m', - ], - data: 'ai3535', - programId: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', - }), - }); - - const result2 = - await connection.getParsedConfirmedTransaction(confirmedTransaction); - - if (result2 && result2.meta && result2.meta.innerInstructions) { - const innerInstructions = result2.meta.innerInstructions; - const instruction = innerInstructions[0].instructions[0]; - expect(instruction.programId).to.be.instanceOf(PublicKey); - if ('accounts' in instruction) { - expect(instruction.accounts[0]).to.be.instanceOf(PublicKey); - expect(instruction.accounts[1]).to.be.instanceOf(PublicKey); - } else { - expect('accounts' in instruction).to.be.true; - } - } - }); - } - - describe('get parsed block', function () { - it('can deserialize a response when `transactionDetails` is `full`', async () => { - // Mock block with transaction, fetched using `"transactionDetails": "full"`. - await mockRpcResponse({ - method: 'getBlock', - params: [ - 1, - { - encoding: 'jsonParsed', - maxSupportedTransactionVersion: 0, - transactionDetails: 'full', - }, - ], - value: { - blockHeight: 0, - blockTime: 1614281964, - blockhash: '49d2UbduiZWjtR3Wvfv2t2QxmXvtZNWSPFRZxEDYAvQN', - parentSlot: 0, - previousBlockhash: 'mDd5yMLfuroS1JVZMHo2VZLTgKXXNBXrzPR5UkzFD4X', - transactions: [ - { - meta: { - err: null, - fee: 5000, - innerInstructions: [], - logMessages: [ - 'Program Vote111111111111111111111111111111111111111 invoke [1]', - 'Program Vote111111111111111111111111111111111111111 success', - ], - postBalances: [3712706991, 5765419239, 1169280, 143487360, 1], - postTokenBalances: [], - preBalances: [3712711991, 5765419239, 1169280, 143487360, 1], - preTokenBalances: [], - rewards: null, - status: {Ok: null}, - }, - transaction: { - message: { - accountKeys: [ - { - pubkey: '7v5fMKBqC9PuwjSdS9k9JU7efEXmq3bHTMF5fuSHnqrm', - signer: true, - source: 'transaction', - writable: true, - }, - { - pubkey: 'AhcvnNdppGEcgdpK5gfcaZnAWz4ct8V4n7De5QiLiuzG', - signer: false, - source: 'transaction', - writable: true, - }, - { - pubkey: 'SysvarC1ock11111111111111111111111111111111', - signer: false, - source: 'transaction', - writable: false, - }, - { - pubkey: 'SysvarS1otHashes111111111111111111111111111', - signer: false, - source: 'transaction', - writable: false, - }, - { - pubkey: 'Vote111111111111111111111111111111111111111', - signer: false, - source: 'transaction', - writable: false, - }, - ], - addressTableLookups: null, - instructions: [ - { - parsed: { - info: { - clockSysvar: - 'SysvarC1ock11111111111111111111111111111111', - slotHashesSysvar: - 'SysvarS1otHashes111111111111111111111111111', - vote: { - hash: '2gmQ8xMjZaXn63kr8qzPAUjQAHi7xCDjSibPdJxhVYMm', - slots: [164153060, 164153061], - timestamp: 1669845645, - }, - voteAccount: - 'AhcvnNdppGEcgdpK5gfcaZnAWz4ct8V4n7De5QiLiuzG', - voteAuthority: - '7v5fMKBqC9PuwjSdS9k9JU7efEXmq3bHTMF5fuSHnqrm', - }, - type: 'vote', - }, - program: 'vote', - programId: 'Vote111111111111111111111111111111111111111', - }, - ], - recentBlockhash: - 'GLqYrN6AQxCGtFTQywkPj2WN5tafC3KerBhW4QkmAyD4', - }, - signatures: [ - '5qDZ3nUUwp8VHFfAE5ydTQRULCoVLMGs16EprwdXsvyNCLe1NfckCkRE4BPi6wyEW9hXvG9iWU2prXfbM8SNPVEC', - ], - }, - version: 'legacy', - }, - ], - }, - }); - await expect( - connection.getParsedBlock(1, { - maxSupportedTransactionVersion: 0, - transactionDetails: 'full', - }), - ).not.to.eventually.be.rejected; - }); - - it('can deserialize a response when `transactionDetails` is `none`', async () => { - // Mock block with transaction, fetched using `"transactionDetails": "none"`. - await mockRpcResponse({ - method: 'getBlock', - params: [ - 1, - { - encoding: 'jsonParsed', - maxSupportedTransactionVersion: 0, - transactionDetails: 'none', - }, - ], - value: { - blockHeight: 0, - blockTime: 1614281964, - blockhash: '49d2UbduiZWjtR3Wvfv2t2QxmXvtZNWSPFRZxEDYAvQN', - parentSlot: 0, - previousBlockhash: 'mDd5yMLfuroS1JVZMHo2VZLTgKXXNBXrzPR5UkzFD4X', - }, - }); - await expect( - connection.getParsedBlock(1, { - maxSupportedTransactionVersion: 0, - transactionDetails: 'none', - }), - ).not.to.eventually.be.rejected; - }); - - it('can deserialize a response when `transactionDetails` is `accounts`', async () => { - // Mock block with transaction, fetched using `"transactionDetails": "accounts"`. - await mockRpcResponse({ - method: 'getBlock', - params: [ - 1, - { - encoding: 'jsonParsed', - maxSupportedTransactionVersion: 0, - transactionDetails: 'accounts', - }, - ], - value: { - blockHeight: 0, - blockTime: 1614281964, - blockhash: '49d2UbduiZWjtR3Wvfv2t2QxmXvtZNWSPFRZxEDYAvQN', - parentSlot: 0, - previousBlockhash: 'mDd5yMLfuroS1JVZMHo2VZLTgKXXNBXrzPR5UkzFD4X', - transactions: [ - { - meta: { - err: null, - fee: 5000, - postBalances: [18237691394, 26858640, 1169280, 143487360, 1], - postTokenBalances: [], - preBalances: [18237696394, 26858640, 1169280, 143487360, 1], - preTokenBalances: [], - status: {Ok: null}, - }, - transaction: { - accountKeys: [ - { - pubkey: '914RFshndUeZaNPjf8UWDCyo49ahQ1XQ2w9BnEMwpHKF', - signer: true, - source: 'transaction', - writable: true, - }, - { - pubkey: '4cCd4SGrMswhqboYBJ5AcCVvCjh5NtaeZNwWFJzsnUWY', - signer: false, - source: 'transaction', - writable: true, - }, - { - pubkey: 'SysvarC1ock11111111111111111111111111111111', - signer: false, - source: 'transaction', - writable: false, - }, - { - pubkey: 'SysvarS1otHashes111111111111111111111111111', - signer: false, - source: 'transaction', - writable: false, - }, - { - pubkey: 'Vote111111111111111111111111111111111111111', - signer: false, - source: 'transaction', - writable: false, - }, - ], - signatures: [ - '5ZDp1HfNZhNRHc75ncsiZ4sCq1fGJHMGf9u36M3foD5PMH4Xu5S4X2x7aryn4JinUdG11oSYCk7zxbNmLJzzqUft', - ], - }, - version: 'legacy', - }, - ], - }, - }); - await expect( - connection.getParsedBlock(1, { - maxSupportedTransactionVersion: 0, - transactionDetails: 'accounts', - }), - ).not.to.eventually.be.rejected; - }); - }); - - describe('get block', function () { - beforeEach(async function () { - await mockRpcResponse({ - method: 'getSlot', - params: [], - value: 1, - }); - - await waitForSlot.call(this, connection); - }); - - it('gets the genesis block', async function () { - await mockRpcResponse({ - method: 'getBlock', - params: [0], - value: { - blockHeight: 0, - blockTime: 1614281964, - blockhash: 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo', - previousBlockhash: 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo', - parentSlot: 0, - transactions: [], - }, - }); - - let maybeBlock0: BlockResponse | null; - try { - maybeBlock0 = await connection.getBlock(0); - } catch (e) { - if (process.env.TEST_LIVE) { - console.warn( - 'WARNING: We ran no assertions about the genesis block because block 0 ' + - 'could not be found. See https://github.com/solana-labs/solana/issues/23853.', - ); - this.skip(); - } else { - throw e; - } - } - expect(maybeBlock0).not.to.be.null; - const block0 = maybeBlock0!; - - // Block 0 never has any transactions in test validator - const blockhash0 = block0.blockhash; - expect(block0.transactions).to.have.length(0); - expect(blockhash0).not.to.be.null; - expect(block0.previousBlockhash).not.to.be.null; - expect(block0.parentSlot).to.eq(0); - }); - - it('gets a block having a parent', async function () { - // Mock parent of block with transaction. - await mockRpcResponse({ - method: 'getBlock', - params: [0], - value: { - blockHeight: 0, - blockTime: 1614281964, - blockhash: 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo', - previousBlockhash: 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo', - parentSlot: 0, - transactions: [], - }, - }); - // Mock block with transaction. - await mockRpcResponse({ - method: 'getBlock', - params: [1], - value: { - blockHeight: 0, - blockTime: 1614281964, - blockhash: '57zQNBZBEiHsCZFqsaY6h176ioXy5MsSLmcvHkEyaLGy', - previousBlockhash: 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo', - parentSlot: 0, - transactions: [ - { - meta: { - fee: 10000, - postBalances: [499260347380, 15298080, 1, 1, 1], - preBalances: [499260357380, 15298080, 1, 1, 1], - status: {Ok: null}, - err: null, - }, - transaction: { - message: { - accountKeys: [ - 'va12u4o9DipLEB2z4fuoHszroq1U9NcAB9aooFDPJSf', - '57zQNBZBEiHsCZFqsaY6h176ioXy5MsSLmcvHkEyaLGy', - 'SysvarS1otHashes111111111111111111111111111', - 'SysvarC1ock11111111111111111111111111111111', - 'Vote111111111111111111111111111111111111111', - ], - header: { - numReadonlySignedAccounts: 0, - numReadonlyUnsignedAccounts: 3, - numRequiredSignatures: 2, - }, - instructions: [ - { - accounts: [1, 2, 3], - data: '37u9WtQpcm6ULa3VtWDFAWoQc1hUvybPrA3dtx99tgHvvcE7pKRZjuGmn7VX2tC3JmYDYGG7', - programIdIndex: 4, - }, - ], - recentBlockhash: - 'GeyAFFRY3WGpmam2hbgrKw4rbU2RKzfVLm5QLSeZwTZE', - }, - signatures: [ - 'w2Zeq8YkpyB463DttvfzARD7k9ZxGEwbsEw4boEK7jDp3pfoxZbTdLFSsEPhzXhpCcjGi2kHtHFobgX49MMhbWt', - '4oCEqwGrMdBeMxpzuWiukCYqSfV4DsSKXSiVVCh1iJ6pS772X7y219JZP3mgqBz5PhsvprpKyhzChjYc3VSBQXzG', - ], - }, - }, - ], - }, - }); - - // Find a block that has a transaction *and* a parent. - await mockRpcResponse({ - method: 'getFirstAvailableBlock', - params: [], - value: 0, - }); - let candidateSlot = (await connection.getFirstAvailableBlock()) + 1; - let result: - | { - blockWithTransaction: BlockResponse; - parentBlock: BlockResponse; - } - | undefined; - while (!result) { - const candidateBlock = await connection.getBlock(candidateSlot); - if (candidateBlock && candidateBlock.transactions.length) { - const parentBlock = await connection.getBlock(candidateSlot - 1); - if (parentBlock) { - result = {blockWithTransaction: candidateBlock, parentBlock}; - break; - } - } - candidateSlot++; - } - - // Compare data with parent - expect(result.blockWithTransaction.previousBlockhash).to.eq( - result.parentBlock.blockhash, - ); - expect(result.blockWithTransaction.blockhash).not.to.be.null; - expect(result.blockWithTransaction.transactions[0].transaction).not.to.be - .null; - - await mockRpcResponse({ - method: 'getBlock', - params: [Number.MAX_SAFE_INTEGER], - error: { - message: `Block not available for slot ${Number.MAX_SAFE_INTEGER}`, - }, - }); - await expect( - connection.getBlock(Number.MAX_SAFE_INTEGER), - ).to.be.rejectedWith( - `Block not available for slot ${Number.MAX_SAFE_INTEGER}`, - ); - }); - - it('can deserialize a response when `transactionDetails` is `full`', async () => { - // Mock block with transaction, fetched using `"transactionDetails": "full"`. - await mockRpcResponse({ - method: 'getBlock', - params: [ - 1, - { - maxSupportedTransactionVersion: 0, - transactionDetails: 'full', - }, - ], - value: { - blockHeight: 0, - blockTime: 1614281964, - blockhash: '49d2UbduiZWjtR3Wvfv2t2QxmXvtZNWSPFRZxEDYAvQN', - parentSlot: 0, - previousBlockhash: 'mDd5yMLfuroS1JVZMHo2VZLTgKXXNBXrzPR5UkzFD4X', - transactions: [ - { - meta: { - err: null, - fee: 5000, - innerInstructions: [], - loadedAddresses: {readonly: [], writable: []}, - logMessages: [ - 'Program Vote111111111111111111111111111111111111111 invoke [1]', - 'Program Vote111111111111111111111111111111111111111 success', - ], - postBalances: [12278161908, 39995373, 1169280, 143487360, 1], - postTokenBalances: [], - preBalances: [12278166908, 39995373, 1169280, 143487360, 1], - preTokenBalances: [], - rewards: null, - status: {Ok: null}, - }, - transaction: { - message: { - accountKeys: [ - 'FTWuJ2tqjecNizCSE66z4BD1tBHomG6DVffGUwRuWUkM', - 'H2z3pBT62ByS4jpqsiEMtgN3NUFEuZHiTvoKCFjqCtD6', - 'SysvarC1ock11111111111111111111111111111111', - 'SysvarS1otHashes111111111111111111111111111', - 'Vote111111111111111111111111111111111111111', - ], - header: { - numReadonlySignedAccounts: 0, - numReadonlyUnsignedAccounts: 3, - numRequiredSignatures: 1, - }, - instructions: [ - { - accounts: [1, 3, 2, 0], - data: '29z5mr1JoRmJYQ6zG7p2F3mu68pWTNw9q49Tu7KrSEgoS6Jh1LMPGUK3HXs1N3Dody3icCcXxu6xPYoXLWnUTafEGm3knK', - programIdIndex: 4, - }, - ], - recentBlockhash: - 'GLqYrN6AQxCGtFTQywkPj2WN5tafC3KerBhW4QkmAyD4', - }, - signatures: [ - '4SZofEnXEVzCYvzk16z6ScR6F3iNtZ3FsCC1PEWegpzvGwTJR6x9cDi8VHRmCFGC5XFs2yEFms3j36Mj7XVyHXbb', - ], - }, - version: 'legacy', - }, - ], - }, - }); - await expect( - connection.getBlock(1, { - maxSupportedTransactionVersion: 0, - transactionDetails: 'full', - }), - ).not.to.eventually.be.rejected; - }); - - it('can deserialize a response when `transactionDetails` is `none`', async () => { - // Mock block with transaction, fetched using `"transactionDetails": "none"`. - await mockRpcResponse({ - method: 'getBlock', - params: [ - 1, - { - maxSupportedTransactionVersion: 0, - transactionDetails: 'none', - }, - ], - value: { - blockHeight: 0, - blockTime: 1614281964, - blockhash: '49d2UbduiZWjtR3Wvfv2t2QxmXvtZNWSPFRZxEDYAvQN', - parentSlot: 0, - previousBlockhash: 'mDd5yMLfuroS1JVZMHo2VZLTgKXXNBXrzPR5UkzFD4X', - }, - }); - await expect( - connection.getBlock(1, { - maxSupportedTransactionVersion: 0, - transactionDetails: 'none', - }), - ).not.to.eventually.be.rejected; - }); - - it('can deserialize a response when `transactionDetails` is `accounts`', async () => { - // Mock block with transaction, fetched using `"transactionDetails": "accounts"`. - await mockRpcResponse({ - method: 'getBlock', - params: [ - 1, - { - maxSupportedTransactionVersion: 0, - transactionDetails: 'accounts', - }, - ], - value: { - blockHeight: 0, - blockTime: 1614281964, - blockhash: '49d2UbduiZWjtR3Wvfv2t2QxmXvtZNWSPFRZxEDYAvQN', - parentSlot: 0, - previousBlockhash: 'mDd5yMLfuroS1JVZMHo2VZLTgKXXNBXrzPR5UkzFD4X', - transactions: [ - { - meta: { - err: null, - fee: 5000, - postBalances: [2751549948, 11751747405, 1169280, 143487360, 1], - postTokenBalances: [], - preBalances: [2751554948, 11751747405, 1169280, 143487360, 1], - preTokenBalances: [], - status: {Ok: null}, - }, - transaction: { - accountKeys: [ - { - pubkey: 'D7hwgGRTr1vaCxzmfEKCaf56SPgBJmjHh6UXHG3p12bB', - signer: true, - source: 'transaction', - writable: true, - }, - { - pubkey: '8iLE53Y9k4sccy4gxrT936BHbhYS6J13kQT5vRXhXFMX', - signer: false, - source: 'transaction', - writable: true, - }, - { - pubkey: 'SysvarC1ock11111111111111111111111111111111', - signer: false, - source: 'transaction', - writable: false, - }, - { - pubkey: 'SysvarS1otHashes111111111111111111111111111', - signer: false, - source: 'transaction', - writable: false, - }, - { - pubkey: 'Vote111111111111111111111111111111111111111', - signer: false, - source: 'transaction', - writable: false, - }, - ], - signatures: [ - 'uNKj2ogn8ZRRjyVWXLC7sLRWpKQyMUomm66RXoDuWLXikPSJN8C7ZZK95j8S2bzcjwH6MvrXKSHtCWEURPpEXMB', - ], - }, - version: 'legacy', - }, - ], - }, - }); - await expect( - connection.getBlock(1, { - maxSupportedTransactionVersion: 0, - transactionDetails: 'accounts', - }), - ).not.to.eventually.be.rejected; - }); - }); - - describe('get confirmed block', function () { - beforeEach(async function () { - await mockRpcResponse({ - method: 'getSlot', - params: [], - value: 1, - }); - - await waitForSlot.call(this, connection); - }); - - it('gets the genesis block', async function () { - await mockRpcResponse({ - method: 'getConfirmedBlock', - params: [0], - value: { - blockHeight: 0, - blockTime: 1614281964, - blockhash: 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo', - previousBlockhash: 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo', - parentSlot: 0, - transactions: [], - }, - }); - - let block0: ConfirmedBlock; - try { - block0 = await connection.getConfirmedBlock(0); - } catch (e) { - if (process.env.TEST_LIVE) { - console.warn( - 'WARNING: We ran no assertions about the genesis block because block 0 ' + - 'could not be found. See https://github.com/solana-labs/solana/issues/23853.', - ); - this.skip(); - } else { - throw e; - } - } - - // Block 0 never has any transactions in test validator - const blockhash0 = block0.blockhash; - expect(block0.transactions).to.have.length(0); - expect(blockhash0).not.to.be.null; - expect(block0.previousBlockhash).not.to.be.null; - expect(block0.parentSlot).to.eq(0); - }); - - it('gets a block having a parent', async function () { - // Mock parent of block with transaction. - await mockRpcResponse({ - method: 'getConfirmedBlock', - params: [0], - value: { - blockHeight: 0, - blockTime: 1614281964, - blockhash: 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo', - previousBlockhash: 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo', - parentSlot: 0, - transactions: [], - }, - }); - // Mock block with transaction. - await mockRpcResponse({ - method: 'getConfirmedBlock', - params: [1], - value: { - blockTime: 1614281964, - blockhash: '57zQNBZBEiHsCZFqsaY6h176ioXy5MsSLmcvHkEyaLGy', - previousBlockhash: 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo', - parentSlot: 0, - transactions: [ - { - meta: { - fee: 10000, - postBalances: [499260347380, 15298080, 1, 1, 1], - preBalances: [499260357380, 15298080, 1, 1, 1], - status: {Ok: null}, - err: null, - }, - transaction: { - message: { - accountKeys: [ - 'va12u4o9DipLEB2z4fuoHszroq1U9NcAB9aooFDPJSf', - '57zQNBZBEiHsCZFqsaY6h176ioXy5MsSLmcvHkEyaLGy', - 'SysvarS1otHashes111111111111111111111111111', - 'SysvarC1ock11111111111111111111111111111111', - 'Vote111111111111111111111111111111111111111', - ], - header: { - numReadonlySignedAccounts: 0, - numReadonlyUnsignedAccounts: 3, - numRequiredSignatures: 2, - }, - instructions: [ - { - accounts: [1, 2, 3], - data: '37u9WtQpcm6ULa3VtWDFAWoQc1hUvybPrA3dtx99tgHvvcE7pKRZjuGmn7VX2tC3JmYDYGG7', - programIdIndex: 4, - }, - ], - recentBlockhash: - 'GeyAFFRY3WGpmam2hbgrKw4rbU2RKzfVLm5QLSeZwTZE', - }, - signatures: [ - 'w2Zeq8YkpyB463DttvfzARD7k9ZxGEwbsEw4boEK7jDp3pfoxZbTdLFSsEPhzXhpCcjGi2kHtHFobgX49MMhbWt', - '4oCEqwGrMdBeMxpzuWiukCYqSfV4DsSKXSiVVCh1iJ6pS772X7y219JZP3mgqBz5PhsvprpKyhzChjYc3VSBQXzG', - ], - }, - }, - ], - }, - }); - - // Find a block that has a transaction *and* a parent. - await mockRpcResponse({ - method: 'getFirstAvailableBlock', - params: [], - value: 0, - }); - let candidateSlot = (await connection.getFirstAvailableBlock()) + 1; - let result: - | { - blockWithTransaction: ConfirmedBlock; - parentBlock: ConfirmedBlock; - } - | undefined; - while (!result) { - const candidateBlock = - await connection.getConfirmedBlock(candidateSlot); - if (candidateBlock && candidateBlock.transactions.length) { - const parentBlock = await connection.getConfirmedBlock( - candidateSlot - 1, - ); - if (parentBlock) { - result = {blockWithTransaction: candidateBlock, parentBlock}; - break; - } - } - candidateSlot++; - } - - // Compare data with parent - expect(result.blockWithTransaction.previousBlockhash).to.eq( - result.parentBlock.blockhash, - ); - expect(result.blockWithTransaction.blockhash).not.to.be.null; - expect(result.blockWithTransaction.transactions[0].transaction).not.to.be - .null; - - await mockRpcResponse({ - method: 'getConfirmedBlock', - params: [Number.MAX_SAFE_INTEGER], - error: { - message: `Block not available for slot ${Number.MAX_SAFE_INTEGER}`, - }, - }); - await expect( - connection.getConfirmedBlock(Number.MAX_SAFE_INTEGER), - ).to.be.rejectedWith( - `Block not available for slot ${Number.MAX_SAFE_INTEGER}`, - ); - }); - }); - - it('get blocks between two slots', async function () { - await mockRpcResponse({ - method: 'getBlocks', - params: [0, 9], - value: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - }); - await mockRpcResponse({ - method: 'getFirstAvailableBlock', - params: [], - value: 0, - }); - await mockRpcResponse({ - method: 'getSlot', - params: [], - value: 9, - }); - - await waitForSlot.call(this, connection, 1); - - const [startSlot, latestSlot] = await Promise.all([ - connection.getFirstAvailableBlock(), - connection.getSlot(), - ]); - const blocks = await connection.getBlocks(startSlot, latestSlot); - expect(blocks).to.have.length(latestSlot - startSlot + 1); - expect(blocks[0]).to.eq(startSlot); - expect(blocks).to.contain(latestSlot); - }); - - it('get blocks from starting slot', async function () { - await mockRpcResponse({ - method: 'getBlocks', - params: [0], - value: [ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, - 38, 39, 40, 41, 42, - ], - }); - await mockRpcResponse({ - method: 'getFirstAvailableBlock', - params: [], - value: 0, - }); - await mockRpcResponse({ - method: 'getSlot', - params: [], - value: 20, - }); - - await waitForSlot.call(this, connection, 1); - - const startSlot = await connection.getFirstAvailableBlock(); - const [blocks, latestSlot] = await Promise.all([ - connection.getBlocks(startSlot), - connection.getSlot(), - ]); - if (mockServer) { - expect(blocks).to.have.length(43); - } else { - expect(blocks).to.have.length(latestSlot - startSlot + 1); - } - expect(blocks[0]).to.eq(startSlot); - expect(blocks).to.contain(latestSlot); - }); - - describe('get block signatures', function () { - beforeEach(async function () { - await mockRpcResponse({ - method: 'getSlot', - params: [], - value: 1, - }); - - await waitForSlot.call(this, connection); - }); - - it('gets the genesis block', async function () { - await mockRpcResponse({ - method: 'getBlock', - params: [ - 0, - { - transactionDetails: 'signatures', - rewards: false, - }, - ], - value: { - blockHeight: 0, - blockTime: 1614281964, - blockhash: 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo', - previousBlockhash: 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo', - parentSlot: 0, - signatures: [], - }, - }); - - let block0: BlockSignatures; - try { - block0 = await connection.getBlockSignatures(0); - } catch (e) { - if (process.env.TEST_LIVE) { - console.warn( - 'WARNING: We ran no assertions about the genesis block because block 0 ' + - 'could not be found. See https://github.com/solana-labs/solana/issues/23853.', - ); - this.skip(); - } else { - throw e; - } - } - - // Block 0 never has any transactions in test validator - const blockhash0 = block0.blockhash; - expect(block0.signatures).to.have.length(0); - expect(blockhash0).not.to.be.null; - expect(block0.previousBlockhash).not.to.be.null; - expect(block0.parentSlot).to.eq(0); - expect(block0).to.not.have.property('rewards'); - }); - - it('gets a block having a parent', async function () { - // Mock parent of block with transaction. - await mockRpcResponse({ - method: 'getBlock', - params: [ - 0, - { - transactionDetails: 'signatures', - rewards: false, - }, - ], - value: { - blockHeight: 0, - blockTime: 1614281964, - blockhash: 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo', - previousBlockhash: 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo', - parentSlot: 0, - signatures: [], - }, - }); - // Mock block with transaction. - await mockRpcResponse({ - method: 'getBlock', - params: [ - 1, - { - transactionDetails: 'signatures', - rewards: false, - }, - ], - value: { - blockHeight: 1, - blockTime: 1614281964, - blockhash: '57zQNBZBEiHsCZFqsaY6h176ioXy5MsSLmcvHkEyaLGy', - previousBlockhash: 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo', - parentSlot: 0, - signatures: [ - 'w2Zeq8YkpyB463DttvfzARD7k9ZxGEwbsEw4boEK7jDp3pfoxZbTdLFSsEPhzXhpCcjGi2kHtHFobgX49MMhbWt', - '4oCEqwGrMdBeMxpzuWiukCYqSfV4DsSKXSiVVCh1iJ6pS772X7y219JZP3mgqBz5PhsvprpKyhzChjYc3VSBQXzG', - ], - }, - }); - - // Find a block that has a transaction *and* a parent. - await mockRpcResponse({ - method: 'getFirstAvailableBlock', - params: [], - value: 0, - }); - let candidateSlot = (await connection.getFirstAvailableBlock()) + 1; - let result: - | { - blockWithTransaction: BlockSignatures; - parentBlock: BlockSignatures; - } - | undefined; - while (!result) { - const candidateBlock = - await connection.getBlockSignatures(candidateSlot); - if (candidateBlock && candidateBlock.signatures.length) { - const parentBlock = await connection.getBlockSignatures( - candidateSlot - 1, - ); - if (parentBlock) { - result = {blockWithTransaction: candidateBlock, parentBlock}; - break; - } - } - candidateSlot++; - } - - // Compare data with parent - expect(result.blockWithTransaction.previousBlockhash).to.eq( - result.parentBlock.blockhash, - ); - expect(result.blockWithTransaction.blockhash).not.to.be.null; - expect(result.blockWithTransaction.signatures[0]).not.to.be.null; - expect(result.blockWithTransaction).to.not.have.property('rewards'); - - await mockRpcResponse({ - method: 'getBlock', - params: [Number.MAX_SAFE_INTEGER], - error: { - message: `Block not available for slot ${Number.MAX_SAFE_INTEGER}`, - }, - }); - await expect( - connection.getBlockSignatures(Number.MAX_SAFE_INTEGER), - ).to.be.rejectedWith( - `Block not available for slot ${Number.MAX_SAFE_INTEGER}`, - ); - }); - }); - - it('get recent blockhash', async () => { - const commitments: Commitment[] = ['processed', 'confirmed', 'finalized']; - for (const commitment of commitments) { - const {blockhash, feeCalculator} = await helpers.recentBlockhash({ - connection, - commitment, - }); - expect(bs58.decode(blockhash)).to.have.length(32); - expect(feeCalculator.lamportsPerSignature).to.be.at.least(0); - } - }); - - it('get latest blockhash', async () => { - const commitments: Commitment[] = ['processed', 'confirmed', 'finalized']; - for (const commitment of commitments) { - const {blockhash, lastValidBlockHeight} = await helpers.latestBlockhash({ - connection, - commitment, - }); - expect(bs58.decode(blockhash)).to.have.length(32); - expect(lastValidBlockHeight).to.be.at.least(0); - } - }); - - it('is blockhash valid', async () => { - const blockhash = 'FDeS2dHPUQgAsLZpExG7WUFiMHRcVGgUAeiJr8rfXR1K'; - for (const isBlockhashValid of mockServer ? [true, false] : [false]) { - await mockRpcResponse({ - method: 'isBlockhashValid', - params: [blockhash, {commitment: 'confirmed'}], - value: isBlockhashValid, - withContext: true, - }); - - const isBlockhashValidRpcResult = await connection.isBlockhashValid( - blockhash, - {commitment: 'confirmed'}, - ); - - expect(isBlockhashValidRpcResult.value).to.eq(isBlockhashValid); - } - }); - - it('get fee calculator', async () => { - const {blockhash} = await helpers.recentBlockhash({connection}); - await mockRpcResponse({ - method: 'getFeeCalculatorForBlockhash', - params: [blockhash, {commitment: 'confirmed'}], - value: { - feeCalculator: { - lamportsPerSignature: 5000, - }, - }, - withContext: true, - }); - - const feeCalculator = ( - await connection.getFeeCalculatorForBlockhash(blockhash, 'confirmed') - ).value; - if (feeCalculator === null) { - expect(feeCalculator).not.to.be.null; - return; - } - expect(feeCalculator.lamportsPerSignature).to.eq(5000); - }); - - it('get fee for message (legacy)', async () => { - const accountFrom = Keypair.generate(); - const accountTo = Keypair.generate(); - - const latestBlockhash = await helpers.latestBlockhash({connection}); - - const transaction = new Transaction({ - feePayer: accountFrom.publicKey, - ...latestBlockhash, - }).add( - SystemProgram.transfer({ - fromPubkey: accountFrom.publicKey, - toPubkey: accountTo.publicKey, - lamports: 10, - }), - ); - const message = transaction.compileMessage(); - - await mockRpcResponse({ - method: 'getFeeForMessage', - params: [ - message.serialize().toString('base64'), - {commitment: 'confirmed'}, - ], - value: 5000, - withContext: true, - }); - - const fee = (await connection.getFeeForMessage(message, 'confirmed')).value; - expect(fee).to.eq(5000); - }); - - it('get fee for message (v0)', async () => { - const accountFrom = Keypair.generate(); - const accountTo = Keypair.generate(); - - const recentBlockhash = (await helpers.latestBlockhash({connection})) - .blockhash; - const instructions = [ - SystemProgram.transfer({ - fromPubkey: accountFrom.publicKey, - toPubkey: accountTo.publicKey, - lamports: 10, - }), - ]; - - const messageV0 = new TransactionMessage({ - payerKey: accountFrom.publicKey, - recentBlockhash, - instructions, - }).compileToV0Message(); - - await mockRpcResponse({ - method: 'getFeeForMessage', - params: [ - toBuffer(messageV0.serialize()).toString('base64'), - {commitment: 'confirmed'}, - ], - value: 5000, - withContext: true, - }); - - const fee = (await connection.getFeeForMessage(messageV0, 'confirmed')) - .value; - expect(fee).to.eq(5000); - }); - - it('get recent prioritization fee', async () => { - const pubkey = Keypair.generate().publicKey; - await mockRpcResponse({ - method: 'getRecentPrioritizationFees', - params: [[pubkey.toBase58()]], - value: [ - { - slot: 348127, - prioritizationFee: 500, - }, - { - slot: 348128, - prioritizationFee: 0, - }, - ], - }); - - const recentPrioritizationFees = - await connection.getRecentPrioritizationFees({ - lockedWritableAccounts: [pubkey], - }); - expect(recentPrioritizationFees).to.be.an('array'); - for (const prioritizationFee of recentPrioritizationFees) { - expect(prioritizationFee.prioritizationFee).to.be.a('number'); - expect(prioritizationFee.slot).to.be.a('number'); - } - }); - - it('get block time', async () => { - await mockRpcResponse({ - method: 'getBlockTime', - params: [1], - value: 10000, - }); - - await mockRpcResponse({ - method: 'getFirstAvailableBlock', - params: [], - value: 1, - }); - const slot = await connection.getFirstAvailableBlock(); - const blockTime = await connection.getBlockTime(slot); - if (blockTime === null) { - expect(blockTime).not.to.be.null; - } else { - expect(blockTime).to.be.greaterThan(0); - } - }); - - it('get minimum ledger slot', async () => { - await mockRpcResponse({ - method: 'minimumLedgerSlot', - params: [], - value: 0, - }); - - const minimumLedgerSlot = await connection.getMinimumLedgerSlot(); - expect(minimumLedgerSlot).to.be.at.least(0); - }); - - it('get first available block', async () => { - await mockRpcResponse({ - method: 'getFirstAvailableBlock', - params: [], - value: 0, - }); - - const firstAvailableBlock = await connection.getFirstAvailableBlock(); - expect(firstAvailableBlock).to.be.at.least(0); - }); - - it('get supply', async () => { - await mockRpcResponse({ - method: 'getSupply', - params: [{commitment: 'finalized'}], - value: { - total: 1000, - circulating: 100, - nonCirculating: 900, - nonCirculatingAccounts: [Keypair.generate().publicKey.toBase58()], - }, - withContext: true, - }); - - const supply = (await connection.getSupply('finalized')).value; - expect(supply.total).to.be.greaterThan(0); - expect(supply.circulating).to.be.greaterThan(0); - expect(supply.nonCirculating).to.be.at.least(0); - expect(supply.nonCirculatingAccounts.length).to.be.at.least(0); - }); - - it('get supply without accounts', async () => { - await mockRpcResponse({ - method: 'getSupply', - params: [{commitment: 'finalized'}], - value: { - total: 1000, - circulating: 100, - nonCirculating: 900, - nonCirculatingAccounts: [], - }, - withContext: true, - }); - - const supply = ( - await connection.getSupply({ - commitment: 'finalized', - excludeNonCirculatingAccountsList: true, - }) - ).value; - expect(supply.total).to.be.greaterThan(0); - expect(supply.circulating).to.be.greaterThan(0); - expect(supply.nonCirculating).to.be.at.least(0); - expect(supply.nonCirculatingAccounts.length).to.eq(0); - }); - - [undefined, 'confirmed' as Commitment].forEach(function (commitment) { - describe( - "when the connection's default commitment is `" + commitment + '`', - () => { - let connectionWithCommitment: Connection; - beforeEach(() => { - connectionWithCommitment = new Connection(url, commitment); - }); - it('get performance samples', async () => { - await mockRpcResponse({ - method: 'getRecentPerformanceSamples', - params: [], - value: [ - { - slot: 1234, - numTransactions: 1000, - numSlots: 60, - samplePeriodSecs: 60, - }, - ], - }); - - const perfSamples = - await connectionWithCommitment.getRecentPerformanceSamples(); - expect(Array.isArray(perfSamples)).to.be.true; - - if (perfSamples.length > 0) { - expect(perfSamples[0].slot).to.be.greaterThan(0); - expect(perfSamples[0].numTransactions).to.be.greaterThan(0); - expect(perfSamples[0].numSlots).to.be.greaterThan(0); - expect(perfSamples[0].samplePeriodSecs).to.be.greaterThan(0); - } - }); - }, - ); - }); - - it('get performance samples limit too high', async () => { - await mockRpcResponse({ - method: 'getRecentPerformanceSamples', - params: [100000], - error: mockErrorResponse, - }); - - await expect(connection.getRecentPerformanceSamples(100000)).to.be.rejected; - }); - - const TOKEN_PROGRAM_ID = new PublicKey( - 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', - ); - - if (process.env.TEST_LIVE) { - describe('token methods', () => { - const connection = new Connection(url, 'confirmed'); - const newAccount = PublicKey.unique(); - - // See scripts/fixtures/legacy-token-test-mint-account.json - const testTokenMintPubkey = new PublicKey( - '7MbpdfJa5xqwexkp6WUvkYHTPo4VgxYACDBNFWYLwCdo', - ); - // See scripts/fixtures/legacy-token-test-token-owner.json - const testOwnerKeypair = Keypair.fromSecretKey( - // Public key: `AVGuygVeBmbYiJ47V7tgBNLSukNqW7pWZYJsKUNWhHpc` - new Uint8Array([ - 153, 120, 247, 45, 160, 119, 144, 219, 220, 209, 73, 91, 210, 102, 31, - 136, 155, 12, 68, 27, 226, 215, 61, 214, 10, 245, 247, 180, 236, 63, - 100, 202, 140, 247, 112, 54, 120, 32, 168, 118, 72, 115, 190, 34, 171, - 126, 15, 119, 252, 173, 50, 173, 8, 10, 96, 239, 21, 32, 94, 67, 37, - 43, 145, 249, - ]), - ); - // See scripts/fixtures/legacy-token-test-token-account.json - const testTokenAccountPubkey = new PublicKey( - 'EryTMgfSEabo5Fc7dN5z3nBQKzfHUJRpHAMnXdCrTq4S', - ); - let selfTransferSignature: TransactionSignature; - - // Setup token mints and accounts for token tests - before(async function () { - this.timeout(30 * 1000); - - const selfTransferTransaction = new Transaction().add( - new TransactionInstruction({ - keys: [ - { - pubkey: testTokenAccountPubkey, - isSigner: false, - isWritable: true, - }, - { - pubkey: testTokenAccountPubkey, - isSigner: false, - isWritable: true, - }, - { - pubkey: testOwnerKeypair.publicKey, - isSigner: true, - isWritable: false, - }, - ], - programId: new PublicKey( - 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', - ), - data: Buffer.from( - // prettier-ignore - [ - 3, // TRANSFER instruction - 1, 0, 0, 0, 0, 0, 0, 0, // 1 Lamport - ], - ), - }), - ); - - selfTransferSignature = await sendAndConfirmTransaction( - connection, - selfTransferTransaction, - [testOwnerKeypair], - ); - }); - - it('get token supply', async () => { - const supply = (await connection.getTokenSupply(testTokenMintPubkey)) - .value; - expect(supply.uiAmount).to.eq(111.11); - expect(supply.decimals).to.eq(2); - expect(supply.amount).to.eq('11111'); - - await expect(connection.getTokenSupply(newAccount)).to.be.rejected; - }); - - it('get token largest accounts', async () => { - const largestAccounts = ( - await connection.getTokenLargestAccounts(testTokenMintPubkey) - ).value; - - expect(largestAccounts).to.have.length(1); - const largestAccount = largestAccounts[0]; - expect(largestAccount.address.equals(testTokenAccountPubkey)).to.be - .true; - expect(largestAccount.amount).to.eq('11110'); - expect(largestAccount.decimals).to.eq(2); - expect(largestAccount.uiAmount).to.eq(111.1); - - await expect(connection.getTokenLargestAccounts(newAccount)).to.be - .rejected; - }); - - it('get confirmed token transaction', async () => { - const parsedTx = await connection.getParsedConfirmedTransaction( - selfTransferSignature, - ); - if (parsedTx === null) { - expect(parsedTx).not.to.be.null; - return; - } - const {signatures, message} = parsedTx.transaction; - expect(signatures[0]).to.eq(selfTransferSignature); - const ix = message.instructions[0]; - if ('parsed' in ix) { - expect(ix.program).to.eq('spl-token'); - expect(ix.programId).to.eql(TOKEN_PROGRAM_ID); - } else { - expect('parsed' in ix).to.be.true; - } - - const missingSignature = - '45pGoC4Rr3fJ1TKrsiRkhHRbdUeX7633XAGVec6XzVdpRbzQgHhe6ZC6Uq164MPWtiqMg7wCkC6Wy3jy2BqsDEKf'; - const nullResponse = - await connection.getParsedConfirmedTransaction(missingSignature); - - expect(nullResponse).to.be.null; - }); - - it('get token account balance', async () => { - const balance = ( - await connection.getTokenAccountBalance(testTokenAccountPubkey) - ).value; - expect(balance.amount).to.eq('11110'); - expect(balance.decimals).to.eq(2); - expect(balance.uiAmount).to.eq(111.1); - - await expect(connection.getTokenAccountBalance(newAccount)).to.be - .rejected; - }); - - it('get parsed token account info', async () => { - const accountInfo = ( - await connection.getParsedAccountInfo(testTokenAccountPubkey) - ).value; - if (accountInfo) { - const data = accountInfo.data; - if (Buffer.isBuffer(data)) { - expect(Buffer.isBuffer(data)).to.eq(false); - } else { - expect(data.program).to.eq('spl-token'); - expect(data.parsed).to.be.ok; - } - } - }); - - it('get multiple parsed token accounts', async () => { - const accounts = ( - await connection.getMultipleParsedAccounts([ - testTokenAccountPubkey, - testTokenMintPubkey, - testOwnerKeypair.publicKey, - newAccount, - ]) - ).value; - expect(accounts.length).to.eq(4); - - const parsedTokenAccount = accounts[0]; - if (parsedTokenAccount) { - const data = parsedTokenAccount.data; - if (Buffer.isBuffer(data)) { - expect(Buffer.isBuffer(data)).to.eq(false); - } else { - expect(data.program).to.eq('spl-token'); - expect(data.parsed).to.be.ok; - } - } else { - expect(parsedTokenAccount).to.be.ok; - } - - const parsedTokenMint = accounts[1]; - if (parsedTokenMint) { - const data = parsedTokenMint.data; - if (Buffer.isBuffer(data)) { - expect(Buffer.isBuffer(data)).to.eq(false); - } else { - expect(data.program).to.eq('spl-token'); - expect(data.parsed).to.be.ok; - } - } else { - expect(parsedTokenMint).to.be.ok; - } - - const unparsedOwnerAccount = accounts[2]; - if (unparsedOwnerAccount) { - const data = unparsedOwnerAccount.data; - expect(Buffer.isBuffer(data)).to.be.true; - } else { - expect(unparsedOwnerAccount).to.be.ok; - } - - const unknownAccount = accounts[3]; - expect(unknownAccount).to.not.be.ok; - }); - - it('get parsed token program accounts', async () => { - const tokenAccounts = - await connection.getParsedProgramAccounts(TOKEN_PROGRAM_ID); - tokenAccounts.forEach(({account}) => { - expect(account.owner).to.eql(TOKEN_PROGRAM_ID); - const data = account.data; - if (Buffer.isBuffer(data)) { - expect(Buffer.isBuffer(data)).to.eq(false); - } else { - expect(data.parsed).to.be.ok; - expect(data.program).to.eq('spl-token'); - } - }); - }); - - it('get parsed token accounts by owner', async () => { - const tokenAccounts = ( - await connection.getParsedTokenAccountsByOwner( - testOwnerKeypair.publicKey, - { - mint: testTokenMintPubkey, - }, - ) - ).value; - tokenAccounts.forEach(({account}) => { - expect(account.owner).to.eql(TOKEN_PROGRAM_ID); - const data = account.data; - if (Buffer.isBuffer(data)) { - expect(Buffer.isBuffer(data)).to.eq(false); - } else { - expect(data.parsed).to.be.ok; - expect(data.program).to.eq('spl-token'); - } - }); - }); - - it('get token accounts by owner', async () => { - const accountsWithMintFilter = ( - await connection.getTokenAccountsByOwner(testOwnerKeypair.publicKey, { - mint: testTokenMintPubkey, - }) - ).value; - expect(accountsWithMintFilter).to.have.length(1); - - const accountsWithProgramFilter = ( - await connection.getTokenAccountsByOwner(testOwnerKeypair.publicKey, { - programId: TOKEN_PROGRAM_ID, - }) - ).value; - expect(accountsWithProgramFilter).to.have.length(1); - - const noAccounts = ( - await connection.getTokenAccountsByOwner(newAccount, { - mint: testTokenMintPubkey, - }) - ).value; - expect(noAccounts).to.have.length(0); - - await expect( - connection.getTokenAccountsByOwner(testOwnerKeypair.publicKey, { - mint: newAccount, - }), - ).to.be.rejected; - - await expect( - connection.getTokenAccountsByOwner(testOwnerKeypair.publicKey, { - programId: newAccount, - }), - ).to.be.rejected; - }); - }); - - it('consistent preflightCommitment', async () => { - const connection = new Connection(url, 'singleGossip'); - const sender = Keypair.generate(); - const recipient = Keypair.generate(); - let signature = await connection.requestAirdrop( - sender.publicKey, - 2 * LAMPORTS_PER_SOL, - ); - await connection.confirmTransaction(signature, 'singleGossip'); - const transaction = new Transaction().add( - SystemProgram.transfer({ - fromPubkey: sender.publicKey, - toPubkey: recipient.publicKey, - lamports: LAMPORTS_PER_SOL, - }), - ); - await sendAndConfirmTransaction(connection, transaction, [sender]); - }); - } - - // FIXME Remove when https://github.com/anza-xyz/agave/pull/483 is deployed. - ( - [undefined, 'processed', 'confirmed', 'finalized'] as ( - | Commitment - | undefined - )[] - ).forEach(explicitPreflightCommitment => { - it(`sets \`preflightCommitment\` to \`processed\` when \`skipPreflight\` is \`true\`, no matter that \`preflightCommitment\` was set to \`${explicitPreflightCommitment}\``, () => { - const connection = new Connection(url); - const rpcRequestMethod = spy(connection, '_rpcRequest'); - connection.sendEncodedTransaction('ENCODEDTRANSACTION', { - ...(explicitPreflightCommitment - ? {preflightCommitment: explicitPreflightCommitment} - : null), - skipPreflight: true, - }); - expect(rpcRequestMethod).to.have.been.calledWithExactly( - 'sendTransaction', - [match.any, match.has('preflightCommitment', 'processed')], - ); - }); - }); - - it('get largest accounts', async () => { - await mockRpcResponse({ - method: 'getLargestAccounts', - params: [], - value: new Array(20).fill(0).map(() => ({ - address: Keypair.generate().publicKey.toBase58(), - lamports: 1000, - })), - withContext: true, - }); - - const largestAccounts = (await connection.getLargestAccounts()).value; - expect(largestAccounts).to.have.length(20); - }); - - it('stake activation should throw when called for not delegated account', async () => { - const publicKey = Keypair.generate().publicKey; - await mockRpcResponse({ - method: 'getStakeActivation', - params: [publicKey.toBase58(), {}], - error: {message: 'account not delegated'}, - }); - - await expect(connection.getStakeActivation(publicKey)).to.be.rejected; - }); - - if (process.env.TEST_LIVE) { - it('stake activation should return activating for new accounts', async () => { - // todo: use `Connection.getMinimumStakeDelegation` when implemented - const MIN_STAKE_DELEGATION = LAMPORTS_PER_SOL; - const STAKE_ACCOUNT_MIN_BALANCE = - await connection.getMinimumBalanceForRentExemption(StakeProgram.space); - - const voteAccounts = await connection.getVoteAccounts(); - const voteAccount = voteAccounts.current.concat( - voteAccounts.delinquent, - )[0]; - const votePubkey = new PublicKey(voteAccount.votePubkey); - - const authorized = Keypair.generate(); - let signature = await connection.requestAirdrop( - authorized.publicKey, - 2 * LAMPORTS_PER_SOL, - ); - await connection.confirmTransaction(signature, 'confirmed'); - - const newStakeAccount = Keypair.generate(); - let createAndInitialize = StakeProgram.createAccount({ - fromPubkey: authorized.publicKey, - stakePubkey: newStakeAccount.publicKey, - authorized: new Authorized(authorized.publicKey, authorized.publicKey), - lockup: new Lockup(0, 0, new PublicKey(0)), - lamports: STAKE_ACCOUNT_MIN_BALANCE + MIN_STAKE_DELEGATION, - }); - - await sendAndConfirmTransaction( - connection, - createAndInitialize, - [authorized, newStakeAccount], - { - preflightCommitment: 'confirmed', - commitment: 'confirmed', - }, - ); - let delegation = StakeProgram.delegate({ - stakePubkey: newStakeAccount.publicKey, - authorizedPubkey: authorized.publicKey, - votePubkey, - }); - await sendAndConfirmTransaction(connection, delegation, [authorized], { - preflightCommitment: 'confirmed', - commitment: 'confirmed', - }); - - const LARGE_EPOCH = 4000; - await expect( - connection.getStakeActivation( - newStakeAccount.publicKey, - 'confirmed', - LARGE_EPOCH, - ), - ).to.be.rejectedWith( - `failed to get Stake Activation ${newStakeAccount.publicKey.toBase58()}: Invalid param: epoch ${LARGE_EPOCH}. Only the current epoch (0) is supported`, - ); - - const activationState = await connection.getStakeActivation( - newStakeAccount.publicKey, - 'confirmed', - ); - expect(activationState.state).to.eq('activating'); - expect(activationState.inactive).to.eq(MIN_STAKE_DELEGATION); - expect(activationState.active).to.eq(0); - }); - } - - if (mockServer) { - it('stake activation should only accept state with valid string literals', async () => { - const publicKey = Keypair.generate().publicKey; - - const addStakeActivationMock = async (state: any) => { - await mockRpcResponse({ - method: 'getStakeActivation', - params: [publicKey.toBase58(), {}], - value: { - state: state, - active: 0, - inactive: 80, - }, - }); - }; - - await addStakeActivationMock('active'); - let activation = await connection.getStakeActivation( - publicKey, - 'confirmed', - ); - expect(activation.state).to.eq('active'); - expect(activation.active).to.eq(0); - expect(activation.inactive).to.eq(80); - - await addStakeActivationMock('invalid'); - await expect(connection.getStakeActivation(publicKey, 'confirmed')).to.be - .rejected; - }); - } - - it('getVersion', async () => { - await mockRpcResponse({ - method: 'getVersion', - params: [], - value: {'solana-core': '0.20.4'}, - }); - - const version = await connection.getVersion(); - expect(version['solana-core']).to.be.ok; - }); - - it('getGenesisHash', async () => { - await mockRpcResponse({ - method: 'getGenesisHash', - params: [], - value: 'GH7ome3EiwEr7tu9JuTh2dpYWBJK3z69Xm1ZE3MEE6JC', - }); - - const genesisHash = await connection.getGenesisHash(); - expect(genesisHash).not.to.be.empty; - }); - - it('request airdrop', async () => { - const account = Keypair.generate(); - - await helpers.airdrop({ - connection, - address: account.publicKey, - amount: LAMPORTS_PER_SOL, - }); - - await mockRpcResponse({ - method: 'getBalance', - params: [account.publicKey.toBase58(), {commitment: 'confirmed'}], - value: LAMPORTS_PER_SOL, - withContext: true, - }); - - const balance = await connection.getBalance(account.publicKey, 'confirmed'); - expect(balance).to.eq(LAMPORTS_PER_SOL); - - await mockRpcResponse({ - method: 'getAccountInfo', - params: [ - account.publicKey.toBase58(), - {commitment: 'confirmed', encoding: 'base64'}, - ], - value: { - owner: '11111111111111111111111111111111', - lamports: LAMPORTS_PER_SOL, - data: ['', 'base64'], - executable: false, - rentEpoch: 20, - space: 0, - }, - withContext: true, - }); - - const accountInfo = await connection.getAccountInfo( - account.publicKey, - 'confirmed', - ); - if (accountInfo === null) { - expect(accountInfo).not.to.be.null; - return; - } - expect(accountInfo.lamports).to.eq(LAMPORTS_PER_SOL); - expect(accountInfo.data).to.have.length(0); - expect(accountInfo.owner).to.eql(SystemProgram.programId); - - await mockRpcResponse({ - method: 'getAccountInfo', - params: [ - account.publicKey.toBase58(), - {commitment: 'confirmed', encoding: 'jsonParsed'}, - ], - value: { - owner: '11111111111111111111111111111111', - lamports: LAMPORTS_PER_SOL, - data: ['', 'base64'], - executable: false, - rentEpoch: 20, - space: 0, - }, - withContext: true, - }); - - const parsedAccountInfo = ( - await connection.getParsedAccountInfo(account.publicKey, 'confirmed') - ).value; - if (parsedAccountInfo === null) { - expect(parsedAccountInfo).not.to.be.null; - return; - } else if ('parsed' in parsedAccountInfo.data) { - expect(parsedAccountInfo.data.parsed).not.to.be.ok; - return; - } - expect(parsedAccountInfo.lamports).to.eq(LAMPORTS_PER_SOL); - expect(parsedAccountInfo.data).to.have.length(0); - expect(parsedAccountInfo.owner).to.eql(SystemProgram.programId); - }); - - it('transaction failure', async () => { - const payer = Keypair.generate(); - - await helpers.airdrop({ - connection, - address: payer.publicKey, - amount: LAMPORTS_PER_SOL, - }); - - const newAccount = Keypair.generate(); - let transaction = new Transaction().add( - SystemProgram.createAccount({ - fromPubkey: payer.publicKey, - newAccountPubkey: newAccount.publicKey, - lamports: LAMPORTS_PER_SOL / 2, - space: 0, - programId: SystemProgram.programId, - }), - ); - - await helpers.processTransaction({ - connection, - transaction, - signers: [payer, newAccount], - commitment: 'confirmed', - }); - - // This should fail because the account is already created - const expectedErr = {InstructionError: [0, {Custom: 0}]}; - const confirmResult = ( - await helpers.processTransaction({ - connection, - transaction, - signers: [payer, newAccount], - commitment: 'confirmed', - err: expectedErr, - }) - ).value; - expect(confirmResult.err).to.eql(expectedErr); - - invariant(transaction.signature); - const signature = bs58.encode(transaction.signature); - await mockRpcResponse({ - method: 'getSignatureStatuses', - params: [[signature]], - value: [ - { - slot: 0, - confirmations: 11, - status: {Err: expectedErr}, - err: expectedErr, - }, - ], - withContext: true, - }); - - const response = (await connection.getSignatureStatus(signature)).value; - verifySignatureStatus(response, expectedErr); - }); - - if (mockServer) { - it('returnData on simulateTransaction', async () => { - const tx = new Transaction(); - tx.feePayer = Keypair.generate().publicKey; - - const getLatestBlockhashResponse = { - method: 'getLatestBlockhash', - params: [], - value: { - blockhash: 'CSymwgTNX1j3E4qhKfJAUE41nBWEwXufoYryPbkde5RR', - feeCalculator: { - lamportsPerSignature: 5000, - }, - lastValidBlockHeight: 51, - }, - withContext: true, - }; - const simulateTransactionResponse = { - method: 'simulateTransaction', - params: [], - value: { - err: null, - accounts: null, - logs: [ - 'Program 83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri invoke [1]', - 'Program 83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri consumed 2366 of 1400000 compute units', - 'Program return: 83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri KgAAAAAAAAA=', - 'Program 83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri success', - ], - returnData: { - data: ['KgAAAAAAAAA==', 'base64'], - programId: '83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri', - }, - unitsConsumed: 2366, - }, - withContext: true, - }; - await mockRpcResponse(getLatestBlockhashResponse); - await mockRpcResponse(simulateTransactionResponse); - const response = (await connection.simulateTransaction(tx)).value; - expect(response.returnData).to.eql({ - data: ['KgAAAAAAAAA==', 'base64'], - programId: '83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri', - }); - }); - } - - if (process.env.TEST_LIVE) { - it('getStakeMinimumDelegation', async () => { - const {value} = await connection.getStakeMinimumDelegation(); - expect(value).to.be.a('number'); - }); - - it('sendTransaction', async () => { - const connection = new Connection(url, 'confirmed'); - const payer = Keypair.generate(); - - await helpers.airdrop({ - connection, - address: payer.publicKey, - amount: LAMPORTS_PER_SOL, - }); - - const recentBlockhash = await ( - await helpers.latestBlockhash({connection}) - ).blockhash; - - const versionedTx = new VersionedTransaction( - new Message({ - header: { - numRequiredSignatures: 1, - numReadonlySignedAccounts: 0, - numReadonlyUnsignedAccounts: 0, - }, - recentBlockhash, - instructions: [], - accountKeys: [payer.publicKey.toBase58()], - }), - ); - - versionedTx.sign([payer]); - await connection.sendTransaction(versionedTx); - }); - - it('simulateTransaction', async () => { - const connection = new Connection(url, 'confirmed'); - const payer = Keypair.generate(); - - await helpers.airdrop({ - connection, - address: payer.publicKey, - amount: LAMPORTS_PER_SOL, - }); - - const recentBlockhash = await ( - await helpers.latestBlockhash({connection}) - ).blockhash; - - const versionedTx = new VersionedTransaction( - new Message({ - header: { - numRequiredSignatures: 1, - numReadonlySignedAccounts: 0, - numReadonlyUnsignedAccounts: 0, - }, - recentBlockhash, - instructions: [], - accountKeys: [payer.publicKey.toBase58()], - }), - ); - - const response = await connection.simulateTransaction(versionedTx, { - accounts: { - encoding: 'base64', - addresses: [payer.publicKey.toBase58()], - }, - }); - expect(response.value.err).to.be.null; - expect(response.value.accounts).to.eql([ - { - data: ['', 'base64'], - executable: false, - lamports: LAMPORTS_PER_SOL - 5000, - owner: SystemProgram.programId.toBase58(), - rentEpoch: 18446744073709552000, - space: 0, - }, - ]); - }); - - it('simulate transaction with message', async () => { - connection._commitment = 'confirmed'; - - const account1 = Keypair.generate(); - const account2 = Keypair.generate(); - - await helpers.airdrop({ - connection, - address: account1.publicKey, - amount: LAMPORTS_PER_SOL, - }); - - await helpers.airdrop({ - connection, - address: account2.publicKey, - amount: LAMPORTS_PER_SOL, - }); - - const recentBlockhash = await ( - await helpers.latestBlockhash({connection}) - ).blockhash; - const message = new Message({ - accountKeys: [ - account1.publicKey.toString(), - account2.publicKey.toString(), - 'Memo1UhkJRfHyvLMcVucJwxXeuD728EqVDDwQDxFMNo', - ], - header: { - numReadonlySignedAccounts: 1, - numReadonlyUnsignedAccounts: 2, - numRequiredSignatures: 1, - }, - instructions: [ - { - accounts: [0, 1], - data: bs58.encode(Buffer.alloc(5).fill(9)), - programIdIndex: 2, - }, - ], - recentBlockhash, - }); - - const results1 = await connection.simulateTransaction( - message, - [account1], - true, - ); - - expect(results1.value.accounts).lengthOf(2); - - const results2 = await connection.simulateTransaction( - message, - [account1], - [ - account1.publicKey, - new PublicKey('Missing111111111111111111111111111111111111'), - ], - ); - - expect(results2.value.accounts).lengthOf(2); - if (results2.value.accounts) { - expect(results2.value.accounts[1]).to.be.null; - } - }).timeout(10000); - - it('transaction', async () => { - connection._commitment = 'confirmed'; - - const accountFrom = Keypair.generate(); - const accountTo = Keypair.generate(); - const minimumAmount = - await connection.getMinimumBalanceForRentExemption(0); - - await helpers.airdrop({ - connection, - address: accountFrom.publicKey, - amount: minimumAmount + 100010, - }); - await helpers.airdrop({ - connection, - address: accountTo.publicKey, - amount: minimumAmount, - }); - - const transaction = new Transaction().add( - SystemProgram.transfer({ - fromPubkey: accountFrom.publicKey, - toPubkey: accountTo.publicKey, - lamports: 10, - }), - ); - - const signature = await sendAndConfirmTransaction( - connection, - transaction, - [accountFrom], - {preflightCommitment: 'confirmed'}, - ); - - // Send again and ensure that new blockhash is used - const lastFetch = Date.now(); - const transaction2 = new Transaction().add( - SystemProgram.transfer({ - fromPubkey: accountFrom.publicKey, - toPubkey: accountTo.publicKey, - lamports: 10, - }), - ); - - const signature2 = await sendAndConfirmTransaction( - connection, - transaction2, - [accountFrom], - {preflightCommitment: 'confirmed'}, - ); - - expect(signature).not.to.eq(signature2); - expect(transaction.recentBlockhash).not.to.eq( - transaction2.recentBlockhash, - ); - - // Send new transaction and ensure that same blockhash is used - const transaction3 = new Transaction().add( - SystemProgram.transfer({ - fromPubkey: accountFrom.publicKey, - toPubkey: accountTo.publicKey, - lamports: 9, - }), - ); - await sendAndConfirmTransaction(connection, transaction3, [accountFrom], { - preflightCommitment: 'confirmed', - }); - expect(transaction2.recentBlockhash).to.eq(transaction3.recentBlockhash); - - // Sleep until blockhash cache times out - await sleep( - Math.max( - 0, - 1000 + BLOCKHASH_CACHE_TIMEOUT_MS - (Date.now() - lastFetch), - ), - ); - - const transaction4 = new Transaction().add( - SystemProgram.transfer({ - fromPubkey: accountFrom.publicKey, - toPubkey: accountTo.publicKey, - lamports: 13, - }), - ); - - await sendAndConfirmTransaction(connection, transaction4, [accountFrom], { - preflightCommitment: 'confirmed', - }); - - expect(transaction4.recentBlockhash).not.to.eq( - transaction3.recentBlockhash, - ); - - // accountFrom may have less than 100000 due to transaction fees - const balance = await connection.getBalance(accountFrom.publicKey); - expect(balance).to.be.greaterThan(0); - expect(balance).to.be.at.most(minimumAmount + 100000); - expect(await connection.getBalance(accountTo.publicKey)).to.eq( - minimumAmount + 42, - ); - }).timeout(45 * 1000); // waits 30s for cache timeout - - it('multi-instruction transaction', async () => { - connection._commitment = 'confirmed'; - - const accountFrom = Keypair.generate(); - const accountTo = Keypair.generate(); - - let signature = await connection.requestAirdrop( - accountFrom.publicKey, - LAMPORTS_PER_SOL, - ); - await connection.confirmTransaction(signature); - expect(await connection.getBalance(accountFrom.publicKey)).to.eq( - LAMPORTS_PER_SOL, - ); - - const minimumAmount = - await connection.getMinimumBalanceForRentExemption(0); - - signature = await connection.requestAirdrop( - accountTo.publicKey, - minimumAmount + 21, - ); - await connection.confirmTransaction(signature); - expect(await connection.getBalance(accountTo.publicKey)).to.eq( - minimumAmount + 21, - ); - - // 1. Move(accountFrom, accountTo) - // 2. Move(accountTo, accountFrom) - const transaction = new Transaction() - .add( - SystemProgram.transfer({ - fromPubkey: accountFrom.publicKey, - toPubkey: accountTo.publicKey, - lamports: 100, - }), - ) - .add( - SystemProgram.transfer({ - fromPubkey: accountTo.publicKey, - toPubkey: accountFrom.publicKey, - lamports: 100, - }), - ); - signature = await connection.sendTransaction( - transaction, - [accountFrom, accountTo], - {skipPreflight: true}, - ); - - await connection.confirmTransaction({ - blockhash: transaction.recentBlockhash!, - lastValidBlockHeight: transaction.lastValidBlockHeight!, - signature: signature, - }); - - const response = (await connection.getSignatureStatus(signature)).value; - if (response !== null) { - expect(typeof response.slot).to.eq('number'); - expect(response.err).to.be.null; - } else { - expect(response).not.to.be.null; - } - - // accountFrom may have less than LAMPORTS_PER_SOL due to transaction fees - expect( - await connection.getBalance(accountFrom.publicKey), - ).to.be.greaterThan(0); - expect(await connection.getBalance(accountFrom.publicKey)).to.be.at.most( - LAMPORTS_PER_SOL, - ); - - expect(await connection.getBalance(accountTo.publicKey)).to.eq( - minimumAmount + 21, - ); - }); - - describe('given an open websocket connection', () => { - beforeEach(async () => { - // Open the socket connection and wait for it to become pingable. - connection._rpcWebSocket.connect(); - // eslint-disable-next-line no-constant-condition - while (true) { - try { - await connection._rpcWebSocket.notify('ping'); - break; - // eslint-disable-next-line no-empty - } catch (_err) {} - await sleep(100); - } - }); - - it('account change notification', async () => { - const connection = new Connection(url, 'confirmed'); - const owner = Keypair.generate(); - - let subscriptionId: number | undefined; - try { - const accountInfoPromise = new Promise>( - resolve => { - subscriptionId = connection.onAccountChange( - owner.publicKey, - resolve, - {commitment: 'confirmed'}, - ); - }, - ); - connection.requestAirdrop(owner.publicKey, LAMPORTS_PER_SOL); - const accountInfo = await accountInfoPromise; - expect(accountInfo.lamports).to.eq(LAMPORTS_PER_SOL); - expect(accountInfo.owner.equals(SystemProgram.programId)).to.be.true; - } finally { - if (subscriptionId != null) { - await connection.removeAccountChangeListener(subscriptionId); - } - } - }); - - it('program account change notification', async () => { - connection._commitment = 'confirmed'; - - const owner = Keypair.generate(); - const programAccount = Keypair.generate(); - const balanceNeeded = - await connection.getMinimumBalanceForRentExemption(0); - - let subscriptionId: number | undefined; - try { - const keyedAccountInfoPromise = new Promise( - resolve => { - subscriptionId = connection.onProgramAccountChange( - SystemProgram.programId, - resolve, - ); - }, - ); - - await helpers.airdrop({ - connection, - address: owner.publicKey, - amount: LAMPORTS_PER_SOL, - }); - - const transaction = new Transaction().add( - SystemProgram.transfer({ - fromPubkey: owner.publicKey, - toPubkey: programAccount.publicKey, - lamports: balanceNeeded, - }), - ); - await sendAndConfirmTransaction(connection, transaction, [owner], { - commitment: 'confirmed', - }); - - const keyedAccountInfo = await keyedAccountInfoPromise; - if (keyedAccountInfo.accountId.equals(programAccount.publicKey)) { - expect(keyedAccountInfo.accountInfo.lamports).to.eq(balanceNeeded); - expect( - keyedAccountInfo.accountInfo.owner.equals( - SystemProgram.programId, - ), - ).to.be.true; - } - } finally { - if (subscriptionId != null) { - await connection.removeProgramAccountChangeListener(subscriptionId); - } - } - }); - - it('slot notification', async () => { - let subscriptionId: number | undefined; - try { - const notifiedSlotInfo = await new Promise(resolve => { - subscriptionId = connection.onSlotChange(resolve); - }); - expect(notifiedSlotInfo.parent).to.be.at.least(0); - expect(notifiedSlotInfo.root).to.be.at.least(0); - expect(notifiedSlotInfo.slot).to.be.at.least(1); - } finally { - if (subscriptionId != null) { - await connection.removeSlotChangeListener(subscriptionId); - } - } - }); - - it('root notification', async () => { - let subscriptionId: number | undefined; - try { - const atLeastTwoRoots = await new Promise(resolve => { - const roots: number[] = []; - subscriptionId = connection.onRootChange(root => { - if (roots.length === 2) { - return; - } - roots.push(root); - if (roots.length === 2) { - // Collect at least two, then resolve. - resolve(roots); - } - }); - }); - expect(atLeastTwoRoots[1]).to.be.greaterThan(atLeastTwoRoots[0]); - } finally { - if (subscriptionId != null) { - await connection.removeRootChangeListener(subscriptionId); - } - } - }); - - it('signature notification', async () => { - const owner = Keypair.generate(); - const signature = await connection.requestAirdrop( - owner.publicKey, - LAMPORTS_PER_SOL, - ); - const signatureResult = await new Promise(resolve => { - // NOTE: Signature subscriptions auto-remove themselves, so there's no - // need to track the subscription id and remove it when the test ends. - connection.onSignature(signature, resolve, 'processed'); - }); - expect(signatureResult.err).to.be.null; - }); - - it('logs notification', async () => { - let subscriptionId: number | undefined; - const owner = Keypair.generate(); - try { - const logPromise = new Promise<[Logs, Context]>(resolve => { - subscriptionId = connection.onLogs( - owner.publicKey, - (logs, ctx) => { - if (!logs.err) { - resolve([logs, ctx]); - } - }, - 'processed', - ); - }); - - // Execute a transaction so that we can pickup its logs. - await connection.requestAirdrop(owner.publicKey, LAMPORTS_PER_SOL); - - const [logsRes, ctx] = await logPromise; - expect(ctx.slot).to.be.greaterThan(0); - expect(logsRes.logs.length).to.eq(2); - expect(logsRes.logs[0]).to.eq( - 'Program 11111111111111111111111111111111 invoke [1]', - ); - expect(logsRes.logs[1]).to.eq( - 'Program 11111111111111111111111111111111 success', - ); - } finally { - if (subscriptionId != null) { - await connection.removeOnLogsListener(subscriptionId); - } - } - }); - }); - - it('https request', async () => { - const connection = new Connection('https://api.mainnet-beta.solana.com'); - const version = await connection.getVersion(); - expect(version['solana-core']).to.be.ok; - }).timeout(20 * 1000); - - let lookupTableKey: PublicKey; - const lookupTableAddresses = new Array(10) - .fill(0) - .map(() => Keypair.generate().publicKey); - - describe('address lookup table program', () => { - const connection = new Connection(url); - const payer = Keypair.generate(); - - before(async () => { - await helpers.airdrop({ - connection, - address: payer.publicKey, - amount: 10 * LAMPORTS_PER_SOL, - }); - }); - - it('createLookupTable', async () => { - const recentSlot = await connection.getSlot('finalized'); - - let createIx: TransactionInstruction; - [createIx, lookupTableKey] = - AddressLookupTableProgram.createLookupTable({ - recentSlot, - payer: payer.publicKey, - authority: payer.publicKey, - }); - - await helpers.processTransaction({ - connection, - transaction: new Transaction().add(createIx), - signers: [payer], - commitment: 'processed', - }); - }); - - it('extendLookupTable', async () => { - const transaction = new Transaction().add( - AddressLookupTableProgram.extendLookupTable({ - lookupTable: lookupTableKey, - addresses: lookupTableAddresses, - authority: payer.publicKey, - payer: payer.publicKey, - }), - ); - - await helpers.processTransaction({ - connection, - transaction, - signers: [payer], - commitment: 'processed', - }); - }); - - it('freezeLookupTable', async () => { - const transaction = new Transaction().add( - AddressLookupTableProgram.freezeLookupTable({ - lookupTable: lookupTableKey, - authority: payer.publicKey, - }), - ); - - await helpers.processTransaction({ - connection, - transaction, - signers: [payer], - commitment: 'processed', - }); - }); - - it('getAddressLookupTable', async () => { - const lookupTableResponse = await connection.getAddressLookupTable( - lookupTableKey, - { - commitment: 'processed', - }, - ); - const lookupTableAccount = lookupTableResponse.value; - if (!lookupTableAccount) { - expect(lookupTableAccount).to.be.ok; - return; - } - expect(lookupTableAccount.isActive()).to.be.true; - expect(lookupTableAccount.state.authority).to.be.undefined; - expect(lookupTableAccount.state.addresses).to.eql(lookupTableAddresses); - }); - }); - - describe('v0 transaction', () => { - const connection = new Connection(url); - const payer = Keypair.generate(); - - before(async () => { - await helpers.airdrop({ - connection, - address: payer.publicKey, - amount: 10 * LAMPORTS_PER_SOL, - }); - }); - - // wait for lookup table to be usable - before(async () => { - const lookupTableResponse = await connection.getAddressLookupTable( - lookupTableKey, - { - commitment: 'processed', - }, - ); - - const lookupTableAccount = lookupTableResponse.value; - if (!lookupTableAccount) { - expect(lookupTableAccount).to.be.ok; - return; - } - - // eslint-disable-next-line no-constant-condition - while (true) { - const latestSlot = await connection.getSlot('confirmed'); - if (latestSlot > lookupTableAccount.state.lastExtendedSlot) { - break; - } else { - console.log('Waiting for next slot...'); - await sleep(500); - } - } - }); - - let signature: TransactionSignature; - let addressTableLookups: MessageAddressTableLookup[]; - it('send and confirm', async () => { - const {blockhash, lastValidBlockHeight} = - await connection.getLatestBlockhash(); - const transferIxData = encodeData(SYSTEM_INSTRUCTION_LAYOUTS.Transfer, { - lamports: BigInt(LAMPORTS_PER_SOL), - }); - addressTableLookups = [ - { - accountKey: lookupTableKey, - writableIndexes: [0], - readonlyIndexes: [], - }, - ]; - const transaction = new VersionedTransaction( - new MessageV0({ - header: { - numRequiredSignatures: 1, - numReadonlySignedAccounts: 0, - numReadonlyUnsignedAccounts: 1, - }, - staticAccountKeys: [payer.publicKey, SystemProgram.programId], - recentBlockhash: blockhash, - compiledInstructions: [ - { - programIdIndex: 1, - accountKeyIndexes: [0, 2], - data: transferIxData, - }, - ], - addressTableLookups, - }), - ); - transaction.sign([payer]); - signature = bs58.encode(transaction.signatures[0]); - const serializedTransaction = transaction.serialize(); - await connection.sendRawTransaction(serializedTransaction, { - preflightCommitment: 'confirmed', - }); - - await connection.confirmTransaction( - { - signature, - blockhash, - lastValidBlockHeight, - }, - 'confirmed', - ); - - const transferToKey = lookupTableAddresses[0]; - const transferToAccount = await connection.getAccountInfo( - transferToKey, - {commitment: 'confirmed', dataSlice: {length: 0, offset: 0}}, - ); - expect(transferToAccount?.data.length).to.be.eq(0); - expect(transferToAccount?.lamports).to.be.eq(LAMPORTS_PER_SOL); - }); - - it('getTransaction (failure)', async () => { - await expect( - connection.getTransaction(signature, { - commitment: 'confirmed', - }), - ).to.be.rejectedWith( - 'failed to get transaction: Transaction version (0) is not supported', - ); - }); - - let transactionSlot: number; - it('getTransaction', async () => { - // fetch v0 transaction - const fetchedTransaction = await connection.getTransaction(signature, { - commitment: 'confirmed', - maxSupportedTransactionVersion: 0, - }); - if (fetchedTransaction === null) { - expect(fetchedTransaction).to.not.be.null; - return; - } - transactionSlot = fetchedTransaction.slot; - expect(fetchedTransaction.version).to.eq(0); - expect(fetchedTransaction.meta?.loadedAddresses).to.eql({ - readonly: [], - writable: [lookupTableAddresses[0]], - }); - expect(fetchedTransaction.meta?.computeUnitsConsumed).to.not.be - .undefined; - expect( - fetchedTransaction.transaction.message.addressTableLookups, - ).to.eql(addressTableLookups); - }); - - it('getParsedTransaction (failure)', async () => { - await expect( - connection.getParsedTransaction(signature, { - commitment: 'confirmed', - }), - ).to.be.rejectedWith( - 'failed to get transaction: Transaction version (0) is not supported', - ); - }); - - it('getParsedTransaction', async () => { - const parsedTransaction = await connection.getParsedTransaction( - signature, - { - commitment: 'confirmed', - maxSupportedTransactionVersion: 0, - }, - ); - expect(parsedTransaction).to.not.be.null; - expect(parsedTransaction?.version).to.eq(0); - // loaded addresses are not returned for parsed transactions - expect(parsedTransaction?.meta?.loadedAddresses).to.be.undefined; - expect(parsedTransaction?.meta?.computeUnitsConsumed).to.not.be - .undefined; - expect( - parsedTransaction?.transaction.message.addressTableLookups, - ).to.eql(addressTableLookups); - expect(parsedTransaction?.transaction.message.accountKeys).to.eql([ - { - pubkey: payer.publicKey, - signer: true, - writable: true, - source: 'transaction', - }, - { - pubkey: SystemProgram.programId, - signer: false, - writable: false, - source: 'transaction', - }, - { - pubkey: lookupTableAddresses[0], - signer: false, - writable: true, - source: 'lookupTable', - }, - ]); - }); - - it('getBlock (failure)', async () => { - await expect( - connection.getBlock(transactionSlot, { - maxSupportedTransactionVersion: undefined, - commitment: 'confirmed', - }), - ).to.be.rejectedWith( - 'failed to get confirmed block: Transaction version (0) is not supported', - ); - }); - - it('getBlock', async () => { - const block = await connection.getBlock(transactionSlot, { - maxSupportedTransactionVersion: 0, - commitment: 'confirmed', - }); - expect(block).to.not.be.null; - if (block === null) throw new Error(); // unreachable - - let foundTx = false; - for (const tx of block.transactions) { - if (tx.transaction.signatures[0] === signature) { - foundTx = true; - expect(tx.version).to.eq(0); - } - } - expect(foundTx).to.be.true; - }); - - it('getParsedBlock', async () => { - const block = await connection.getParsedBlock(transactionSlot, { - maxSupportedTransactionVersion: 0, - commitment: 'confirmed', - }); - expect(block).to.not.be.null; - if (block === null) throw new Error(); // unreachable - - let foundTx = false; - for (const tx of block.transactions) { - if (tx.transaction.signatures[0] === signature) { - foundTx = true; - expect(tx.version).to.eq(0); - } - } - expect(foundTx).to.be.true; - }); - }).timeout(5 * 1000); - } - - it('passes the commitment/encoding to the RPC when calling `onAccountChange`', () => { - const connection = new Connection(url); - const rpcRequestMethod = stub( - connection, - // @ts-expect-error This method is private, but none the less this spy will work. - '_makeSubscription', - ); - const mockCallback = () => {}; - connection.onAccountChange(PublicKey.default, mockCallback, { - commitment: 'processed', - encoding: 'base64+zstd', - }); - expect(rpcRequestMethod).to.have.been.calledWithExactly( - { - callback: mockCallback, - method: 'accountSubscribe', - unsubscribeMethod: 'accountUnsubscribe', - }, - [ - match.any, - match - .has('commitment', 'processed') - .and(match.has('encoding', 'base64+zstd')), - ], - ); - }); - it('passes the commitment to the RPC when the deprecated signature of `onAccountChange` is used', () => { - const connection = new Connection(url); - const rpcRequestMethod = stub( - connection, - // @ts-expect-error This method is private, but none the less this spy will work. - '_makeSubscription', - ); - const mockCallback = () => {}; - connection.onAccountChange(PublicKey.default, mockCallback, 'processed'); - expect(rpcRequestMethod).to.have.been.calledWithExactly( - { - callback: mockCallback, - method: 'accountSubscribe', - unsubscribeMethod: 'accountUnsubscribe', - }, - [match.any, match.has('commitment', 'processed')], - ); - }); - it('passes the commitment to the RPC when the deprecated signature of `onProgramAccountChange` is used', () => { - const connection = new Connection(url); - const rpcRequestMethod = stub( - connection, - // @ts-expect-error This method is private, but none the less this spy will work. - '_makeSubscription', - ); - const mockCallback = () => {}; - connection.onProgramAccountChange( - PublicKey.default, - mockCallback, - 'processed' /* commitment */, - ); - expect(rpcRequestMethod).to.have.been.calledWithExactly( - { - callback: mockCallback, - method: 'programSubscribe', - unsubscribeMethod: 'programUnsubscribe', - }, - [match.any, match.has('commitment', 'processed')], - ); - }); - it('passes the filters to the RPC when the deprecated signature of `onProgramAccountChange` is used', () => { - const connection = new Connection(url); - const rpcRequestMethod = stub( - connection, - // @ts-expect-error This method is private, but none the less this spy will work. - '_makeSubscription', - ); - const mockCallback = () => {}; - connection.onProgramAccountChange( - PublicKey.default, - mockCallback, - /* commitment */ undefined, - /* filters */ [{dataSize: 123}, {memcmp: {bytes: 'AAA', offset: 1}}], - ); - expect(rpcRequestMethod).to.have.been.calledWithExactly( - { - callback: mockCallback, - method: 'programSubscribe', - unsubscribeMethod: 'programUnsubscribe', - }, - [ - match.any, - match.has('filters', [ - {dataSize: 123}, - {memcmp: {encoding: 'base58', bytes: 'AAA', offset: 1}}, - ]), - ], - ); - }); - it('passes the commitment/encoding/filters to the RPC when calling `onProgramAccountChange`', () => { - const connection = new Connection(url); - const rpcRequestMethod = stub( - connection, - // @ts-expect-error This method is private, but none the less this spy will work. - '_makeSubscription', - ); - const mockCallback = () => {}; - connection.onProgramAccountChange(PublicKey.default, mockCallback, { - commitment: 'processed', - encoding: 'base64+zstd', - filters: [{dataSize: 123}], - }); - expect(rpcRequestMethod).to.have.been.calledWithExactly( - { - callback: mockCallback, - method: 'programSubscribe', - unsubscribeMethod: 'programUnsubscribe', - }, - [ - match.any, - match - .has('commitment', 'processed') - .and( - match - .has('encoding', 'base64+zstd') - .and(match.has('filters', [{dataSize: 123}])), - ), - ], - ); - }); -}); diff --git a/packages/library-legacy/test/epoch-schedule.test.ts b/packages/library-legacy/test/epoch-schedule.test.ts deleted file mode 100644 index 7ab0d02e9ebc..000000000000 --- a/packages/library-legacy/test/epoch-schedule.test.ts +++ /dev/null @@ -1,46 +0,0 @@ -import {expect} from 'chai'; - -import {EpochSchedule} from '../src'; - -describe('EpochSchedule', () => { - it('slot methods work', () => { - const firstNormalEpoch = 14; - const firstNormalSlot = 524_256; - const leaderScheduleSlotOffset = 432_000; - const slotsPerEpoch = 432_000; - const warmup = true; - - const epochSchedule = new EpochSchedule( - slotsPerEpoch, - leaderScheduleSlotOffset, - warmup, - firstNormalEpoch, - firstNormalSlot, - ); - - expect(epochSchedule.getEpoch(35)).to.be.equal(1); - expect(epochSchedule.getEpochAndSlotIndex(35)).to.be.eql([1, 3]); - - expect( - epochSchedule.getEpoch(firstNormalSlot + 3 * slotsPerEpoch + 12345), - ).to.be.equal(17); - expect( - epochSchedule.getEpochAndSlotIndex( - firstNormalSlot + 3 * slotsPerEpoch + 12345, - ), - ).to.be.eql([17, 12345]); - - expect(epochSchedule.getSlotsInEpoch(4)).to.be.equal(512); - expect(epochSchedule.getSlotsInEpoch(100)).to.be.equal(slotsPerEpoch); - - expect(epochSchedule.getFirstSlotInEpoch(2)).to.be.equal(96); - expect(epochSchedule.getLastSlotInEpoch(2)).to.be.equal(223); - - expect(epochSchedule.getFirstSlotInEpoch(16)).to.be.equal( - firstNormalSlot + 2 * slotsPerEpoch, - ); - expect(epochSchedule.getLastSlotInEpoch(16)).to.be.equal( - firstNormalSlot + 3 * slotsPerEpoch - 1, - ); - }); -}); diff --git a/packages/library-legacy/test/fixtures/noop-program/.gitignore b/packages/library-legacy/test/fixtures/noop-program/.gitignore deleted file mode 100644 index e13de17f65e9..000000000000 --- a/packages/library-legacy/test/fixtures/noop-program/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/target/ - -Cargo.lock diff --git a/packages/library-legacy/test/fixtures/noop-program/Cargo.toml b/packages/library-legacy/test/fixtures/noop-program/Cargo.toml deleted file mode 100644 index 91908dec94d2..000000000000 --- a/packages/library-legacy/test/fixtures/noop-program/Cargo.toml +++ /dev/null @@ -1,23 +0,0 @@ -[package] -name = "solana-sbf-rust-noop" -version = "1.8.0" -description = "Solana SBF noop program written in Rust" -authors = ["Solana Labs Maintainers "] -repository = "https://github.com/solana-labs/solana" -license = "Apache-2.0" -homepage = "https://solana.com/" -documentation = "https://docs.rs/solana-sbf-rust-noop" -edition = "2021" - -[dependencies] -num-derive = "0.3" -num-traits = "0.2" -solana-program = "1.4.16" -thiserror = "1.0" - -[workspace] -members = [] - -[lib] -name = "solana_sbf_rust_noop" -crate-type = ["cdylib"] diff --git a/packages/library-legacy/test/fixtures/noop-program/build.sh b/packages/library-legacy/test/fixtures/noop-program/build.sh deleted file mode 100755 index 9c1960ddac5c..000000000000 --- a/packages/library-legacy/test/fixtures/noop-program/build.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env bash -set -ex - -cd "$(dirname "$0")" - -cargo build-bpf -cp ./target/deploy/solana_sbf_rust_noop.so . diff --git a/packages/library-legacy/test/fixtures/noop-program/solana_sbf_rust_noop.so b/packages/library-legacy/test/fixtures/noop-program/solana_sbf_rust_noop.so deleted file mode 100755 index cde65c43a7f2033a2557dd3012ab2c7fdb323149..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 52328 zcmeHw3w%_^b@#oyd$lVe&;u5PjI1l3GWNm>gd}8R<2Ml3$adBuj%~CE@vs3sF2iB5Vn440cz7p%XLQWp9zL#Ew`Gi z2>ljXF@@_;maFm2cT2aWc;75(mpgC~N3N&NpLgnx-eQt}jH% zs4uC@nej1QOyZb^AJ_45A`qtMObrtR44Ro5#smzRGBsR4%4N$L&K}}8N=TL8 zWd4?(y+cDI$jMY5RIzvHoQ4M&K03_t;8~8JKg02Jr&U}*G<@CBBlwt1G3Zk@BiS?o z8eUBT0DrRRoYH|`tMe896Tr5t>;WC`)^RV#-m}aX=>IvD1-;>C9@C{PtG)6wiZ4^% z>|rh+r81wPijEU6Xh+a_&qU~f0coM3qmvD}%;V@&^urbl#+5k2s+!;tH8 zLaCri&VGh*@moR08VkUv|Gi`wqA$;=$2+XsXFl_hnSV;vp9)>4_)qKhtsp*vddP0% zI;$2DV-y_g1{Fi!BDd1_A(d>wE+7Z^c#&f75XH>{s(yimpLobt_U%~L zD1y*OpP>(8QOQ|M5AhhR#Ioj*`6emOKA=D=O1dBxh+pnNUYgTAT|e3ne2bl@LQ#d_ zm2*GHC@WuYlS045;R{2dAS$@3w9}JX-9ZSHYx0oUHBdedEksc4TpxJs( z%U;iMH8+BB=ob={d~8lu1qO$H&QbE|F)=%p)5MQfU(2vBADKT$Celp!IClr@ zIOtJGp<`1JIuC<5g|!VFgP%P4(nTu6~mZm{tEq8^bUGSO>Y6|J9A%b7?{w*iaa`{e)_(=bW5cN`!(dwKC9~^ zF;u_(B*W5g&`*POAkQ5ny66G+%HYK#rvW zd4hJgA}E)(yNi+MSJc;o?c?V0os;KOUiw>?CrAhKR0rhA&gJ&>c$l@so`81+xqy`R z3c>V*N{97g{9&(Q+BeGo{v_nHBN{7zx5_62p)gi{E76dCaXvn$jl*ZfMe_Od1^C>0 z0Y0w_@;OV1V|m)2%X~y&=%tYO61jruE2xi2x@srte?hp>fEx_>eKZyczQp41vo*{Y zh5@vk_@6{Mw$ra5Gaj9y5d8kQoAJTNXNm8)Rjd*miw#`#knPLiVOJipfcV=Q}Z&$Cx<*KzHY_y(tOn~Z@1^coJ@#URhuGxznYdgC#278J6(RAfp2 zLAea<=!mv^ZO5X&vG89f6{8##8_9MtJt^<&t&;mirf7)ere*`b-XYe5^pCh*qX-<= z`B~i_Sf?OBPY8~+P{rbZ<`EA`O37+{mgsqU?;Z0MUT^zl9A96nV(-uZ_mj!4f-}7p z9Pc4PD0qi>9+sKR?Jw)qjHa7D^lMeVeKJfAE{6Dn9=JX-`)+ry2(}%GOJj=xP7GsM*Q^*wM)}y6^iV)H1szo7E-a$k+}OtZtres@0DCG^VBic&-)qn zR%ku#)pT{c%!$~Fu4Db2@$b|2u!8Zj@8nq4e^?KJpA?ltko6Jl6)E2HEMH2mE5(jW z^f=eu&35XKKYHBqx?PZ?bq3q3w?nt{A#Ue;%AZmE1^vtr^~21A`#8N-6{mUOeui&i z7k~PIJf2RI>iM z^*U1ax!@mMB7y#m76xBGe1rJX{XT_`gnW(X(9BU_#F=T_e#oc)2?iC!D)Q%@n4h5O zGSjsF(k%)hQ^|6pd@ZE}`S=d_U~*Q9>848tx@=5cdV~Wg-faAm!_*o`LVTBQ7iegbFeGJKZxHFeS5zBazl@@-@CZK zz#d+tcJMyQu<$4LX!?J#*R0l?_>bOqa{m%P-aCc;gZTMg?f1MxTD~c+5=`1RGlk{P z>}7k)^lAO+{$u)k$GT4Slb}6e%`E;Yvuc?8QS(_9XGwPmS*_1_OxwBc2eOX|{|!#C zpF?U^Whr{d(FX`#+yxnbKI@O0+%5g_Q}_T+*3+tp`T;(wlzi_1=LsC8OcVhhNyMZE z%wyxRYZM~r9S*EtL2m-(NO|-hgz@;wYX2knp!bdQ(CdDj+v7rXgY^E!pogv~`Q8C; z4}nqts|G%1PLl5(;CA%NnUBO=7SK`Jq4t~wX-Q9{f8=E97|)xm`_mGYojZ5o;^XQ^ z>IGjvH28`WDarQ^oKv=ukFX$g$iI9G53FzV?g8d4wV z#0)x+RPw#&w4U@iPrLwDL3W_+TjrG|-74AYhA%Rp*zNbhAE5KVSU8039hW z>y_+m%A`gy48F<~lmC9{`S^pQWhRKZhHCJ$<*vhh52f zS=PU@{u4b)KIjL_`TCv3a!UXA^{da#-n4!jwSF6!?tdlyPP|C{Cf}ldgXP}N{fZ}F zzqtL1Clnq#xQp4Z_>jWq_LcRv*qzwTf7E^j{Lxc}KPsbk!M=Kz;rHg#7#{R5!SNF5 z8R9#bzs~SuodH<(Tg7k4{+-ues|?yptBCxA_AlB$Z6qfNKN*kE#DfCn!3c8h6(y!n z!ds(~tr9M7A)Q#Xu-+afK4f1f75SAKC*om9O?35snpegJQ#NYjde9=$Pcd%+y~J+b zAj|Fs7WvPa9Q$|#s&b@H#EDw`5*;{o3bG$6^S)G=_rGL*FLdHDmRH6{)DKF~_f4dC zNl)qhD}jS}Ukm78=3SY2kb>Gy)=PRE&OCUE=LttuwuNz3`ByzI2hW+3gaST(NCREa zALBd+=a(k~c9iX9dcgkZk5z<+^hBE zuLtHbJz5Va1kr!{{NE@&E0|0!QLguUba|6ME@u-SF-*a+*#26neXb$+W{UeM?tSnL zZohH@DC{7ez_M^@#@IOZKjh8RynHO_z*?uwpBf#hF)PQ60L+tqDkmQ@=4fy^h zEj_YiCkWziQ#SWMZ(XfQ_tLJ4F&>@^_@hiSuVciI`}5Xj-X{b8aKJBRnoo0oqI6W5 zX+EQ1)9-<=Mv}|qE3VI@L>~BKSc3FN@y96tMMEwK5Vv_9C~`U$uaB_C`|cGphJo`& zY$vWO*~S9`wF4{Q0i}dVu^`!F`zip+8A^)88H^p{b}P>-vpkwl2Xtbll+- zS~Ub?->Z+}xbs=McZoP+VVxbP`!f?Mmh)cVVQTMKgY?Vgwkh~I1;?Gct(o)`cLuC^ zDqgGRuKbbnhr3psQ*p^jtp&&3n~A(ndAF5>(hL>H{D)%bD`QT7>;54j~B z?Oj3vr4g^i;6(xHHU&H*UZ~SCzBN%A<_FlP2Oh==;2}tPv?sBu#&7U*lzvFHWcMrS zm+gKg#n~kav|6ELvVgdASkaRGY4jJYOJ)9n`hNFWE`#5oeJ-TDpnbXu9^XETkL2jU zKH)K7pLYk+VV|#2haPR8NmbafKF$76k7KP==g>$s`K`f`q31$=KaEoQ%PU?VG3^)q z5PC_Jv)t0JLFWxc=b4d9Pvq0Nw{C1YGz<})-^=3%^;S7-GGdBMB zsf`llA0CDOhd=twm~#E$zZ4Pv!wTQmU$0V|wUPAg(j)8~vGn^n;awv?wkJ`0!%Eps z(Dm}{gk*|4_b9rVx#)#-ulXj%Z|7+xos**%2K+h(3<};{m*aV8ZG!taL*`59k9E(e zEcFAszr2nWpcn81K7Rhv%Rd74rO*HLz4w&zK|toIgQ}g7Un+wv;rw^d2ktedEEghK z-YzY-_Ji<$Qz%{TOTccfd8?ZXvx@gWGpqFck{j4joT~8Pp~~;-={yKNUNV*JFp&t<#3Ny`g1V-7^Mg01FJdt^7VrHl6m}b zJxI@M7kzIySP%38x)TEXUYX`5t^Xv)tCp+SyPe0+%={G$-^ueo?{=OSVw^%o+`d%F z9k*T8&fw$spHWHbCsWy?%0u56?=qEZm|hLz$h`r_s#XcvqnwWQLL2m=$5;5{BxQmB zKOn~(lxx4z>#$!BD2Sd>FHAGnE@u=T_}rhT$J2iLxs{;6LDqwr2iZ<#{{rP-dPcA? zPk}YDKm1}KJt#lhn<@XRs$TFJ?8k3jzMNdA$B-*XZ@JRfF<;(_$8vH=KN!nTCsnxt zzg(XG((g$H>uFK=`xSmL{WPTq*MCO{&e{7xg)isrnN@=f>w5q}IBwKjYui zDkDM^d^>-H?ZF|-L@0SuMOO6_91Go40SQ7u{JXs8CikLJ_CA%5{)Zs#275(~iJBy* z>wYTtFR~aUDPaE^{l1lAoZD9Gbd*O(MYyxcd7kWdC$6nm`I!f`Ubicd_90lGB}*92 zws2g+;#;16PbsVCFBMdI5d~l&e!*jWtfxlac;gK~6unV`LpBOWX}Uvfj;uY%utxXC zLn-g$6Pm)`&-knRIR^cH3V;x=Wi`>fg8c;M=U{o+lpiSj@CLcPyrV3ycZB6!ruSDt zul5+Iae&<{p$$dpH@L5ZkloC2Jaj$7M!U#3E$0s&gj^G))*YGf>aMc;Do5&Z5n_3w%0M8RQmvDXW?5 zllqPF;Q!yAQ7Gz1_!WBI5!Q#?zZ3p)^cOJw#Vn7Ucc47_F}oy+#ztKa`H-?udN=xKXFJ-;^E8|@_RE$x+S-=8WyIo6-4*gK@{ zLEn=Lo~xZCImAw+{ZrOI>2j=BPv6&+_w2#X8wNj=pR%WMxn`CV{1pvw8T`g0;Ew%4UccA% zqyK=9>r-dUhr+FRwLD6&XQ@X!)yQ;jW>0fkz)%y2(mkx+>?IO_RQUu?z{1L)B6O= z3qJr=XQr|q%>In_L1=I0^Lx3!YVJ2<-q%lfiF%&zsCgifOw@D7IbS(&AoDnxAGMOv zUPJV7?hm@X^YuLjJ#X7V>DWg`{*cON{&o<*nDMnztjbf|kNjqRkAYzNpXO`W?aJLJ zfSk~Sf4^at${v>v>PJ1O|0Kn7F9CEYiRhHkFY!S@z8rkEBl}XIQ%-oGGfc723Fa$# zM$yst8>l|$;e7H^(^x_K!ub;XdlmWj$0-j%_G9F%@_g@ocTyJ*jw5ov=Tu-k3*I}p zm*`79!TSOe1NBQf^oQ_2_LgtA|3BEvf^5cjUcP{@A-A_V*Flx4wT--<4n80m+tKvX1@0FJTtE6KjOy#^SClu z*JsQ}*Nvyo8x+3C4SGz6jF1A><7iLW-;?*6yc^NFG*6^|L-W+5`nkt}HS&BAbi8X7 z=zl*z`eCM7+uJUl_j-HJDEZ=%TzQlP%=}>V${fjCFJ@t$Eg{Dt1p2Y8XEqsm?5AlRg=H=W^%B=Ks z^b)cgyct^Q@$Kvm8>1&$SMyeJn zd|AiBe@E=6YF`R4fUE;0-&6OFu)maXM%Lx6y8UI}TkJnw&g;?4{G1)2Y1{Sw zx#&gi69|98S8q4#4R)5Haw&`VA>=(FDgWm6%IzAruZ6g@54G$f^~&WOy`LujMEtd! z$B5ly{6xD5zd3!J({@#>>i4F)Di*m>4)*PT*JKap%e@xwFqhAb->)co4xK)MkkFBH zuDJc@lwRiZ;T`7o@ZZhMX`+TT!hcumv ze0ja+*}mm_k5wKSFzUI0yfRM2wY-3#FPRUD{E6xOJxIU^j`b<#3yng--@nuS=|8W% z_#WH%?e#eEN$vHP_0RX%uup>^_UD=U*XJEo2N>~!dM7lf&euD^(7T+QBo4fn?M2#K zf5)e{hWoMDo%Dal`acRkdy`_*$~Nk_LdP{6V_xCX;|?9iZ8Rw9XBSdoFWRmaGc5gL z^!W-8L^5v6_wmGE`Sf;cdfNYqUy^mS_&;esZwhrB@DW!L-QVNyUgYLw9V#R4f45?V zf-`sN{>sCcKYz^V_s-?KP2NYAb8tELh=-X^IZyKj**}TBi$AJb$>T@%AoGX$IjPd> z-p{biH?S^2OTDb)j)DsASAlZSAjaz~A4OdcORzrlE2rrwi+ zyw$p)OWuca#9!}smHkz%;QgWQy`1jzf8BK|p?fz<=k|{piD2bLYgYMuO}{yvV_V|N_Z!Q+dH75`MPQ_l05cdBfv zN4NW(44Za^{)c)y3SQ&+7Nb$QAF1|`?<9C-Y~QlKn!Sw?rT>ZD!ahLH+%K*E0OPk3 zpJ<89Q#`MYM|k}gkMQ??vrjVK4st6>AKK5!{7TBnd!jO*_MX%0NBy1TxO1f@@ zB5L22Qp9gmbu_AcNA)u9CrHT5XTF3F8Q;(=?MSn%@fq4VlpWhCcJW}xO)0h{gtiMq0 z2>uk_Q7vCL!&MvE&V0HT;4`ZEitGCrfFZBUheQvFX|zi)5UX`E$x@ zR07GoHXh>-W{93Mj|?jQ<$XH24=(s}FE_hMvE%p0Tt3eOGmq@&c475d-P|25+2=Fc zqa$=Vw>R851++g}qU=fE%Wy?vhQbnZ;;!^JHq`s9)3+_B$^;C(P6h_Rqgqq zf*tGcRg8L|Nxz;&Dw)1Zbz%fhnIc}#2G1GJQvb-zA5i)5hxj5F)(?y6Lm6r97dr}g zzs)WhhUTwKPdZ7ar^H_ zP|o|LZjS+Ok3@1UrBZ$BmJ-wI*xS{<$|u%e}jVkaZ9h0rM#>!<=&$B&y=-Tm2)h% z(|C9a+f{ff+ZFKxJ<9u?@?IPK5-gyVer8ZC-w}IgmLjM81ZHB;LlQ9&!H%<>&mtXT zNQv&RGVjB>5BiMTeD4A<>Onsza~W~0e^l)*>7axC72zN0&@a-rQ!Mg}-W}`jRC(V{ zwO<*}PCM*leBWyq5d%H#C&gdOcOh}#>s;X668v?vSvp2psbYZ*tDwii&pl|3C z8?A{N^d5rgpR!A&lg1M@>OrLgqXeCVLZ*oQtz#`>J56)C+}rLhXV{!)$oSYn`|eq? zH<|Z{Kg{msae_AU7mSk;Nd0eZyX7 z5^VY(+2_a-9|-lFV8!z0JN+%e-{xg~uD-w-$XM9pjDo3CF^|HN)Ur%85S5Yd7)x=6Qs)Bj_l_C3V`Rc=Vh6{M%$Thj9>__H68KNG+H+mNsAZIib-vdt6!JCo4;o;Zv|4z^pl}z)j4)u_o!!W*MMnjg` zH=yc9s&%@Wzfd~f&%*mrz(x%Jg5X%oR4nJ#CEA~Mx2a?+URY%f(PO-@#`+hE<$KQ9 zho~mFm0}n$#z(Al6C0Ut$6^L#{wnV|V;`c4@LtxjjH?}mU*P#Q(E)`yG^5IbuI5M1 z5u#L1`C-CCShn;<6=z))Sta{9MmgZ=<)pQdo>jd%_UpAirRG_Vbwm{uezB$*qJM%H zr+MxG!H)GT{W4$R^TKjHohKK@l>sW3DCGM9j`b8lIeM*>{{~>Khg9Jc7IsiBT+e|~ z^_-+~iNbFw|Kg~d>_o?_tra2^-4R=4rP+Afa$_w@*^l#&vA`MtMgO?(bu(i^W`x7u94oG&Hz zoKy14KCgUVSML91W-(vVPv|`=#Za#Nx3&J5A53Q-KEyoZSL{vriPK*nL|2Z}J$1EC zAUlMe`0YufzOvsj>{{?ZH}O$Gus5Ff`tt8r$*NxfL+Ul#P3r5Q)ATI)1IM~q74-X4 zKhr_m1?ydwT%j_?_XlycuNW`9#QHg5N`FDWL`%Vbp)jd`PT|!`-V59B(sAsUC!UVA zMDcYY{uAL1y1f?q_>d2BqGe&PLH^Jmla!VyWV?~~f<&$h^F1?UxhJxcV(;xo^0 zB`+Z?>UZ;0WR-wH3Mi-i7MtOD{MKaEu6{iq;PPk(Wp|q1vZcJAHJ1GV@51&|py~l# z=uysD&G96$r%&tsF%?UH@{Vx->zzDJF?j#vxQg4`%T(OkTdLyBo?JgfJsG_pFYCz6 zswPD@)0|W>zHc7<4g>5B;W+)nSCz7tDbPx|#5e_{Lja6>Co$e~va(YeI;o#w^rCT+ z=stW{J*pp&C3JdUiuubtwSxJmT+Z=>YdF5IMa79(Y_EygEN9|+p2*4mr>q+mk7dx&AoQ!p>h=OI+jX(>RF)Z$~|)Pef91eRJJ;YQvHCGj<_QdVgEzMMb(X9 zpBzE{?uyuX)vTE+-QQo+a%5Rdb^fO460GQk*l&01@1?d<`ZYvB`ip;lcatKk_Gd|C zYxP`)=a4h`9z8nNDwQDTd)-sH!d5~CJ-II;-#gz({TH4_#@E#ksN%{G4bx*Hx?Cmr z^vbv+x02Y3UOD5BIbp_SGn|KCtebIHNoKxvzeea$7Pp;qTSAA7Q zWA!)q1-VCydfGM$SKyobRZ!k73jgB$PMg9%HcD^(lrHBGXonvM+5!F)`ftBaw+FRb zKf#H0`d$NN!qU*5YJYm2-ruHlSd2<13W;?ut9n5Xe$3JLD&_Bpc(?KQhGhT3yHnp6 z56>rTI+q|~;6v^S=j?#>@2yeO!MuG$i)zHaBt}d%?oyo5->=F%a#ryp-=9m=@p-JQ zD`cKtRbEM@XnryewNw2tA_^tjIqt6EI7;$E1yy>z>{!20^b;+7u$_3{)e5l$!c&mH z2Pb^__cjl3KKdC5bgy6-_maTDJryi(D?J02d5O>Wvutmk-dE1a0c_~~|0=#vFH+>b zV%%na<^3T^m-iP0U(KtDg7`amZy?Ld1FL!^YN7U`d5uf)%R1irQ9ge=N@=LKYVHpd zAK4B9C}7_J>D}uUXvudxu#8v!QpZ~-0}FEeM3uj14mmOk=r3dW7ko!$f1rQEzB>Z; z4gdNOm4_dLoygyPTCMjtu)lzIm3#C4`NHj#NCEVB8uU-l`(!eok$YP5Ud34W`2N1& zi(cjaB>D?RN=Mz2BfHb~mmNUuyq-Y+m2tAS1=3JD@kPlaazA4Sl_L?YIrLq6tdD~G zKK%q^-)9%ai77n)M88Ek_&xRlJ?H>F*9Z8Ozb}?u&Iqte(8qpJlH!D%yAq5%$I|Uy zM*xL~xjD(daeoi`Hzk+G!@RGb@H3UVpMMgibN&GQf)x0z9Y78T$c6R;-!IU84Cycb z9rWDz7WLdn^1hvV-W||$dKRpJ+NoYe>bp?X6!aY^{E|&jd$|a5OW}zfbnE_} z>u)?y96z7=f2;iw_o~2<^q(Ch7yWO|ahwbE&l<(ILpwVN#5;5=uh+Z zH%MLtw3l;H{haq5T1hW1mCN;Wz9)qK1%CYZ?1_FUB_yT*oBKUtU*E((^5uJG^T-|) zyc}4h_ZE(2o~HU4S$-qopmj-#?fW`Toer&@UXo&`XECn*AT? z1%7Yq6i|i#TB~AzoPSn<>i+uq?8C9vDMayWqvsh|mF4t4I-mFP-l`wjLGqI*G!MC0 zKgWhGesX;O!23_fi9Y)~-hcY{^LZivcH#Nb)j|LEPNm-S_-%bpjpSfI_x8+}9Q}P8 z>36NvXs~PF-`&V^p#QC>$LiY{R{jq5Pi8u%{qwM;=BMqmOg7YF>kWo-X5r<0Q}9?fmc55 z!>+?)*!6#%m{<{Iyr(g6-V>(ZKiPJ~61W z)DPxYG&K6(?Gt}5{Q>jm8Do5B3h7S-)AjkI{JlT_{RHh#aKDpWMQ$Gui)0G&ce%Q| z8IIF;Q86BSX;&qf-!;H@{klG(veXaw2VJ2r@9BBzS}rf&Elj%#M)~#UDc@Vf`{$Ya zcz+V>5QN@J-p7;ub9vt{^C0hY2FK+g%oh%GIqbLMei8P2_P@Ys_=W!d_7`;TR{oB! z{`=i=8@D`Z{=ZH|{(XT|i0_MdN13mb&2O}HA7Z}bdy3}w5##!PhyVS;9<7&vJroac zUHFAQA+qRG-q)1(Z^om8b9I!1ekTmjgAOJ=+zUb$&U^51oc^JleD51D0_K!R7kiZN z^qAjyk@*(%d1Jt@o8PID@4}4ty(;jTr20VTOBBofZD|L&KaBj((7x;_zVy84eEih~ z_>+4Ka=z_#8}{1m5*Mt`!$yClt!lr0V4q5V>X-BhfP#FVT+S&n_h~yl%K5Ng+yf7; z*I}n3H`?*jM!nb}!MXVG=a~k6p$~`b80*m(!G1l@G7ioIOuBz$(1kqee*TMG2EU;D ztDjT<7~uYxv-7w@lKpMper!JIll|*-O;X`uo)7;c^d1?p?`!4!IZ8O6CGiQ&HYWK)bjECl;|i$bO!r!@r*~`o%Rr%k39# zq45_L165@u*7JAXOWKe+hM%wDbm$fB3pq|2dYux`tDLh2+hNeapA^JrHTnDeun(%j z-@lwkO#U16TE~3Mu`BqT2+UJ}{@~{lOVA5){#NvwZBxmX{M`rf^Cipswn5?xf0cqiYRd`}(Im+z{}{8Rcx3A;f{{ysvl-md{Y(Ahef{k{DC7kQ5Yeie2j zd_K->SPQS`hlRR5TUaF>Ob7l7`Oq(7@e_h)+Q~v~ z$FgrG^@*LxJY)ye1A0==!dV1R5P#&CWA|@~J&Qexy=HEM)^p`depfG7*;dBpSoGA= z)48!Hz17{kzGGY8<_()WdYZ3oZ|~f`t(hPd=H8z6gBuOnQXth~x?K-coqt`{aqjPJAd(|>`_?gF^xV3XzhaC#H zr?+hBSnsyo-qE{#OJ8&I_H8?Q(p|NewYgMBdYjvJV^2?;`#^fj_72U?%557uQDd69 zTf3QHsv1eed5_oCxp`Y3B_!OHy>9R3joUhU67D-Xyo7s8dTUo_PaoxoWMJRj(y?u0 z-=>7SdIzCeD+4kj`!aXOrjBiH@0QK&o40Lr+j`R5Hg>ojN*n7tcDm^;Jss)wp1XB> zUwYjZ&t2Eq)6==5V?FWR+0*Q9?bzDc;}O=D&i1rY+=ldKlK2X@lhoI_K_ig*deS}K zLWQ>wvh<{PtbL%Podju5cct4m_jzvT106jZwsh`DyBj)twx;{~z))XLdUKz6J9t0Y*mC->?-*vaAIQu2UQH*ZjAK`Ln9)X`hBY}vAOZ*NCWK)uawTkV#P4SlZLvw7pD zzRTK*T&ib7AEmclQN)ROrhm<@n<=`Y=n9J5_qgw=EvmiZvQe^tmu=g(5*x{#$z-xF zxhT0fS)W{zY)CdHo03cGl67@;i|Q8F)z>YlYp83iYpPqiD7mO^(V|6*7u7FXvZ!HE z*DYQ|e@?W1@sh<2iyId=EnZrmtgowIRKK{szJ5u4Lw#d?Q~lB<$t875 z7A;x4q<+bgB@Ig&mozO|+K_ChYgp8Y5fcEpDoBTGG_e)Y#P2v~(%4xRk12N~D)kv89wWrjT1Z*OQQJ>)5z?8$2oeP%V1Tw$45`?Y3`9 z_mBsozD3UDN*9iymk9NeQ+F>@B}X;EcIw5Q>pK>9^^n^n57t4AVA)~EDJTd<3u4j2 zvZ5IirWaREES)s5BvKkKFP~gE)t(lqu&0MBqnFq-Le*2<@a5segavjoTo+no9}PVp z`c&l8v0sIL?Ytg(BRo?0*`3}8KYTdZy5@r)+CSrOCzZV8mS6v7!NP0qzGvz z2OfL=^I!bZSHAkSKl{6Xpl<<0%E~XRt8Z++a@opN_w4-$W&Xhzzx35V`}!;Y@Q+qx z;v|*ZeC3Tdtz32Q`i{K^KK_ZXef^b*WtUOX%GP(^eec@!9UngMJQexM*S_};|2RCc z?8cSrJNoy&_|liN-~86_Pxid;gU>$q#>TR7fs@A^ey`OvGp)b8Ob=sxX zH{E>e>NR)WeeZi8`opjM)i?iU_$R;U>3y_s`xA2)EIj(c@$Ad5eCvBpEr0T0^3m$Q z{Hw2z+`9U%cSmC-rSlfP_Tz1xjmxgN?#BHG?%25f)Yndbxl+#IQzv)0`jxo=MYDQEYwaAm>n*Te6M zPA#k`oKifc_`ZUog35w-MK5=5D!L+49I?Z76RwC<7EB2De}=La*8NVn|Jm48;gaxG z(Wcnt&hC-2irB)kM7XA;rlkKvk=;*DpAg^oF=wH3Wi&LYqOkwVGy97B|GKi+=^t_W zzgPUzPlOu_cilau|3s|+&z+)*E5k(vO|hF|#RYv6E)Cxmc~@coo{AYoQwwj2^gmMY z>1T_lMd}Vkc711VwAgX_pDW$U3+FQD8HNBX}Uz9d{S(JHWQ5-#LKqoG)=FjVAB z2u+HV+GU|~XL8vTJ06-Anm%!cQx%(S-xs+*^g{Th&?}*Dg#N1dn}vTJ`c~*W_K@>x z=m(Lrq1W8u$hi<1s$D$q%Byc({pizAKa=_3N1r(S;uqil`GRO+!?LUI{MqSmM5a_U zG~U_z(5F84!XGagDu4I`A9>ohL>S_&tJinj{YS?ynGuZ@O_(yRVQKT=^Jl(Y*tq|| zV6^DUt2b zw&#xipT8K0POqFf=jv;I@S`7(eC4YVch;P_wTqjYSFF0F<&M;yFuJz(jt%$s?tITf zk39RS7ml4g{ka#mb$;~TnHeV>p_g95_QD1IyQ{)=B{L$k3omspcW#JGn&1Dag4vPT zk=j`Ogj=uQ)mS*SC{}UhjZ4GrvBKn3rzU)fV=r%tyu(=-DT)?Gm%H;K#f1&wW~VY5 zDUP^2ZpISM0#*}G=w^9W+Oq?DqDp(PlSGaw`HP_BBxY8*q zxUIl;O2bb72iIM?B39J@+`ThzoKRFSadLA(QNtCHY5iZgYW*F>D+-Hly77_~u{$QN z+!ej4s49H(%Es`dSW&^!Xwj~Q>HWv;l0_5ue0;<93H|^3kz3j)?p^rkH+J8A=nK1- zM(0QFE|^<%Q&FumdH1n*cf2FAG+MSCHt^)R*xtXMUwHTjyA~(HWs%sf4}BnVzcVph z7%hFQ?dHP1tNQ=7s5jOXzp4MJDaEaY)B7LZb#wTA*OkQgwp91OdU^jh6XD88XxH-U zvS!ELJJkQn%WjDjMM8VZZn$Mx|DRk{U`JBUCH0|Qldg!YFTS&=|8q@M6R(IAlHC{d zKegu!2|Y2~SNyIh^`esEND~QD8=HCSu6GvGM>4|E!m98Dr=X~)AVyxb|Igf6wy9@L1rc6-;_zD_l{TT3IbTI}tKxYhxu&AMmufK@)ttuA)k zs(*aNz~%Fk?iHQS4P6l$Y)f4F>$U~f8*anXBW(?@+pjj*MKz7HC%)SF=}GCO3o8yS zP0o1r=AT_!bIb63udZI*S<~`~mkza9ucUA5_{O2ztnbv^ZVkP9NAlHl>T};ebm!@_ zuioie+ggY1kyd)CDoU3PZ97E&*()X_j?A(zz2w~!nhOi1> zd{u0Ih3z&{fk=#;PP8agWjCXEBt|Gjp-MXxT1uTf5+WyOUm6PA697AeU{486B^N;0 zL_20j!$qM>?JKElF_o+(@UrHLoM`KPZH6d9&+p_LzU$d z?YXh(6BdM%BwHvn&%T~C9|{$dTnp{RL^Tw0NbdQenEe{mhK~%Dmf{md_V?|_>7!C4 zWu!J7u|G-lt5Jr-b_(kITqEpS^8<6AOge!JC@lcL;kf6q>MS<2_#f5zWL{Ws{pDhxi&@@9Qs zB6_-uDS~T=Ua-AhrF_{B1cFKL2b4dDSy6sh`g<@Pw~ZP!&h|mlrG9<~#qu0XZ>4n6 zK`3`MnrGo|J*;|vSPz0^?tVaN@@RJjf`{x)1h`m5d93j z$gpQ5cuR&rEXRLJie9#$=GB(}^ zLO|P$gW92q|t=`TpYqxZ6Tx+Fi7q-u8-`?BTxpl4DsPyw1>eu?u zUE9~u-nIgJJNnl0uBn=Ht2As~c6n>5VhSgnYKBFDA;5X?9 zfm;l?R8JNpe~kfm8Sn`MK4ZYO+JJ=Kas%FHz{d>uoB@|=gB5yf40xaJ0Fv+Oflc5p z13qcMrF`Ac_bbZ{_>2L&dJ-b^n+$k`0dF$kQtgDKe60aD8Sp*>uBgekhok}T)Q()} zA2Z-n27JbVPtX{LAmx|W=EGeEyy7w=e||oE!hla3aA_hRe~kfmnJ@-;3c}wB19p@7 z`KJsxS(l$bXuv}TynInU{y_uYxi~+6(17*l&3%58a8ML{{tdWoNq+uL10FEo69(L* z2Q#6+$$$q8c#WP@34WIW4;XN1b3T7VSLMT9%kp7Y4~jznm;s+M;CfSY#a z<8LzH69zo=U_SoNOg=nlz(WRH`n&n~%T4&9{QNZre8Paw8t}pX{PHVy<-^wQeE66F zFW-}&e|B#^y#Iaq@L2;s`2PI-frs1Nr$oAIXQ$7;w`E^Yc#|@W6-i^UoOY zu@C3xmwqH49yH*ckLKqeGvIyu^YhOdaQ}h){F4UU|Co_)z)c^`&p&Oz?#J@;yB^Pn z&l<4xM1KBq172gmXAHRX$^7y|2E6lNetyO8<-^Mjc+h~mp327`FyPo{^7CB-ZZhB% z2Ha-AI}LcB0S_4PpaGvW;8O-XWWZ+)*!pa~JTU`y4Ya&h2AnkD6$ad5z-7ExeJt=k13qKGwUznw))?@x0r%_mu+Tp>Bfoqsz#ks>=?yC2 z13qQIF}=Yh`KR@MgunxMpdfIU-aiod?4$2RFyuTtJ zzb&8-$k!6k2jG4KK4!ot4S2|a&l>Qs0iQGA7@c(>h`ddDLsH-_13p-tkAK>LSJdR^ zuQA|F2E5aN_Ze_(RzAI913s(wFNEJ=19lhZm$&r#TkzWqc(@@Sf4DIpu5HeT_v!Vo z&}-7`TY+o!`cL4~di^Kx;1+}4)_i!=wtQG!bf+XKAJgj}f%pGzK7N;8zexUR1Gf6} z@sAmBgz^>-Sirv^|Fi)Q z1^O5AR|Lw#buDnKs==R=G5GNfWXV? z0Y%CsfzDb~&@ug4qP!sElO!S=<>9jsVlwa6ajh`M+5Ucn2G!sA28xtV>TykCJ SStruct { - SStruct { x: 1, y: 2, z: 3 } -} - -solana_program::entrypoint!(process_instruction); -fn process_instruction( - program_id: &Pubkey, - accounts: &[AccountInfo], - instruction_data: &[u8], -) -> ProgramResult { - msg!("Program identifier:"); - program_id.log(); - - // Log the provided account keys and instruction input data. In the case of - // the no-op program, no account keys or input data are expected but real - // programs will have specific requirements so they can do their work. - msg!("Account keys and instruction input data:"); - sol_log_params(accounts, instruction_data); - - { - // Test - use std methods, unwrap - - // valid bytes, in a stack-allocated array - let sparkle_heart = [240, 159, 146, 150]; - let result_str = std::str::from_utf8(&sparkle_heart).unwrap(); - assert_eq!(4, result_str.len()); - assert_eq!("💖", result_str); - msg!(result_str); - } - - { - // Test - struct return - - let s = return_sstruct(); - assert_eq!(s.x + s.y + s.z, 6); - } - - { - // Test - arch config - #[cfg(not(target_os = "solana"))] - panic!(); - } - - { - // return data in simulate transaction - let return_data: &[u8] = &[1, 2, 3]; - set_return_data(return_data); - } - - Ok(()) -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_return_sstruct() { - assert_eq!(SStruct { x: 1, y: 2, z: 3 }, return_sstruct()); - } -} diff --git a/packages/library-legacy/test/guarded-array-utils.test.ts b/packages/library-legacy/test/guarded-array-utils.test.ts deleted file mode 100644 index 06afec819a16..000000000000 --- a/packages/library-legacy/test/guarded-array-utils.test.ts +++ /dev/null @@ -1,52 +0,0 @@ -import {expect} from 'chai'; -import {spy} from 'sinon'; - -import {guardedShift, guardedSplice} from '../src/utils/guarded-array-utils'; - -describe('guardedShift', () => { - it('delegates to Array#shift', () => { - const arr = [1, 2, 3]; - const shiftSpy = spy(arr, 'shift'); - const result = guardedShift(arr); - expect(shiftSpy).is.calledWithExactly(); - expect(result).to.eq(shiftSpy.returnValues[0]); - }); - it('throws when the array is zero-length', () => { - const arr: number[] = []; - expect(() => guardedShift(arr)).to.throw(); - }); -}); - -describe('guardedSplice', () => { - it('delegates to Array#splice', () => { - const arr = [1, 2, 3]; - const spliceSpy = spy(arr, 'splice'); - const result = guardedSplice( - arr, - /* start */ 0, - /* deleteCount */ 3, - /* ...items */ - 100, - 101, - 102, - ); - expect(spliceSpy).is.calledWithExactly(0, 3, 100, 101, 102); - expect(result).to.eq(spliceSpy.returnValues[0]); - }); - it('allows zero-length splices', () => { - const arr: number[] = [1, 2, 3]; - expect(guardedSplice(arr, 0, 0)).to.be.an.empty('array'); - }); - it('allows zero-length splices via the `deleteCount` argument being the explicit value `undefined`', () => { - const arr: number[] = [1, 2, 3]; - expect(guardedSplice(arr, 0, undefined)).to.be.an.empty('array'); - }); - it('throws when the `start` would take you past the end of the array', () => { - const arr: number[] = [1, 2, 3]; - expect(() => guardedSplice(arr, 3)).to.throw(); - }); - it('throws when the `deleteCount` and `start` would take you past the end of the array', () => { - const arr: number[] = [1, 2, 3]; - expect(() => guardedSplice(arr, 1, 3)).to.throw(); - }); -}); diff --git a/packages/library-legacy/test/keypair.test.ts b/packages/library-legacy/test/keypair.test.ts deleted file mode 100644 index 60185d5b845c..000000000000 --- a/packages/library-legacy/test/keypair.test.ts +++ /dev/null @@ -1,61 +0,0 @@ -import {expect} from 'chai'; -import {Buffer} from 'buffer'; - -import {Keypair} from '../src'; - -describe('Keypair', () => { - it('new keypair', () => { - const keypair = new Keypair(); - expect(keypair.secretKey).to.have.length(64); - expect(keypair.publicKey.toBytes()).to.have.length(32); - }); - - it('generate new keypair', () => { - const keypair = Keypair.generate(); - expect(keypair.secretKey).to.have.length(64); - }); - - it('create keypair from secret key', () => { - const secretKey = Buffer.from( - 'mdqVWeFekT7pqy5T49+tV12jO0m+ESW7ki4zSU9JiCgbL0kJbj5dvQ/PqcDAzZLZqzshVEs01d1KZdmLh4uZIg==', - 'base64', - ); - const keypair = Keypair.fromSecretKey(secretKey); - expect(keypair.publicKey.toBase58()).to.eq( - '2q7pyhPwAwZ3QMfZrnAbDhnh9mDUqycszcpf86VgQxhF', - ); - expect(keypair.secretKey.toString()).to.eq( - '153,218,149,89,225,94,145,62,233,171,46,83,227,223,173,87,93,163,59,73,' + - '190,17,37,187,146,46,51,73,79,73,136,40,27,47,73,9,110,62,93,189,15,207,' + - '169,192,192,205,146,217,171,59,33,84,75,52,213,221,74,101,217,139,135,139,153,34', - ); - }); - - it('creating keypair from invalid secret key throws error', () => { - const secretKey = Buffer.from( - 'mdqVWeFekT7pqy5T49+tV12jO0m+ESW7ki4zSU9JiCgbL0kJbj5dvQ/PqcDAzZLZqzshVEs01d1KZdmLh4uZIG==', - 'base64', - ); - expect(() => { - Keypair.fromSecretKey(secretKey); - }).to.throw('provided secretKey is invalid'); - }); - - it('creating keypair from invalid secret key succeeds if validation is skipped', () => { - const secretKey = Buffer.from( - 'mdqVWeFekT7pqy5T49+tV12jO0m+ESW7ki4zSU9JiCgbL0kJbj5dvQ/PqcDAzZLZqzshVEs01d1KZdmLh4uZIG==', - 'base64', - ); - const keypair = Keypair.fromSecretKey(secretKey, {skipValidation: true}); - expect(keypair.publicKey.toBase58()).to.eq( - '2q7pyhPwAwZ3QMfZrnAbDhnh9mDUqycszcpf86VgQxhD', - ); - }); - - it('generate keypair from random seed', () => { - const keypair = Keypair.fromSeed(Uint8Array.from(Array(32).fill(8))); - expect(keypair.publicKey.toBase58()).to.eq( - '2KW2XRd9kwqet15Aha2oK3tYvd3nWbTFH1MBiRAv1BE1', - ); - }); -}); diff --git a/packages/library-legacy/test/makeWebsocketUrl.test.ts b/packages/library-legacy/test/makeWebsocketUrl.test.ts deleted file mode 100644 index 4f0c196d52e2..000000000000 --- a/packages/library-legacy/test/makeWebsocketUrl.test.ts +++ /dev/null @@ -1,52 +0,0 @@ -import {expect} from 'chai'; - -import {makeWebsocketUrl} from '../src/utils/makeWebsocketUrl'; - -const INVALID_URLS = [ - '', - '0.0.0.0', - 'localhost', - 'www.no-protocol.com', - '//api.protocol.relative.com', -]; -const TEST_CASES = [ - // Non-https => `ws` - ['http://api.devnet.solana.com/', 'ws://api.devnet.solana.com/'], - ['gopher://gopher.example.com/', 'ws://gopher.example.com/'], - ['http://localhost/', 'ws://localhost/'], - // `https` => `wss` - ['https://api.devnet.solana.com/', 'wss://api.devnet.solana.com/'], - // IPv4 address - ['https://192.168.0.1/', 'wss://192.168.0.1/'], - // IPv6 address - ['https://[0:0:0:0:0:0:0:0]/', 'wss://[0:0:0:0:0:0:0:0]/'], - ['https://[::]/', 'wss://[::]/'], - ['https://[::1]/', 'wss://[::1]/'], - // Increment port if supplied - ['https://api.devnet.solana.com:80/', 'wss://api.devnet.solana.com:81/'], - ['https://192.168.0.1:443/', 'wss://192.168.0.1:444/'], - ['https://[::]:8080/', 'wss://[::]:8081/'], - // No trailing slash - ['http://api.devnet.solana.com', 'ws://api.devnet.solana.com'], - ['https://api.devnet.solana.com', 'wss://api.devnet.solana.com'], - ['https://api.devnet.solana.com:80', 'wss://api.devnet.solana.com:81'], - // Username - ['https://alice@private.com', 'wss://alice@private.com'], - // Username/password - ['https://bob:password@private.com', 'wss://bob:password@private.com'], -]; - -describe('makeWebsocketUrl', () => { - TEST_CASES.forEach(([inputUrl, outputUrl]) => { - it(`converts \`${inputUrl}\` to \`${outputUrl}\``, () => { - expect(makeWebsocketUrl(inputUrl)).to.equal(outputUrl); - }); - }); - INVALID_URLS.forEach(invalidUrl => { - it(`fatals when called with invalid url \`${invalidUrl}\``, () => { - expect(() => { - makeWebsocketUrl(invalidUrl); - }).to.throw(); - }); - }); -}); diff --git a/packages/library-legacy/test/message-tests/account-keys.test.ts b/packages/library-legacy/test/message-tests/account-keys.test.ts deleted file mode 100644 index ec132e4d9657..000000000000 --- a/packages/library-legacy/test/message-tests/account-keys.test.ts +++ /dev/null @@ -1,180 +0,0 @@ -import {expect} from 'chai'; - -import { - MessageAccountKeys, - MessageCompiledInstruction, -} from '../../src/message'; -import {PublicKey} from '../../src/publickey'; -import {TransactionInstruction} from '../../src/transaction'; - -function createTestKeys(count: number): Array { - return new Array(count).fill(0).map(() => PublicKey.unique()); -} - -describe('MessageAccountKeys', () => { - it('keySegments', () => { - const keys = createTestKeys(6); - const staticAccountKeys = keys.slice(0, 3); - const accountKeysFromLookups = { - writable: [keys[3], keys[4]], - readonly: [keys[5]], - }; - - const accountKeys = new MessageAccountKeys( - staticAccountKeys, - accountKeysFromLookups, - ); - - const expectedSegments = [ - staticAccountKeys, - accountKeysFromLookups.writable, - accountKeysFromLookups.readonly, - ]; - - expect(expectedSegments).to.eql(accountKeys.keySegments()); - }); - - it('get', () => { - const keys = createTestKeys(3); - const accountKeys = new MessageAccountKeys(keys); - - expect(accountKeys.get(0)).to.eq(keys[0]); - expect(accountKeys.get(1)).to.eq(keys[1]); - expect(accountKeys.get(2)).to.eq(keys[2]); - expect(accountKeys.get(3)).to.be.undefined; - }); - - it('get with loaded addresses', () => { - const keys = createTestKeys(6); - const staticAccountKeys = keys.slice(0, 3); - const accountKeysFromLookups = { - writable: [keys[3], keys[4]], - readonly: [keys[5]], - }; - - const accountKeys = new MessageAccountKeys( - staticAccountKeys, - accountKeysFromLookups, - ); - - expect(accountKeys.get(0)).to.eq(keys[0]); - expect(accountKeys.get(1)).to.eq(keys[1]); - expect(accountKeys.get(2)).to.eq(keys[2]); - expect(accountKeys.get(3)).to.eq(keys[3]); - expect(accountKeys.get(4)).to.eq(keys[4]); - expect(accountKeys.get(5)).to.eq(keys[5]); - }); - - it('length', () => { - const keys = createTestKeys(6); - const accountKeys = new MessageAccountKeys(keys); - expect(accountKeys.length).to.eq(6); - }); - - it('length with loaded addresses', () => { - const keys = createTestKeys(6); - const accountKeys = new MessageAccountKeys(keys.slice(0, 3), { - writable: [], - readonly: keys.slice(3, 6), - }); - - expect(accountKeys.length).to.eq(6); - }); - - it('compileInstructions', () => { - const keys = createTestKeys(3); - const staticAccountKeys = [keys[0]]; - const accountKeysFromLookups = { - writable: [keys[1]], - readonly: [keys[2]], - }; - - const accountKeys = new MessageAccountKeys( - staticAccountKeys, - accountKeysFromLookups, - ); - - const instruction = new TransactionInstruction({ - programId: keys[0], - keys: [ - { - pubkey: keys[1], - isSigner: true, - isWritable: true, - }, - { - pubkey: keys[2], - isSigner: true, - isWritable: true, - }, - ], - data: Buffer.alloc(0), - }); - - const expectedInstruction: MessageCompiledInstruction = { - programIdIndex: 0, - accountKeyIndexes: [1, 2], - data: new Uint8Array(0), - }; - - expect(accountKeys.compileInstructions([instruction])).to.eql([ - expectedInstruction, - ]); - }); - - it('compileInstructions with unknown key', () => { - const keys = createTestKeys(3); - const staticAccountKeys = [keys[0]]; - const accountKeysFromLookups = { - writable: [keys[1]], - readonly: [keys[2]], - }; - - const accountKeys = new MessageAccountKeys( - staticAccountKeys, - accountKeysFromLookups, - ); - - const unknownKey = PublicKey.unique(); - const testInstructions = [ - new TransactionInstruction({ - programId: unknownKey, - keys: [], - data: Buffer.alloc(0), - }), - new TransactionInstruction({ - programId: keys[0], - keys: [ - { - pubkey: keys[1], - isSigner: true, - isWritable: true, - }, - { - pubkey: unknownKey, - isSigner: true, - isWritable: true, - }, - ], - data: Buffer.alloc(0), - }), - ]; - - for (const instruction of testInstructions) { - expect(() => accountKeys.compileInstructions([instruction])).to.throw( - 'Encountered an unknown instruction account key during compilation', - ); - } - }); - - it('compileInstructions with too many account keys', () => { - const keys = createTestKeys(257); - const accountKeys = new MessageAccountKeys(keys.slice(0, 256), { - writable: [keys[256]], - readonly: [], - }); - expect(() => accountKeys.compileInstructions([])).to.throw( - 'Account index overflow encountered during compilation', - ); - }); -}); diff --git a/packages/library-legacy/test/message-tests/compiled-keys.test.ts b/packages/library-legacy/test/message-tests/compiled-keys.test.ts deleted file mode 100644 index adca1cefe240..000000000000 --- a/packages/library-legacy/test/message-tests/compiled-keys.test.ts +++ /dev/null @@ -1,243 +0,0 @@ -import {expect} from 'chai'; - -import {CompiledKeyMeta, CompiledKeys} from '../../src/message/compiled-keys'; -import {AddressLookupTableAccount} from '../../src/programs'; -import {PublicKey} from '../../src/publickey'; -import {AccountMeta, TransactionInstruction} from '../../src/transaction'; - -function createTestKeys(count: number): Array { - return new Array(count).fill(0).map(() => PublicKey.unique()); -} - -function createTestLookupTable( - addresses: Array, -): AddressLookupTableAccount { - const U64_MAX = BigInt('0xffffffffffffffff'); - return new AddressLookupTableAccount({ - key: PublicKey.unique(), - state: { - lastExtendedSlot: 0, - lastExtendedSlotStartIndex: 0, - deactivationSlot: U64_MAX, - authority: PublicKey.unique(), - addresses, - }, - }); -} - -describe('CompiledKeys', () => { - it('compile', () => { - const payer = PublicKey.unique(); - const keys = createTestKeys(4); - const programIds = createTestKeys(4); - const compiledKeys = CompiledKeys.compile( - [ - new TransactionInstruction({ - programId: programIds[0], - keys: [ - createAccountMeta(keys[0], false, false), - createAccountMeta(keys[1], true, false), - createAccountMeta(keys[2], false, true), - createAccountMeta(keys[3], true, true), - // duplicate the account metas - createAccountMeta(keys[0], false, false), - createAccountMeta(keys[1], true, false), - createAccountMeta(keys[2], false, true), - createAccountMeta(keys[3], true, true), - // reference program ids - createAccountMeta(programIds[0], false, false), - createAccountMeta(programIds[1], true, false), - createAccountMeta(programIds[2], false, true), - createAccountMeta(programIds[3], true, true), - ], - }), - new TransactionInstruction({programId: programIds[1], keys: []}), - new TransactionInstruction({programId: programIds[2], keys: []}), - new TransactionInstruction({programId: programIds[3], keys: []}), - ], - payer, - ); - - const map = new Map(); - setMapEntry(map, payer, true, true, false); - setMapEntry(map, keys[0], false, false, false); - setMapEntry(map, keys[1], true, false, false); - setMapEntry(map, keys[2], false, true, false); - setMapEntry(map, keys[3], true, true, false); - setMapEntry(map, programIds[0], false, false, true); - setMapEntry(map, programIds[1], true, false, true); - setMapEntry(map, programIds[2], false, true, true); - setMapEntry(map, programIds[3], true, true, true); - expect(compiledKeys.keyMetaMap).to.eql(map); - expect(compiledKeys.payer).to.eq(payer); - }); - - it('compile with dup payer', () => { - const [payer, programId] = createTestKeys(2); - const compiledKeys = CompiledKeys.compile( - [ - new TransactionInstruction({ - programId: programId, - keys: [createAccountMeta(payer, false, false)], - }), - ], - payer, - ); - - const map = new Map(); - setMapEntry(map, payer, true, true, false); - setMapEntry(map, programId, false, false, true); - expect(compiledKeys.keyMetaMap).to.eql(map); - expect(compiledKeys.payer).to.eq(payer); - }); - - it('compile with dup key', () => { - const [payer, key, programId] = createTestKeys(3); - const compiledKeys = CompiledKeys.compile( - [ - new TransactionInstruction({ - programId: programId, - keys: [ - createAccountMeta(key, false, false), - createAccountMeta(key, true, true), - ], - }), - ], - payer, - ); - - const map = new Map(); - setMapEntry(map, payer, true, true, false); - setMapEntry(map, key, true, true, false); - setMapEntry(map, programId, false, false, true); - expect(compiledKeys.keyMetaMap).to.eql(map); - expect(compiledKeys.payer).to.eq(payer); - }); - - it('getMessageComponents', () => { - const keys = createTestKeys(4); - const payer = keys[0]; - const map = new Map(); - setMapEntry(map, payer, true, true, false); - setMapEntry(map, keys[1], true, false, false); - setMapEntry(map, keys[2], false, true, false); - setMapEntry(map, keys[3], false, false, false); - const compiledKeys = new CompiledKeys(payer, map); - const [header, staticAccountKeys] = compiledKeys.getMessageComponents(); - expect(staticAccountKeys).to.eql(keys); - expect(header).to.eql({ - numRequiredSignatures: 2, - numReadonlySignedAccounts: 1, - numReadonlyUnsignedAccounts: 1, - }); - }); - - it('getMessageComponents with overflow', () => { - const keys = createTestKeys(257); - const map = new Map(); - for (const key of keys) { - setMapEntry(map, key, true, true, false); - } - const compiledKeys = new CompiledKeys(keys[0], map); - expect(() => compiledKeys.getMessageComponents()).to.throw( - 'Max static account keys length exceeded', - ); - }); - - it('extractTableLookup', () => { - const keys = createTestKeys(6); - const map = new Map(); - setMapEntry(map, keys[0], true, true, false); - setMapEntry(map, keys[1], true, false, false); - setMapEntry(map, keys[2], false, true, false); - setMapEntry(map, keys[3], false, false, false); - setMapEntry(map, keys[4], true, false, true); - setMapEntry(map, keys[5], false, false, true); - - const lookupTable = createTestLookupTable([...keys, ...keys]); - const compiledKeys = new CompiledKeys(keys[0], map); - const extractResult = compiledKeys.extractTableLookup(lookupTable); - if (extractResult === undefined) { - expect(extractResult).to.not.be.undefined; - return; - } - - const [tableLookup, extractedAddresses] = extractResult; - expect(tableLookup).to.eql({ - accountKey: lookupTable.key, - writableIndexes: [2], - readonlyIndexes: [3], - }); - expect(extractedAddresses).to.eql({ - writable: [keys[2]], - readonly: [keys[3]], - }); - }); - - it('extractTableLookup no extractable keys found', () => { - const keys = createTestKeys(6); - const map = new Map(); - setMapEntry(map, keys[0], true, true, false); - setMapEntry(map, keys[1], true, false, false); - setMapEntry(map, keys[2], true, true, true); - setMapEntry(map, keys[3], true, false, true); - setMapEntry(map, keys[4], false, true, true); - setMapEntry(map, keys[5], false, false, true); - - const lookupTable = createTestLookupTable(keys); - const compiledKeys = new CompiledKeys(keys[0], map); - const extractResult = compiledKeys.extractTableLookup(lookupTable); - expect(extractResult).to.be.undefined; - }); - - it('extractTableLookup with empty lookup table', () => { - const keys = createTestKeys(2); - const map = new Map(); - setMapEntry(map, keys[0], true, true, false); - setMapEntry(map, keys[1], false, false, false); - - const lookupTable = createTestLookupTable([]); - const compiledKeys = new CompiledKeys(keys[0], map); - const extractResult = compiledKeys.extractTableLookup(lookupTable); - expect(extractResult).to.be.undefined; - }); - - it('extractTableLookup with invalid lookup table', () => { - const keys = createTestKeys(257); - const map = new Map(); - setMapEntry(map, keys[0], true, true, false); - setMapEntry(map, keys[256], false, false, false); - - const lookupTable = createTestLookupTable(keys); - const compiledKeys = new CompiledKeys(keys[0], map); - expect(() => compiledKeys.extractTableLookup(lookupTable)).to.throw( - 'Max lookup table index exceeded', - ); - }); -}); - -function setMapEntry( - map: Map, - pubkey: PublicKey, - isSigner: boolean, - isWritable: boolean, - isInvoked: boolean, -) { - map.set(pubkey.toBase58(), { - isSigner, - isWritable, - isInvoked, - }); -} - -function createAccountMeta( - pubkey: PublicKey, - isSigner: boolean, - isWritable: boolean, -): AccountMeta { - return { - pubkey, - isSigner, - isWritable, - }; -} diff --git a/packages/library-legacy/test/message-tests/legacy.test.ts b/packages/library-legacy/test/message-tests/legacy.test.ts deleted file mode 100644 index 5af60c8cff31..000000000000 --- a/packages/library-legacy/test/message-tests/legacy.test.ts +++ /dev/null @@ -1,143 +0,0 @@ -import bs58 from 'bs58'; -import {expect} from 'chai'; -import {sha256} from '@noble/hashes/sha256'; - -import {Message} from '../../src/message'; -import {TransactionInstruction} from '../../src/transaction'; -import {PublicKey} from '../../src/publickey'; - -function createTestKeys(count: number): Array { - return new Array(count).fill(0).map(() => PublicKey.unique()); -} - -describe('Message', () => { - it('compile', () => { - const keys = createTestKeys(5); - const recentBlockhash = bs58.encode(sha256('test')); - const payerKey = keys[0]; - const instructions = [ - new TransactionInstruction({ - programId: keys[4], - keys: [ - {pubkey: keys[1], isSigner: true, isWritable: true}, - {pubkey: keys[2], isSigner: false, isWritable: false}, - {pubkey: keys[3], isSigner: false, isWritable: false}, - ], - data: Buffer.alloc(1), - }), - new TransactionInstruction({ - programId: keys[1], - keys: [ - {pubkey: keys[2], isSigner: true, isWritable: false}, - {pubkey: keys[3], isSigner: false, isWritable: true}, - ], - data: Buffer.alloc(2), - }), - ]; - - const message = Message.compile({ - payerKey, - recentBlockhash, - instructions, - }); - - expect(message.accountKeys).to.eql([ - payerKey, // payer is first - keys[1], // other writable signer - keys[2], // sole readonly signer - keys[3], // sole writable non-signer - keys[4], // sole readonly non-signer - ]); - expect(message.header).to.eql({ - numRequiredSignatures: 3, - numReadonlySignedAccounts: 1, - numReadonlyUnsignedAccounts: 1, - }); - expect(message.addressTableLookups.length).to.eq(0); - expect(message.instructions).to.eql([ - { - programIdIndex: 4, - accounts: [1, 2, 3], - data: bs58.encode(Buffer.alloc(1)), - }, - { - programIdIndex: 1, - accounts: [2, 3], - data: bs58.encode(Buffer.alloc(2)), - }, - ]); - expect(message.recentBlockhash).to.eq(recentBlockhash); - }); - - it('compile without instructions', () => { - const payerKey = PublicKey.unique(); - const recentBlockhash = bs58.encode(sha256('test')); - const message = Message.compile({ - payerKey, - instructions: [], - recentBlockhash, - }); - - expect(message.accountKeys).to.eql([payerKey]); - expect(message.header).to.eql({ - numRequiredSignatures: 1, - numReadonlySignedAccounts: 0, - numReadonlyUnsignedAccounts: 0, - }); - expect(message.addressTableLookups.length).to.eq(0); - expect(message.instructions.length).to.eq(0); - expect(message.recentBlockhash).to.eq(recentBlockhash); - }); - - it('isAccountWritable', () => { - const accountKeys = [ - PublicKey.unique(), - PublicKey.unique(), - PublicKey.unique(), - PublicKey.unique(), - ]; - - const recentBlockhash = bs58.encode(sha256('test')); - const message = new Message({ - header: { - numRequiredSignatures: 2, - numReadonlySignedAccounts: 1, - numReadonlyUnsignedAccounts: 1, - }, - recentBlockhash, - accountKeys, - instructions: [], - }); - - expect(message.isAccountWritable(0)).to.be.true; - expect(message.isAccountWritable(1)).to.be.false; - expect(message.isAccountWritable(2)).to.be.true; - expect(message.isAccountWritable(3)).to.be.false; - }); - - it('isAccountSigner', () => { - const accountKeys = [ - PublicKey.unique(), - PublicKey.unique(), - PublicKey.unique(), - PublicKey.unique(), - ]; - - const recentBlockhash = bs58.encode(sha256('test')); - const message = new Message({ - header: { - numRequiredSignatures: 2, - numReadonlySignedAccounts: 1, - numReadonlyUnsignedAccounts: 1, - }, - recentBlockhash, - accountKeys, - instructions: [], - }); - - expect(message.isAccountSigner(0)).to.be.true; - expect(message.isAccountSigner(1)).to.be.true; - expect(message.isAccountSigner(2)).to.be.false; - expect(message.isAccountSigner(3)).to.be.false; - }); -}); diff --git a/packages/library-legacy/test/message-tests/v0.test.ts b/packages/library-legacy/test/message-tests/v0.test.ts deleted file mode 100644 index 47d3807818e2..000000000000 --- a/packages/library-legacy/test/message-tests/v0.test.ts +++ /dev/null @@ -1,387 +0,0 @@ -import bs58 from 'bs58'; -import {expect} from 'chai'; -import {sha256} from '@noble/hashes/sha256'; - -import { - MessageAccountKeys, - MessageAddressTableLookup, - MessageV0, -} from '../../src/message'; -import {TransactionInstruction} from '../../src/transaction'; -import {PublicKey} from '../../src/publickey'; -import {AddressLookupTableAccount} from '../../src/programs'; - -function createTestKeys(count: number): Array { - return new Array(count).fill(0).map(() => PublicKey.unique()); -} - -function createTestLookupTable( - addresses: Array, -): AddressLookupTableAccount { - const U64_MAX = BigInt('0xffffffffffffffff'); - return new AddressLookupTableAccount({ - key: PublicKey.unique(), - state: { - lastExtendedSlot: 0, - lastExtendedSlotStartIndex: 0, - deactivationSlot: U64_MAX, - authority: PublicKey.unique(), - addresses, - }, - }); -} - -describe('MessageV0', () => { - it('numAccountKeysFromLookups', () => { - const message = MessageV0.compile({ - payerKey: PublicKey.unique(), - recentBlockhash: '', - instructions: [], - }); - expect(message.numAccountKeysFromLookups).to.eq(0); - - message.addressTableLookups = [ - { - accountKey: PublicKey.unique(), - writableIndexes: [0], - readonlyIndexes: [1], - }, - { - accountKey: PublicKey.unique(), - writableIndexes: [0, 2], - readonlyIndexes: [], - }, - ]; - expect(message.numAccountKeysFromLookups).to.eq(4); - }); - - it('getAccountKeys', () => { - const staticAccountKeys = createTestKeys(3); - const lookupTable = createTestLookupTable(createTestKeys(2)); - const message = new MessageV0({ - header: { - numRequiredSignatures: 1, - numReadonlySignedAccounts: 0, - numReadonlyUnsignedAccounts: 0, - }, - recentBlockhash: 'test', - staticAccountKeys, - compiledInstructions: [], - addressTableLookups: [ - { - accountKey: lookupTable.key, - writableIndexes: [0], - readonlyIndexes: [1], - }, - ], - }); - - expect(() => message.getAccountKeys()).to.throw( - 'Failed to get account keys because address table lookups were not resolved', - ); - expect(() => - message.getAccountKeys({ - accountKeysFromLookups: { - writable: [PublicKey.unique()], - readonly: [], - }, - }), - ).to.throw( - 'Failed to get account keys because of a mismatch in the number of account keys from lookups', - ); - - const accountKeysFromLookups = message.resolveAddressTableLookups([ - lookupTable, - ]); - const expectedAccountKeys = new MessageAccountKeys( - staticAccountKeys, - accountKeysFromLookups, - ); - - expect( - message.getAccountKeys({ - accountKeysFromLookups, - }), - ).to.eql(expectedAccountKeys); - - expect( - message.getAccountKeys({ - addressLookupTableAccounts: [lookupTable], - }), - ).to.eql(expectedAccountKeys); - }); - - it('resolveAddressTableLookups', () => { - const keys = createTestKeys(7); - const lookupTable = createTestLookupTable(keys); - const createTestMessage = ( - addressTableLookups: MessageAddressTableLookup[], - ): MessageV0 => { - return new MessageV0({ - header: { - numRequiredSignatures: 1, - numReadonlySignedAccounts: 0, - numReadonlyUnsignedAccounts: 0, - }, - recentBlockhash: 'test', - staticAccountKeys: [], - compiledInstructions: [], - addressTableLookups, - }); - }; - - expect( - createTestMessage([]).resolveAddressTableLookups([lookupTable]), - ).to.eql({ - writable: [], - readonly: [], - }); - - expect(() => - createTestMessage([ - { - accountKey: PublicKey.unique(), - writableIndexes: [1, 3, 5], - readonlyIndexes: [0, 2, 4], - }, - ]).resolveAddressTableLookups([lookupTable]), - ).to.throw('Failed to find address lookup table account for table key'); - - expect(() => - createTestMessage([ - { - accountKey: lookupTable.key, - writableIndexes: [10], - readonlyIndexes: [], - }, - ]).resolveAddressTableLookups([lookupTable]), - ).to.throw('Failed to find address for index'); - - expect( - createTestMessage([ - { - accountKey: lookupTable.key, - writableIndexes: [1, 3, 5], - readonlyIndexes: [0, 2, 4], - }, - ]).resolveAddressTableLookups([lookupTable]), - ).to.eql({ - writable: [keys[1], keys[3], keys[5]], - readonly: [keys[0], keys[2], keys[4]], - }); - }); - - it('compile', () => { - const keys = createTestKeys(7); - const recentBlockhash = bs58.encode(sha256('test')); - const payerKey = keys[0]; - const instructions = [ - new TransactionInstruction({ - programId: keys[4], - keys: [ - {pubkey: keys[1], isSigner: true, isWritable: true}, - {pubkey: keys[2], isSigner: false, isWritable: false}, - {pubkey: keys[3], isSigner: false, isWritable: false}, - ], - data: Buffer.alloc(1), - }), - new TransactionInstruction({ - programId: keys[1], - keys: [ - {pubkey: keys[2], isSigner: true, isWritable: false}, - {pubkey: keys[3], isSigner: false, isWritable: true}, - ], - data: Buffer.alloc(2), - }), - new TransactionInstruction({ - programId: keys[3], - keys: [ - {pubkey: keys[5], isSigner: false, isWritable: true}, - {pubkey: keys[6], isSigner: false, isWritable: false}, - ], - data: Buffer.alloc(3), - }), - ]; - - const lookupTable = createTestLookupTable(keys); - const message = MessageV0.compile({ - payerKey, - recentBlockhash, - instructions, - addressLookupTableAccounts: [lookupTable], - }); - - expect(message.staticAccountKeys).to.eql([ - payerKey, // payer is first - keys[1], // other writable signer - keys[2], // sole readonly signer - keys[3], // sole writable non-signer - keys[4], // sole readonly non-signer - ]); - expect(message.header).to.eql({ - numRequiredSignatures: 3, - numReadonlySignedAccounts: 1, - numReadonlyUnsignedAccounts: 1, - }); - // only keys 5 and 6 are eligible to be referenced by a lookup table - // because they are not invoked and are not signers - expect(message.addressTableLookups).to.eql([ - { - accountKey: lookupTable.key, - writableIndexes: [5], - readonlyIndexes: [6], - }, - ]); - expect(message.compiledInstructions).to.eql([ - { - programIdIndex: 4, - accountKeyIndexes: [1, 2, 3], - data: new Uint8Array(1), - }, - { - programIdIndex: 1, - accountKeyIndexes: [2, 3], - data: new Uint8Array(2), - }, - { - programIdIndex: 3, - accountKeyIndexes: [5, 6], - data: new Uint8Array(3), - }, - ]); - expect(message.recentBlockhash).to.eq(recentBlockhash); - }); - - it('serialize and deserialize', () => { - const messageV0 = new MessageV0({ - header: { - numRequiredSignatures: 1, - numReadonlySignedAccounts: 0, - numReadonlyUnsignedAccounts: 1, - }, - staticAccountKeys: [new PublicKey(1), new PublicKey(2)], - compiledInstructions: [ - { - programIdIndex: 1, - accountKeyIndexes: [2, 3], - data: new Uint8Array(10), - }, - ], - recentBlockhash: new PublicKey(0).toString(), - addressTableLookups: [ - { - accountKey: new PublicKey(3), - writableIndexes: [1], - readonlyIndexes: [], - }, - { - accountKey: new PublicKey(4), - writableIndexes: [], - readonlyIndexes: [2], - }, - ], - }); - const serializedMessage = messageV0.serialize(); - const deserializedMessage = MessageV0.deserialize(serializedMessage); - expect(JSON.stringify(messageV0)).to.eql( - JSON.stringify(deserializedMessage), - ); - }); - - it('deserialize failures', () => { - const bufferWithLegacyPrefix = new Uint8Array([1]); - expect(() => { - MessageV0.deserialize(bufferWithLegacyPrefix); - }).to.throw('Expected versioned message but received legacy message'); - - const bufferWithV1Prefix = new Uint8Array([(1 << 7) + 1]); - expect(() => { - MessageV0.deserialize(bufferWithV1Prefix); - }).to.throw( - 'Expected versioned message with version 0 but found version 1', - ); - }); - - it('isAccountWritable', () => { - const staticAccountKeys = [ - PublicKey.unique(), - PublicKey.unique(), - PublicKey.unique(), - PublicKey.unique(), - ]; - - const recentBlockhash = bs58.encode(sha256('test')); - const message = new MessageV0({ - header: { - numRequiredSignatures: 2, - numReadonlySignedAccounts: 1, - numReadonlyUnsignedAccounts: 1, - }, - recentBlockhash, - staticAccountKeys, - compiledInstructions: [], - addressTableLookups: [ - { - accountKey: PublicKey.unique(), - writableIndexes: [0], - readonlyIndexes: [1], - }, - { - accountKey: PublicKey.unique(), - writableIndexes: [0], - readonlyIndexes: [1], - }, - ], - }); - - expect(message.isAccountWritable(0)).to.be.true; - expect(message.isAccountWritable(1)).to.be.false; - expect(message.isAccountWritable(2)).to.be.true; - expect(message.isAccountWritable(3)).to.be.false; - - expect(message.isAccountWritable(4)).to.be.true; - expect(message.isAccountWritable(5)).to.be.true; - - expect(message.isAccountWritable(6)).to.be.false; - expect(message.isAccountWritable(7)).to.be.false; - }); - - it('isAccountSigner', () => { - const staticAccountKeys = [ - PublicKey.unique(), - PublicKey.unique(), - PublicKey.unique(), - PublicKey.unique(), - ]; - - const recentBlockhash = bs58.encode(sha256('test')); - const message = new MessageV0({ - header: { - numRequiredSignatures: 2, - numReadonlySignedAccounts: 1, - numReadonlyUnsignedAccounts: 1, - }, - recentBlockhash, - staticAccountKeys, - compiledInstructions: [], - addressTableLookups: [ - { - accountKey: PublicKey.unique(), - writableIndexes: [0], - readonlyIndexes: [1], - }, - { - accountKey: PublicKey.unique(), - writableIndexes: [0], - readonlyIndexes: [1], - }, - ], - }); - - expect(message.isAccountSigner(0)).to.be.true; - expect(message.isAccountSigner(1)).to.be.true; - for (let i = 2; i < 8; i++) { - expect(message.isAccountSigner(i)).to.be.false; - } - }); -}); diff --git a/packages/library-legacy/test/message-tests/versioned.test.ts b/packages/library-legacy/test/message-tests/versioned.test.ts deleted file mode 100644 index 1acaf7823b14..000000000000 --- a/packages/library-legacy/test/message-tests/versioned.test.ts +++ /dev/null @@ -1,28 +0,0 @@ -import {expect} from 'chai'; - -import {VersionedMessage} from '../../src/message'; - -describe('VersionedMessage', () => { - it('deserializeMessageVersion', () => { - const bufferWithLegacyPrefix = new Uint8Array([1]); - expect( - VersionedMessage.deserializeMessageVersion(bufferWithLegacyPrefix), - ).to.eq('legacy'); - - for (const version of [0, 1, 127]) { - const bufferWithVersionPrefix = new Uint8Array([(1 << 7) + version]); - expect( - VersionedMessage.deserializeMessageVersion(bufferWithVersionPrefix), - ).to.eq(version); - } - }); - - it('deserialize failure', () => { - const bufferWithV1Prefix = new Uint8Array([(1 << 7) + 1]); - expect(() => { - VersionedMessage.deserialize(bufferWithV1Prefix); - }).to.throw( - 'Transaction message version 1 deserialization is not supported', - ); - }); -}); diff --git a/packages/library-legacy/test/mocks/rpc-http.ts b/packages/library-legacy/test/mocks/rpc-http.ts deleted file mode 100644 index dae8fdd41ff8..000000000000 --- a/packages/library-legacy/test/mocks/rpc-http.ts +++ /dev/null @@ -1,273 +0,0 @@ -import bs58 from 'bs58'; -import BN from 'bn.js'; -import * as mockttp from 'mockttp'; - -import {mockRpcMessage} from './rpc-websocket'; -import {Connection, PublicKey, Transaction, Signer} from '../../src'; -import invariant from '../../src/utils/assert'; -import type {Commitment, HttpHeaders, RpcParams} from '../../src/connection'; - -export const mockServer: mockttp.Mockttp | undefined = - process.env.TEST_LIVE === undefined ? mockttp.getLocal() : undefined; - -let uniqueCounter = 0; -export const uniqueSignature = () => { - return bs58.encode(new BN(++uniqueCounter).toArray(undefined, 64)); -}; -export const uniqueBlockhash = () => { - return bs58.encode(new BN(++uniqueCounter).toArray(undefined, 32)); -}; - -export const mockErrorMessage = 'Invalid'; -export const mockErrorResponse = { - code: -32602, - message: mockErrorMessage, -}; - -export const mockRpcBatchResponse = async ({ - batch, - result, - error, -}: { - batch: RpcParams[]; - result: any[]; - error?: string; -}) => { - if (!mockServer) return; - - const request = batch.map((batch: RpcParams) => { - return { - jsonrpc: '2.0', - method: batch.methodName, - params: batch.args, - }; - }); - - const response = result.map((result: any) => { - return { - jsonrpc: '2.0', - id: '', - result, - error, - }; - }); - - await mockServer - .forPost('/') - .withJsonBodyIncluding(request) - .thenReply(200, JSON.stringify(response)); -}; - -function isPromise(obj: PromiseLike | T): obj is PromiseLike { - return ( - !!obj && - (typeof obj === 'object' || typeof obj === 'function') && - typeof (obj as any).then === 'function' - ); -} - -export const mockRpcResponse = async ({ - method, - params, - value, - error, - slot, - withContext, - withHeaders, -}: { - method: string; - params: Array; - value?: Promise | any; - error?: any; - slot?: number; - withContext?: boolean; - withHeaders?: HttpHeaders; -}) => { - if (!mockServer) return; - - await mockServer - .forPost('/') - .withJsonBodyIncluding({ - jsonrpc: '2.0', - method, - params, - }) - .withHeaders(withHeaders || {}) - .thenCallback(async () => { - try { - const unwrappedValue = isPromise(value) ? await value : value; - let result = unwrappedValue; - if (withContext) { - result = { - context: { - slot: slot != null ? slot : 11, - }, - value: unwrappedValue, - }; - } - return { - statusCode: 200, - json: { - jsonrpc: '2.0', - id: '', - error, - result, - }, - }; - } catch (_e) { - return {statusCode: 500}; - } - }); -}; - -const latestBlockhash = async ({ - connection, - commitment, -}: { - connection: Connection; - commitment?: Commitment; -}) => { - const blockhash = uniqueBlockhash(); - const params: Array = []; - if (commitment) { - params.push({commitment}); - } - - await mockRpcResponse({ - method: 'getLatestBlockhash', - params, - value: { - blockhash, - lastValidBlockHeight: 3090, - }, - withContext: true, - }); - - return await connection.getLatestBlockhash(commitment); -}; - -const recentBlockhash = async ({ - connection, - commitment, -}: { - connection: Connection; - commitment?: Commitment; -}) => { - const blockhash = uniqueBlockhash(); - const params: Array = []; - if (commitment) { - params.push({commitment}); - } - - await mockRpcResponse({ - method: 'getRecentBlockhash', - params, - value: { - blockhash, - feeCalculator: { - lamportsPerSignature: 42, - }, - }, - withContext: true, - }); - - return await connection.getRecentBlockhash(commitment); -}; - -const processTransaction = async ({ - connection, - transaction, - signers, - commitment, - err, -}: { - connection: Connection; - transaction: Transaction; - signers: Array; - commitment: Commitment; - err?: any; -}) => { - const {blockhash, lastValidBlockHeight} = await latestBlockhash({ - connection, - }); - transaction.lastValidBlockHeight = lastValidBlockHeight; - transaction.recentBlockhash = blockhash; - transaction.sign(...signers); - - const encoded = transaction.serialize().toString('base64'); - invariant(transaction.signature); - const signature = bs58.encode(transaction.signature); - await mockRpcResponse({ - method: 'sendTransaction', - params: [encoded], - value: signature, - }); - - let sendOptions; - if (err) { - sendOptions = { - skipPreflight: true, - }; - } else { - sendOptions = { - preflightCommitment: commitment, - }; - } - - await connection.sendEncodedTransaction(encoded, sendOptions); - - await mockRpcMessage({ - method: 'signatureSubscribe', - params: [signature, {commitment}], - result: {err: err || null}, - }); - await mockRpcMessage({ - method: 'signatureUnsubscribe', - params: [1], - result: true, - }); - - return await connection.confirmTransaction( - {blockhash, lastValidBlockHeight, signature}, - commitment, - ); -}; - -const airdrop = async ({ - connection, - address, - amount, -}: { - connection: Connection; - address: PublicKey; - amount: number; -}) => { - await mockRpcResponse({ - method: 'requestAirdrop', - params: [address.toBase58(), amount], - value: uniqueSignature(), - }); - - const signature = await connection.requestAirdrop(address, amount); - - await mockRpcMessage({ - method: 'signatureSubscribe', - params: [signature, {commitment: 'confirmed'}], - result: {err: null}, - }); - await mockRpcMessage({ - method: 'signatureUnsubscribe', - params: [1], - result: true, - }); - - await connection.confirmTransaction(signature, 'confirmed'); - return signature; -}; - -export const helpers = { - airdrop, - processTransaction, - recentBlockhash, - latestBlockhash, -}; diff --git a/packages/library-legacy/test/mocks/rpc-websocket.ts b/packages/library-legacy/test/mocks/rpc-websocket.ts deleted file mode 100644 index 4dbfc182c715..000000000000 --- a/packages/library-legacy/test/mocks/rpc-websocket.ts +++ /dev/null @@ -1,138 +0,0 @@ -import {expect} from 'chai'; -import {createSandbox} from 'sinon'; - -import {Connection} from '../../src'; -import LiveClient from '../../src/rpc-websocket'; - -type RpcRequest = { - method: string; - params?: Array; - subscriptionEstablishmentPromise?: Promise; -}; - -type RpcResponse = { - context: { - slot: number; - }; - value: any | Promise; -}; - -const mockRpcSocket: Array<[RpcRequest, RpcResponse | Promise]> = - []; -const sandbox = createSandbox(); - -export const mockRpcMessage = ({ - method, - params, - result, - subscriptionEstablishmentPromise, -}: { - method: string; - params: Array; - result: any | Promise; - subscriptionEstablishmentPromise?: Promise; -}) => { - mockRpcSocket.push([ - {method, params, subscriptionEstablishmentPromise}, - { - context: {slot: 11}, - value: result, - }, - ]); -}; - -export const stubRpcWebSocket = (connection: Connection) => { - const rpcWebSocket = connection._rpcWebSocket; - const mockClient = new MockClient(rpcWebSocket); - sandbox.stub(rpcWebSocket, 'connect').callsFake(() => { - mockClient.connect(); - }); - sandbox.stub(rpcWebSocket, 'close').callsFake(() => { - mockClient.close(); - }); - sandbox - .stub(rpcWebSocket, 'call') - .callsFake((method: string, params: any) => { - return mockClient.call(method, params); - }); - sandbox.stub(rpcWebSocket, 'notify'); -}; - -export const restoreRpcWebSocket = (connection: Connection) => { - connection._rpcWebSocket.close(); - if (connection._rpcWebSocketIdleTimeout !== null) { - clearTimeout(connection._rpcWebSocketIdleTimeout); - connection._rpcWebSocketIdleTimeout = null; - } - sandbox.restore(); -}; - -function isPromise(obj: PromiseLike | T): obj is PromiseLike { - return ( - !!obj && - (typeof obj === 'object' || typeof obj === 'function') && - typeof (obj as any).then === 'function' - ); -} - -class MockClient { - client: LiveClient; - mockOpen = false; - subscriptionCounter = 0; - - constructor(rpcWebSocket: LiveClient) { - this.client = rpcWebSocket; - } - - connect() { - if (!this.mockOpen) { - this.mockOpen = true; - this.client.emit('open'); - } - } - - close() { - if (this.mockOpen) { - this.mockOpen = false; - this.client.emit('close'); - } - } - - async call(method: string, params: Array): Promise { - expect(mockRpcSocket.length).to.be.at.least(1); - const [mockRequest, mockResponse] = mockRpcSocket.shift() as [ - RpcRequest, - RpcResponse, - ]; - - expect(method).to.eq(mockRequest.method); - if (method.endsWith('Unsubscribe')) { - expect(params.length).to.eq(1); - expect(params[0]).to.be.a('number'); - } else { - expect(params).to.eql(mockRequest.params); - } - - if (mockRequest.subscriptionEstablishmentPromise) { - await mockRequest.subscriptionEstablishmentPromise; - } - - let id = ++this.subscriptionCounter; - const response = { - subscription: id, - result: { - ...mockResponse, - value: isPromise(mockResponse.value) - ? await mockResponse.value - : mockResponse.value, - }, - }; - - setImmediate(() => { - const eventName = method.replace('Subscribe', 'Notification'); - this.client.emit(eventName, response); - }); - - return Promise.resolve(id); - } -} diff --git a/packages/library-legacy/test/nonce.test.ts b/packages/library-legacy/test/nonce.test.ts deleted file mode 100644 index 7efd8886e657..000000000000 --- a/packages/library-legacy/test/nonce.test.ts +++ /dev/null @@ -1,179 +0,0 @@ -import bs58 from 'bs58'; -import {Buffer} from 'buffer'; -import {expect} from 'chai'; - -import { - Connection, - SystemProgram, - Transaction, - PublicKey, - Keypair, -} from '../src'; -import {NONCE_ACCOUNT_LENGTH} from '../src/nonce-account'; -import {MOCK_PORT, url} from './url'; -import {helpers, mockRpcResponse, mockServer} from './mocks/rpc-http'; -import {stubRpcWebSocket, restoreRpcWebSocket} from './mocks/rpc-websocket'; - -const expectedData = (authorizedPubkey: PublicKey): [string, string] => { - const expectedData = Buffer.alloc(NONCE_ACCOUNT_LENGTH); - expectedData.writeInt32LE(0, 0); // Version, 4 bytes - expectedData.writeInt32LE(1, 4); // State, 4 bytes - authorizedPubkey.toBuffer().copy(expectedData, 8); // authorizedPubkey, 32 bytes - const mockNonce = Keypair.generate(); - mockNonce.publicKey.toBuffer().copy(expectedData, 40); // Hash, 32 bytes - expectedData.writeUInt16LE(5000, 72); // feeCalculator, 8 bytes - return [expectedData.toString('base64'), 'base64']; -}; - -describe('Nonce', () => { - let connection: Connection; - beforeEach(() => { - connection = new Connection(url); - }); - - if (mockServer) { - const server = mockServer; - beforeEach(() => { - server.start(MOCK_PORT); - stubRpcWebSocket(connection); - }); - - afterEach(() => { - server.stop(); - restoreRpcWebSocket(connection); - }); - } - - it('create and query nonce account', async () => { - const from = Keypair.generate(); - const nonceAccount = Keypair.generate(); - - await mockRpcResponse({ - method: 'getMinimumBalanceForRentExemption', - params: [NONCE_ACCOUNT_LENGTH], - value: 50, - }); - - const minimumAmount = - await connection.getMinimumBalanceForRentExemption(NONCE_ACCOUNT_LENGTH); - - await helpers.airdrop({ - connection, - address: from.publicKey, - amount: minimumAmount * 2, - }); - - const transaction = new Transaction().add( - SystemProgram.createNonceAccount({ - fromPubkey: from.publicKey, - noncePubkey: nonceAccount.publicKey, - authorizedPubkey: from.publicKey, - lamports: minimumAmount, - }), - ); - - await helpers.processTransaction({ - connection, - transaction, - signers: [from, nonceAccount], - commitment: 'confirmed', - }); - - await mockRpcResponse({ - method: 'getAccountInfo', - params: [ - nonceAccount.publicKey.toBase58(), - {encoding: 'base64', commitment: 'confirmed'}, - ], - value: { - owner: '11111111111111111111111111111111', - lamports: minimumAmount, - data: expectedData(from.publicKey), - executable: false, - rentEpoch: 20, - }, - withContext: true, - }); - - const nonceAccountData = await connection.getNonce( - nonceAccount.publicKey, - 'confirmed', - ); - if (nonceAccountData === null) { - expect(nonceAccountData).not.to.be.null; - return; - } - expect(nonceAccountData.authorizedPubkey).to.eql(from.publicKey); - expect(bs58.decode(nonceAccountData.nonce).length).to.be.greaterThan(30); - }); - - it('create and query nonce account with seed', async () => { - const from = Keypair.generate(); - const seed = 'seed'; - const noncePubkey = await PublicKey.createWithSeed( - from.publicKey, - seed, - SystemProgram.programId, - ); - - await mockRpcResponse({ - method: 'getMinimumBalanceForRentExemption', - params: [NONCE_ACCOUNT_LENGTH], - value: 50, - }); - - const minimumAmount = - await connection.getMinimumBalanceForRentExemption(NONCE_ACCOUNT_LENGTH); - - await helpers.airdrop({ - connection, - address: from.publicKey, - amount: minimumAmount * 2, - }); - - const transaction = new Transaction().add( - SystemProgram.createNonceAccount({ - fromPubkey: from.publicKey, - noncePubkey: noncePubkey, - basePubkey: from.publicKey, - seed, - authorizedPubkey: from.publicKey, - lamports: minimumAmount, - }), - ); - - await helpers.processTransaction({ - connection, - transaction, - signers: [from], - commitment: 'confirmed', - }); - - await mockRpcResponse({ - method: 'getAccountInfo', - params: [ - noncePubkey.toBase58(), - {encoding: 'base64', commitment: 'confirmed'}, - ], - value: { - owner: '11111111111111111111111111111111', - lamports: minimumAmount, - data: expectedData(from.publicKey), - executable: false, - rentEpoch: 20, - }, - withContext: true, - }); - - const nonceAccountData = await connection.getNonce( - noncePubkey, - 'confirmed', - ); - if (nonceAccountData === null) { - expect(nonceAccountData).not.to.be.null; - return; - } - expect(nonceAccountData.authorizedPubkey).to.eql(from.publicKey); - expect(bs58.decode(nonceAccountData.nonce).length).to.be.greaterThan(30); - }); -}); diff --git a/packages/library-legacy/test/program-tests/address-lookup-table.test.ts b/packages/library-legacy/test/program-tests/address-lookup-table.test.ts deleted file mode 100644 index 3af70617948d..000000000000 --- a/packages/library-legacy/test/program-tests/address-lookup-table.test.ts +++ /dev/null @@ -1,268 +0,0 @@ -import {expect, use} from 'chai'; -import chaiAsPromised from 'chai-as-promised'; - -import { - Keypair, - AddressLookupTableProgram, - Transaction, - AddressLookupTableInstruction, - Connection, - sendAndConfirmTransaction, -} from '../../src'; -import {sleep} from '../../src/utils/sleep'; -import {helpers} from '../mocks/rpc-http'; -import {url} from '../url'; - -use(chaiAsPromised); - -describe('AddressLookupTableProgram', () => { - it('createAddressLookupTable', () => { - const recentSlot = 0; - const authorityPubkey = Keypair.generate().publicKey; - const payerPubkey = Keypair.generate().publicKey; - const [instruction] = AddressLookupTableProgram.createLookupTable({ - authority: authorityPubkey, - payer: payerPubkey, - recentSlot, - }); - - const transaction = new Transaction().add(instruction); - const createLutParams = { - authority: authorityPubkey, - payer: payerPubkey, - recentSlot, - }; - expect(transaction.instructions).to.have.length(1); - expect(createLutParams).to.eql( - AddressLookupTableInstruction.decodeCreateLookupTable(instruction), - ); - }); - - it('extendLookupTableWithPayer', () => { - const lutAddress = Keypair.generate().publicKey; - const authorityPubkey = Keypair.generate().publicKey; - const payerPubkey = Keypair.generate().publicKey; - - const addressesToAdd = [ - Keypair.generate().publicKey, - Keypair.generate().publicKey, - Keypair.generate().publicKey, - Keypair.generate().publicKey, - ]; - - const instruction = AddressLookupTableProgram.extendLookupTable({ - lookupTable: lutAddress, - authority: authorityPubkey, - payer: payerPubkey, - addresses: addressesToAdd, - }); - const transaction = new Transaction().add(instruction); - const extendLutParams = { - lookupTable: lutAddress, - authority: authorityPubkey, - payer: payerPubkey, - addresses: addressesToAdd, - }; - expect(transaction.instructions).to.have.length(1); - expect(extendLutParams).to.eql( - AddressLookupTableInstruction.decodeExtendLookupTable(instruction), - ); - }); - - it('extendLookupTableWithoutPayer', () => { - const lutAddress = Keypair.generate().publicKey; - const authorityPubkey = Keypair.generate().publicKey; - - const addressesToAdd = [ - Keypair.generate().publicKey, - Keypair.generate().publicKey, - Keypair.generate().publicKey, - Keypair.generate().publicKey, - ]; - - const instruction = AddressLookupTableProgram.extendLookupTable({ - lookupTable: lutAddress, - authority: authorityPubkey, - addresses: addressesToAdd, - }); - const transaction = new Transaction().add(instruction); - const extendLutParams = { - lookupTable: lutAddress, - authority: authorityPubkey, - payer: undefined, - addresses: addressesToAdd, - }; - expect(transaction.instructions).to.have.length(1); - expect(extendLutParams).to.eql( - AddressLookupTableInstruction.decodeExtendLookupTable(instruction), - ); - }); - - it('closeLookupTable', () => { - const lutAddress = Keypair.generate().publicKey; - const authorityPubkey = Keypair.generate().publicKey; - const recipientPubkey = Keypair.generate().publicKey; - - const instruction = AddressLookupTableProgram.closeLookupTable({ - lookupTable: lutAddress, - authority: authorityPubkey, - recipient: recipientPubkey, - }); - const transaction = new Transaction().add(instruction); - const closeLutParams = { - lookupTable: lutAddress, - authority: authorityPubkey, - recipient: recipientPubkey, - }; - expect(transaction.instructions).to.have.length(1); - expect(closeLutParams).to.eql( - AddressLookupTableInstruction.decodeCloseLookupTable(instruction), - ); - }); - - it('freezeLookupTable', () => { - const lutAddress = Keypair.generate().publicKey; - const authorityPubkey = Keypair.generate().publicKey; - - const instruction = AddressLookupTableProgram.freezeLookupTable({ - lookupTable: lutAddress, - authority: authorityPubkey, - }); - const transaction = new Transaction().add(instruction); - const freezeLutParams = { - lookupTable: lutAddress, - authority: authorityPubkey, - }; - expect(transaction.instructions).to.have.length(1); - expect(freezeLutParams).to.eql( - AddressLookupTableInstruction.decodeFreezeLookupTable(instruction), - ); - }); - - it('deactivateLookupTable', () => { - const lutAddress = Keypair.generate().publicKey; - const authorityPubkey = Keypair.generate().publicKey; - - const instruction = AddressLookupTableProgram.deactivateLookupTable({ - lookupTable: lutAddress, - authority: authorityPubkey, - }); - - const transaction = new Transaction().add(instruction); - const deactivateLutParams = { - lookupTable: lutAddress, - authority: authorityPubkey, - }; - expect(transaction.instructions).to.have.length(1); - expect(deactivateLutParams).to.eql( - AddressLookupTableInstruction.decodeDeactivateLookupTable(instruction), - ); - }); - - if (process.env.TEST_LIVE) { - it('live address lookup table actions', async () => { - const connection = new Connection(url, 'confirmed'); - const authority = Keypair.generate(); - const payer = Keypair.generate(); - - const [payerMinBalance, slot] = await Promise.all([ - connection.getMinimumBalanceForRentExemption(44 * 10), - connection.getSlot('confirmed'), - ]); - - const [createInstruction, lutAddress] = - AddressLookupTableProgram.createLookupTable({ - authority: authority.publicKey, - payer: payer.publicKey, - recentSlot: slot, - }); - - await Promise.all([ - helpers.airdrop({ - connection, - address: payer.publicKey, - amount: payerMinBalance, - }), - helpers.airdrop({ - connection, - address: authority.publicKey, - amount: payerMinBalance, - }), - ]); - - // Creating a new lut - const createLutTransaction = new Transaction(); - createLutTransaction.add(createInstruction); - createLutTransaction.feePayer = payer.publicKey; - - await sendAndConfirmTransaction( - connection, - createLutTransaction, - [authority, payer], - {preflightCommitment: 'confirmed'}, - ); - - await sleep(500); - - // Extending a lut without a payer - await helpers.airdrop({ - connection, - address: lutAddress, - amount: payerMinBalance, - }); - - const extendWithoutPayerInstruction = - AddressLookupTableProgram.extendLookupTable({ - lookupTable: lutAddress, - authority: authority.publicKey, - addresses: [...Array(10)].map(() => Keypair.generate().publicKey), - }); - const extendLutWithoutPayerTransaction = new Transaction(); - extendLutWithoutPayerTransaction.add(extendWithoutPayerInstruction); - - await sendAndConfirmTransaction( - connection, - extendLutWithoutPayerTransaction, - [authority], - {preflightCommitment: 'confirmed'}, - ); - - // Extending an lut with a payer - const extendWithPayerInstruction = - AddressLookupTableProgram.extendLookupTable({ - lookupTable: lutAddress, - authority: authority.publicKey, - payer: payer.publicKey, - addresses: [...Array(10)].map(() => Keypair.generate().publicKey), - }); - - const extendLutWithPayerTransaction = new Transaction(); - extendLutWithPayerTransaction.add(extendWithPayerInstruction); - - await sendAndConfirmTransaction( - connection, - extendLutWithPayerTransaction, - [authority, payer], - {preflightCommitment: 'confirmed'}, - ); - - //deactivating the lut - const deactivateInstruction = - AddressLookupTableProgram.deactivateLookupTable({ - lookupTable: lutAddress, - authority: authority.publicKey, - }); - - const deactivateLutTransaction = new Transaction(); - deactivateLutTransaction.add(deactivateInstruction); - await sendAndConfirmTransaction( - connection, - deactivateLutTransaction, - [authority], - {preflightCommitment: 'confirmed'}, - ); - - // After deactivation, LUTs can be closed *only* after a short perioid of time - }).timeout(10 * 1000); - } -}); diff --git a/packages/library-legacy/test/program-tests/compute-budget.test.ts b/packages/library-legacy/test/program-tests/compute-budget.test.ts deleted file mode 100644 index fb49aa122672..000000000000 --- a/packages/library-legacy/test/program-tests/compute-budget.test.ts +++ /dev/null @@ -1,177 +0,0 @@ -import {expect, use} from 'chai'; -import chaiAsPromised from 'chai-as-promised'; - -import { - Keypair, - Connection, - LAMPORTS_PER_SOL, - Transaction, - ComputeBudgetProgram, - ComputeBudgetInstruction, - sendAndConfirmTransaction, -} from '../../src'; -import {helpers} from '../mocks/rpc-http'; -import {url} from '../url'; - -use(chaiAsPromised); - -describe('ComputeBudgetProgram', () => { - it('requestUnits', () => { - const params = { - units: 150000, - additionalFee: LAMPORTS_PER_SOL, - }; - const ix = ComputeBudgetProgram.requestUnits(params); - const decodedParams = ComputeBudgetInstruction.decodeRequestUnits(ix); - expect(params).to.eql(decodedParams); - expect(ComputeBudgetInstruction.decodeInstructionType(ix)).to.eq( - 'RequestUnits', - ); - }); - - it('requestHeapFrame', () => { - const params = { - bytes: 33 * 1024, - }; - const ix = ComputeBudgetProgram.requestHeapFrame(params); - const decodedParams = ComputeBudgetInstruction.decodeRequestHeapFrame(ix); - expect(decodedParams).to.eql(params); - expect(ComputeBudgetInstruction.decodeInstructionType(ix)).to.eq( - 'RequestHeapFrame', - ); - }); - - it('setComputeUnitLimit', () => { - const params = { - units: 50_000, - }; - const ix = ComputeBudgetProgram.setComputeUnitLimit(params); - const decodedParams = - ComputeBudgetInstruction.decodeSetComputeUnitLimit(ix); - expect(decodedParams).to.eql(params); - expect(ComputeBudgetInstruction.decodeInstructionType(ix)).to.eq( - 'SetComputeUnitLimit', - ); - }); - - it('setComputeUnitPrice', () => { - const params = { - microLamports: 100_000, - }; - const ix = ComputeBudgetProgram.setComputeUnitPrice(params); - const expectedParams = { - ...params, - microLamports: BigInt(params.microLamports), - }; - const decodedParams = - ComputeBudgetInstruction.decodeSetComputeUnitPrice(ix); - expect(decodedParams).to.eql(expectedParams); - expect(ComputeBudgetInstruction.decodeInstructionType(ix)).to.eq( - 'SetComputeUnitPrice', - ); - }); - - if (process.env.TEST_LIVE) { - it('send live request heap ix', async () => { - const connection = new Connection(url, 'confirmed'); - const STARTING_AMOUNT = 2 * LAMPORTS_PER_SOL; - const baseAccount = Keypair.generate(); - const basePubkey = baseAccount.publicKey; - await helpers.airdrop({ - connection, - address: basePubkey, - amount: STARTING_AMOUNT, - }); - - async function expectRequestHeapFailure(bytes: number) { - const requestHeapFrameTransaction = new Transaction().add( - ComputeBudgetProgram.setComputeUnitLimit({units: 1_000_000}), - ComputeBudgetProgram.requestHeapFrame({bytes}), - ); - await expect( - sendAndConfirmTransaction( - connection, - requestHeapFrameTransaction, - [baseAccount], - {preflightCommitment: 'confirmed'}, - ), - ).to.be.rejectedWith(/invalid instruction data/); - } - const NOT_MULTIPLE_OF_1024 = 33 * 1024 + 1; - const BELOW_MIN = 1024; - const ABOVE_MAX = 257 * 1024; - await expectRequestHeapFailure(NOT_MULTIPLE_OF_1024); - await expectRequestHeapFailure(BELOW_MIN); - await expectRequestHeapFailure(ABOVE_MAX); - - const VALID_BYTES = 33 * 1024; - const requestHeapFrameTransaction = new Transaction().add( - ComputeBudgetProgram.setComputeUnitLimit({units: 1_000_000}), - ComputeBudgetProgram.requestHeapFrame({bytes: VALID_BYTES}), - ); - await sendAndConfirmTransaction( - connection, - requestHeapFrameTransaction, - [baseAccount], - {preflightCommitment: 'confirmed'}, - ); - }); - - it('send live compute unit ixs', async () => { - const connection = new Connection(url, 'confirmed'); - const FEE_AMOUNT = LAMPORTS_PER_SOL; - const STARTING_AMOUNT = 2 * LAMPORTS_PER_SOL; - const baseAccount = Keypair.generate(); - const basePubkey = baseAccount.publicKey; - await helpers.airdrop({ - connection, - address: basePubkey, - amount: STARTING_AMOUNT, - }); - - // lamport fee = 2B * 1M / 1M = 2 SOL - const prioritizationFeeTooHighTransaction = new Transaction() - .add( - ComputeBudgetProgram.setComputeUnitPrice({ - microLamports: 2_000_000_000, - }), - ) - .add( - ComputeBudgetProgram.setComputeUnitLimit({ - units: 1_000_000, - }), - ); - - await expect( - sendAndConfirmTransaction( - connection, - prioritizationFeeTooHighTransaction, - [baseAccount], - {preflightCommitment: 'confirmed'}, - ), - ).to.be.rejected; - - // lamport fee = 1B * 1M / 1M = 1 SOL - const validPrioritizationFeeTransaction = new Transaction() - .add( - ComputeBudgetProgram.setComputeUnitPrice({ - microLamports: 1_000_000_000, - }), - ) - .add( - ComputeBudgetProgram.setComputeUnitLimit({ - units: 1_000_000, - }), - ); - await sendAndConfirmTransaction( - connection, - validPrioritizationFeeTransaction, - [baseAccount], - {preflightCommitment: 'confirmed'}, - ); - expect(await connection.getBalance(baseAccount.publicKey)).to.be.at.most( - STARTING_AMOUNT - FEE_AMOUNT, - ); - }); - } -}); diff --git a/packages/library-legacy/test/program-tests/ed25519.test.ts b/packages/library-legacy/test/program-tests/ed25519.test.ts deleted file mode 100644 index 853dae6cf39a..000000000000 --- a/packages/library-legacy/test/program-tests/ed25519.test.ts +++ /dev/null @@ -1,54 +0,0 @@ -import {Buffer} from 'buffer'; - -import { - Connection, - Keypair, - sendAndConfirmTransaction, - LAMPORTS_PER_SOL, - Transaction, - Ed25519Program, -} from '../../src'; -import {sign} from '../../src/utils/ed25519'; -import {url} from '../url'; - -if (process.env.TEST_LIVE) { - describe('ed25519', () => { - const keypair = Keypair.generate(); - const privateKey = keypair.secretKey; - const publicKey = keypair.publicKey.toBytes(); - const from = Keypair.generate(); - const connection = new Connection(url, 'confirmed'); - - before(async function () { - await connection.confirmTransaction( - await connection.requestAirdrop(from.publicKey, 10 * LAMPORTS_PER_SOL), - ); - }); - - it('create ed25519 instruction', async () => { - const message = Buffer.from('string address'); - const signature = sign(message, privateKey); - const transaction = new Transaction().add( - Ed25519Program.createInstructionWithPublicKey({ - publicKey, - message, - signature, - }), - ); - - await sendAndConfirmTransaction(connection, transaction, [from]); - }); - - it('create ed25519 instruction with private key', async () => { - const message = Buffer.from('private key'); - const transaction = new Transaction().add( - Ed25519Program.createInstructionWithPrivateKey({ - privateKey, - message, - }), - ); - - await sendAndConfirmTransaction(connection, transaction, [from]); - }); - }); -} diff --git a/packages/library-legacy/test/program-tests/secp256k1.test.ts b/packages/library-legacy/test/program-tests/secp256k1.test.ts deleted file mode 100644 index 50f26c94637e..000000000000 --- a/packages/library-legacy/test/program-tests/secp256k1.test.ts +++ /dev/null @@ -1,120 +0,0 @@ -import {Buffer} from 'buffer'; -import {keccak_256} from '@noble/hashes/sha3'; - -import { - ecdsaSign, - isValidPrivateKey, - publicKeyCreate, -} from '../../src/utils/secp256k1'; -import { - Connection, - Keypair, - sendAndConfirmTransaction, - LAMPORTS_PER_SOL, - Transaction, - Secp256k1Program, -} from '../../src'; -import {url} from '../url'; - -const randomPrivateKey = () => { - let privateKey; - do { - privateKey = Keypair.generate().secretKey.slice(0, 32); - } while (!isValidPrivateKey(privateKey)); - return privateKey; -}; - -if (process.env.TEST_LIVE) { - describe('secp256k1', () => { - const privateKey = randomPrivateKey(); - const publicKey = publicKeyCreate( - privateKey, - false /* isCompressed */, - ).slice(1); - const ethAddress = Secp256k1Program.publicKeyToEthAddress(publicKey); - const from = Keypair.generate(); - const connection = new Connection(url, 'confirmed'); - - before(async function () { - await connection.confirmTransaction( - await connection.requestAirdrop(from.publicKey, 10 * LAMPORTS_PER_SOL), - ); - }); - - it('create secp256k1 instruction with string address', async () => { - const message = Buffer.from('string address'); - const messageHash = Buffer.from(keccak_256(message)); - const [signature, recoveryId] = ecdsaSign(messageHash, privateKey); - const transaction = new Transaction().add( - Secp256k1Program.createInstructionWithEthAddress({ - ethAddress: ethAddress.toString('hex'), - message, - signature, - recoveryId, - }), - ); - - await sendAndConfirmTransaction(connection, transaction, [from]); - }); - - it('create secp256k1 instruction with 0x prefix string address', async () => { - const message = Buffer.from('0x string address'); - const messageHash = Buffer.from(keccak_256(message)); - const [signature, recoveryId] = ecdsaSign(messageHash, privateKey); - const transaction = new Transaction().add( - Secp256k1Program.createInstructionWithEthAddress({ - ethAddress: '0x' + ethAddress.toString('hex'), - message, - signature, - recoveryId, - }), - ); - - await sendAndConfirmTransaction(connection, transaction, [from]); - }); - - it('create secp256k1 instruction with buffer address', async () => { - const message = Buffer.from('buffer address'); - const messageHash = Buffer.from(keccak_256(message)); - const [signature, recoveryId] = ecdsaSign(messageHash, privateKey); - const transaction = new Transaction().add( - Secp256k1Program.createInstructionWithEthAddress({ - ethAddress, - message, - signature, - recoveryId, - }), - ); - - await sendAndConfirmTransaction(connection, transaction, [from]); - }); - - it('create secp256k1 instruction with public key', async () => { - const message = Buffer.from('public key'); - const messageHash = Buffer.from(keccak_256(message)); - const [signature, recoveryId] = ecdsaSign(messageHash, privateKey); - const transaction = new Transaction().add( - Secp256k1Program.createInstructionWithPublicKey({ - publicKey, - message, - signature, - recoveryId, - }), - ); - - await sendAndConfirmTransaction(connection, transaction, [from]); - }); - - it('create secp256k1 instruction with private key', async () => { - const message = Buffer.from('private key'); - const transaction = new Transaction().add( - Secp256k1Program.createInstructionWithPrivateKey({ - privateKey, - message, - }), - ); - - await sendAndConfirmTransaction(connection, transaction, [from]); - }); - }); -} diff --git a/packages/library-legacy/test/program-tests/stake.test.ts b/packages/library-legacy/test/program-tests/stake.test.ts deleted file mode 100644 index 5cf2a0cef63e..000000000000 --- a/packages/library-legacy/test/program-tests/stake.test.ts +++ /dev/null @@ -1,734 +0,0 @@ -import {expect, use} from 'chai'; -import chaiAsPromised from 'chai-as-promised'; - -import { - Keypair, - Authorized, - Connection, - Lockup, - PublicKey, - sendAndConfirmTransaction, - LAMPORTS_PER_SOL, - StakeAuthorizationLayout, - StakeInstruction, - StakeProgram, - SystemInstruction, - Transaction, -} from '../../src'; -import {helpers} from '../mocks/rpc-http'; -import {url} from '../url'; - -use(chaiAsPromised); - -describe('StakeProgram', () => { - it('createAccountWithSeed', async () => { - const fromPubkey = Keypair.generate().publicKey; - const seed = 'test string'; - const newAccountPubkey = await PublicKey.createWithSeed( - fromPubkey, - seed, - StakeProgram.programId, - ); - const authorizedPubkey = Keypair.generate().publicKey; - const authorized = new Authorized(authorizedPubkey, authorizedPubkey); - const lockup = new Lockup(0, 0, fromPubkey); - const lamports = 123; - const transaction = StakeProgram.createAccountWithSeed({ - fromPubkey, - stakePubkey: newAccountPubkey, - basePubkey: fromPubkey, - seed, - authorized, - lockup, - lamports, - }); - expect(transaction.instructions).to.have.length(2); - const [systemInstruction, stakeInstruction] = transaction.instructions; - const systemParams = { - fromPubkey, - newAccountPubkey, - basePubkey: fromPubkey, - seed, - lamports, - space: StakeProgram.space, - programId: StakeProgram.programId, - }; - expect(systemParams).to.eql( - SystemInstruction.decodeCreateWithSeed(systemInstruction), - ); - const initParams = {stakePubkey: newAccountPubkey, authorized, lockup}; - expect(initParams).to.eql( - StakeInstruction.decodeInitialize(stakeInstruction), - ); - }); - - it('createAccount', () => { - const fromPubkey = Keypair.generate().publicKey; - const newAccountPubkey = Keypair.generate().publicKey; - const authorizedPubkey = Keypair.generate().publicKey; - const authorized = new Authorized(authorizedPubkey, authorizedPubkey); - const lockup = new Lockup(0, 0, fromPubkey); - const lamports = 123; - const transaction = StakeProgram.createAccount({ - fromPubkey, - stakePubkey: newAccountPubkey, - authorized, - lockup, - lamports, - }); - expect(transaction.instructions).to.have.length(2); - const [systemInstruction, stakeInstruction] = transaction.instructions; - const systemParams = { - fromPubkey, - newAccountPubkey, - lamports, - space: StakeProgram.space, - programId: StakeProgram.programId, - }; - expect(systemParams).to.eql( - SystemInstruction.decodeCreateAccount(systemInstruction), - ); - - const initParams = {stakePubkey: newAccountPubkey, authorized, lockup}; - expect(initParams).to.eql( - StakeInstruction.decodeInitialize(stakeInstruction), - ); - }); - - it('delegate', () => { - const stakePubkey = Keypair.generate().publicKey; - const authorizedPubkey = Keypair.generate().publicKey; - const votePubkey = Keypair.generate().publicKey; - const params = { - stakePubkey, - authorizedPubkey, - votePubkey, - }; - const transaction = StakeProgram.delegate(params); - expect(transaction.instructions).to.have.length(1); - const [stakeInstruction] = transaction.instructions; - expect(params).to.eql(StakeInstruction.decodeDelegate(stakeInstruction)); - }); - - it('authorize', () => { - const stakePubkey = Keypair.generate().publicKey; - const authorizedPubkey = Keypair.generate().publicKey; - const newAuthorizedPubkey = Keypair.generate().publicKey; - const stakeAuthorizationType = StakeAuthorizationLayout.Staker; - const params = { - stakePubkey, - authorizedPubkey, - newAuthorizedPubkey, - stakeAuthorizationType, - }; - const transaction = StakeProgram.authorize(params); - expect(transaction.instructions).to.have.length(1); - const [stakeInstruction] = transaction.instructions; - expect(params).to.eql(StakeInstruction.decodeAuthorize(stakeInstruction)); - }); - - it('authorize with custodian', () => { - const stakePubkey = Keypair.generate().publicKey; - const authorizedPubkey = Keypair.generate().publicKey; - const newAuthorizedPubkey = Keypair.generate().publicKey; - const stakeAuthorizationType = StakeAuthorizationLayout.Withdrawer; - const custodianPubkey = Keypair.generate().publicKey; - const params = { - stakePubkey, - authorizedPubkey, - newAuthorizedPubkey, - stakeAuthorizationType, - custodianPubkey, - }; - const transaction = StakeProgram.authorize(params); - expect(transaction.instructions).to.have.length(1); - const [stakeInstruction] = transaction.instructions; - expect(params).to.eql(StakeInstruction.decodeAuthorize(stakeInstruction)); - }); - - it('authorizeWithSeed', () => { - const stakePubkey = Keypair.generate().publicKey; - const authorityBase = Keypair.generate().publicKey; - const authoritySeed = 'test string'; - const authorityOwner = Keypair.generate().publicKey; - const newAuthorizedPubkey = Keypair.generate().publicKey; - const stakeAuthorizationType = StakeAuthorizationLayout.Staker; - const params = { - stakePubkey, - authorityBase, - authoritySeed, - authorityOwner, - newAuthorizedPubkey, - stakeAuthorizationType, - }; - const transaction = StakeProgram.authorizeWithSeed(params); - expect(transaction.instructions).to.have.length(1); - const [stakeInstruction] = transaction.instructions; - expect(params).to.eql( - StakeInstruction.decodeAuthorizeWithSeed(stakeInstruction), - ); - }); - - it('authorizeWithSeed with custodian', () => { - const stakePubkey = Keypair.generate().publicKey; - const authorityBase = Keypair.generate().publicKey; - const authoritySeed = 'test string'; - const authorityOwner = Keypair.generate().publicKey; - const newAuthorizedPubkey = Keypair.generate().publicKey; - const stakeAuthorizationType = StakeAuthorizationLayout.Staker; - const custodianPubkey = Keypair.generate().publicKey; - const params = { - stakePubkey, - authorityBase, - authoritySeed, - authorityOwner, - newAuthorizedPubkey, - stakeAuthorizationType, - custodianPubkey, - }; - const transaction = StakeProgram.authorizeWithSeed(params); - expect(transaction.instructions).to.have.length(1); - const [stakeInstruction] = transaction.instructions; - expect(params).to.eql( - StakeInstruction.decodeAuthorizeWithSeed(stakeInstruction), - ); - }); - - it('split', () => { - const stakePubkey = Keypair.generate().publicKey; - const authorizedPubkey = Keypair.generate().publicKey; - const splitStakePubkey = Keypair.generate().publicKey; - const params = { - stakePubkey, - authorizedPubkey, - splitStakePubkey, - lamports: 123, - }; - const transaction = StakeProgram.split(params, 123 /* rentExemptReserve */); - expect(transaction.instructions).to.have.length(2); - const [systemInstruction, stakeInstruction] = transaction.instructions; - const systemParams = { - fromPubkey: authorizedPubkey, - newAccountPubkey: splitStakePubkey, - lamports: 123, - space: StakeProgram.space, - programId: StakeProgram.programId, - }; - expect(systemParams).to.eql( - SystemInstruction.decodeCreateAccount(systemInstruction), - ); - expect(params).to.eql(StakeInstruction.decodeSplit(stakeInstruction)); - }); - - [0, undefined, 456].forEach(rentExemptReserve => { - it(`splitWithSeed (rent reserve: ${rentExemptReserve})`, async () => { - const stakePubkey = Keypair.generate().publicKey; - const authorizedPubkey = Keypair.generate().publicKey; - const lamports = 123; - const seed = 'test string'; - const basePubkey = Keypair.generate().publicKey; - const splitStakePubkey = await PublicKey.createWithSeed( - basePubkey, - seed, - StakeProgram.programId, - ); - const transaction = StakeProgram.splitWithSeed( - { - stakePubkey, - authorizedPubkey, - lamports, - splitStakePubkey, - basePubkey, - seed, - }, - rentExemptReserve, - ); - const hasRentReserve = rentExemptReserve && rentExemptReserve > 0; - expect(transaction.instructions).to.have.length(hasRentReserve ? 3 : 2); - const allocateInstruction = transaction.instructions[0]; - const splitInstruction = transaction.instructions[hasRentReserve ? 2 : 1]; - const transferInstruction = hasRentReserve - ? transaction.instructions[1] - : undefined; - const allocateParams = { - accountPubkey: splitStakePubkey, - basePubkey, - seed, - space: StakeProgram.space, - programId: StakeProgram.programId, - }; - expect(allocateParams).to.eql( - SystemInstruction.decodeAllocateWithSeed(allocateInstruction), - ); - if (hasRentReserve) { - const transferParams = { - fromPubkey: authorizedPubkey, - toPubkey: splitStakePubkey, - lamports: 456n, - }; - expect(transferParams).to.eql( - SystemInstruction.decodeTransfer(transferInstruction!), - ); - } - const splitParams = { - stakePubkey, - authorizedPubkey, - splitStakePubkey, - lamports, - }; - expect(splitParams).to.eql( - StakeInstruction.decodeSplit(splitInstruction), - ); - }); - }); - - it('merge', () => { - const stakePubkey = Keypair.generate().publicKey; - const sourceStakePubKey = Keypair.generate().publicKey; - const authorizedPubkey = Keypair.generate().publicKey; - const params = { - stakePubkey, - sourceStakePubKey, - authorizedPubkey, - }; - const transaction = StakeProgram.merge(params); - expect(transaction.instructions).to.have.length(1); - const [stakeInstruction] = transaction.instructions; - expect(params).to.eql(StakeInstruction.decodeMerge(stakeInstruction)); - }); - - it('withdraw', () => { - const stakePubkey = Keypair.generate().publicKey; - const authorizedPubkey = Keypair.generate().publicKey; - const toPubkey = Keypair.generate().publicKey; - const params = { - stakePubkey, - authorizedPubkey, - toPubkey, - lamports: 123, - }; - const transaction = StakeProgram.withdraw(params); - expect(transaction.instructions).to.have.length(1); - const [stakeInstruction] = transaction.instructions; - expect(params).to.eql(StakeInstruction.decodeWithdraw(stakeInstruction)); - }); - - it('withdraw with custodian', () => { - const stakePubkey = Keypair.generate().publicKey; - const authorizedPubkey = Keypair.generate().publicKey; - const toPubkey = Keypair.generate().publicKey; - const custodianPubkey = Keypair.generate().publicKey; - const params = { - stakePubkey, - authorizedPubkey, - toPubkey, - lamports: 123, - custodianPubkey, - }; - const transaction = StakeProgram.withdraw(params); - expect(transaction.instructions).to.have.length(1); - const [stakeInstruction] = transaction.instructions; - expect(params).to.eql(StakeInstruction.decodeWithdraw(stakeInstruction)); - }); - - it('deactivate', () => { - const stakePubkey = Keypair.generate().publicKey; - const authorizedPubkey = Keypair.generate().publicKey; - const params = {stakePubkey, authorizedPubkey}; - const transaction = StakeProgram.deactivate(params); - expect(transaction.instructions).to.have.length(1); - const [stakeInstruction] = transaction.instructions; - expect(params).to.eql(StakeInstruction.decodeDeactivate(stakeInstruction)); - }); - - it('StakeInstructions', async () => { - const from = Keypair.generate(); - const seed = 'test string'; - const newAccountPubkey = await PublicKey.createWithSeed( - from.publicKey, - seed, - StakeProgram.programId, - ); - const authorized = Keypair.generate(); - const amount = 123; - const recentBlockhash = 'EETubP5AKHgjPAhzPAFcb8BAY1hMH639CWCFTqi3hq1k'; // Arbitrary known recentBlockhash - const createWithSeed = StakeProgram.createAccountWithSeed({ - fromPubkey: from.publicKey, - stakePubkey: newAccountPubkey, - basePubkey: from.publicKey, - seed, - authorized: new Authorized(authorized.publicKey, authorized.publicKey), - lockup: new Lockup(0, 0, from.publicKey), - lamports: amount, - }); - const createWithSeedTransaction = new Transaction({ - blockhash: recentBlockhash, - lastValidBlockHeight: 9999, - }).add(createWithSeed); - - expect(createWithSeedTransaction.instructions).to.have.length(2); - const systemInstructionType = SystemInstruction.decodeInstructionType( - createWithSeedTransaction.instructions[0], - ); - expect(systemInstructionType).to.eq('CreateWithSeed'); - - const stakeInstructionType = StakeInstruction.decodeInstructionType( - createWithSeedTransaction.instructions[1], - ); - expect(stakeInstructionType).to.eq('Initialize'); - - expect(() => { - StakeInstruction.decodeInstructionType( - createWithSeedTransaction.instructions[0], - ); - }).to.throw(); - - const stake = Keypair.generate(); - const vote = Keypair.generate(); - const delegate = StakeProgram.delegate({ - stakePubkey: stake.publicKey, - authorizedPubkey: authorized.publicKey, - votePubkey: vote.publicKey, - }); - - const delegateTransaction = new Transaction({ - blockhash: recentBlockhash, - lastValidBlockHeight: 9999, - }).add(delegate); - const anotherStakeInstructionType = StakeInstruction.decodeInstructionType( - delegateTransaction.instructions[0], - ); - expect(anotherStakeInstructionType).to.eq('Delegate'); - }); - - if (process.env.TEST_LIVE) { - it('live staking actions', async () => { - const connection = new Connection(url, 'confirmed'); - const [ - SYSTEM_ACCOUNT_MIN_BALANCE, - STAKE_ACCOUNT_MIN_BALANCE, - {value: MIN_STAKE_DELEGATION}, - ] = await Promise.all([ - connection.getMinimumBalanceForRentExemption(0), - connection.getMinimumBalanceForRentExemption(StakeProgram.space), - connection.getStakeMinimumDelegation(), - ]); - - const voteAccounts = await connection.getVoteAccounts(); - const voteAccount = voteAccounts.current.concat( - voteAccounts.delinquent, - )[0]; - const votePubkey = new PublicKey(voteAccount.votePubkey); - - const payer = Keypair.generate(); - await helpers.airdrop({ - connection, - address: payer.publicKey, - amount: 10 * LAMPORTS_PER_SOL, - }); - - const authorized = Keypair.generate(); - await helpers.airdrop({ - connection, - address: authorized.publicKey, - amount: 2 * LAMPORTS_PER_SOL, - }); - - const recipient = Keypair.generate(); - await helpers.airdrop({ - connection, - address: recipient.publicKey, - amount: SYSTEM_ACCOUNT_MIN_BALANCE, - }); - - { - // Create Stake account without seed - const newStakeAccount = Keypair.generate(); - let createAndInitialize = StakeProgram.createAccount({ - fromPubkey: payer.publicKey, - stakePubkey: newStakeAccount.publicKey, - authorized: new Authorized( - authorized.publicKey, - authorized.publicKey, - ), - lamports: STAKE_ACCOUNT_MIN_BALANCE + MIN_STAKE_DELEGATION, - }); - - await sendAndConfirmTransaction( - connection, - createAndInitialize, - [payer, newStakeAccount], - {preflightCommitment: 'confirmed'}, - ); - expect(await connection.getBalance(newStakeAccount.publicKey)).to.eq( - STAKE_ACCOUNT_MIN_BALANCE + MIN_STAKE_DELEGATION, - ); - - const delegation = StakeProgram.delegate({ - stakePubkey: newStakeAccount.publicKey, - authorizedPubkey: authorized.publicKey, - votePubkey, - }); - await sendAndConfirmTransaction(connection, delegation, [authorized], { - commitment: 'confirmed', - }); - } - - // Create Stake account with seed - const seed = 'test string'; - const newAccountPubkey = await PublicKey.createWithSeed( - payer.publicKey, - seed, - StakeProgram.programId, - ); - - const WITHDRAW_AMOUNT = 1; - const INITIAL_STAKE_DELEGATION = 5 * LAMPORTS_PER_SOL; - let createAndInitializeWithSeed = StakeProgram.createAccountWithSeed({ - fromPubkey: payer.publicKey, - stakePubkey: newAccountPubkey, - basePubkey: payer.publicKey, - seed, - authorized: new Authorized(authorized.publicKey, authorized.publicKey), - lockup: new Lockup(0, 0, new PublicKey(0)), - lamports: STAKE_ACCOUNT_MIN_BALANCE + INITIAL_STAKE_DELEGATION, - }); - - await sendAndConfirmTransaction( - connection, - createAndInitializeWithSeed, - [payer], - {preflightCommitment: 'confirmed'}, - ); - let originalStakeBalance = await connection.getBalance(newAccountPubkey); - expect(originalStakeBalance).to.eq( - STAKE_ACCOUNT_MIN_BALANCE + INITIAL_STAKE_DELEGATION, - ); - - let delegation = StakeProgram.delegate({ - stakePubkey: newAccountPubkey, - authorizedPubkey: authorized.publicKey, - votePubkey, - }); - await sendAndConfirmTransaction(connection, delegation, [authorized], { - preflightCommitment: 'confirmed', - }); - - // Test that withdraw fails before deactivation - let withdraw = StakeProgram.withdraw({ - stakePubkey: newAccountPubkey, - authorizedPubkey: authorized.publicKey, - toPubkey: recipient.publicKey, - lamports: WITHDRAW_AMOUNT, - }); - await expect( - sendAndConfirmTransaction(connection, withdraw, [authorized], { - preflightCommitment: 'confirmed', - }), - ).to.be.rejected; - - // Deactivate stake - let deactivate = StakeProgram.deactivate({ - stakePubkey: newAccountPubkey, - authorizedPubkey: authorized.publicKey, - }); - await sendAndConfirmTransaction(connection, deactivate, [authorized], { - preflightCommitment: 'confirmed', - }); - - let stakeActivationState; - do { - stakeActivationState = - await connection.getStakeActivation(newAccountPubkey); - } while (stakeActivationState.state != 'inactive'); - - // Test that withdraw succeeds after deactivation - withdraw = StakeProgram.withdraw({ - stakePubkey: newAccountPubkey, - authorizedPubkey: authorized.publicKey, - toPubkey: recipient.publicKey, - lamports: WITHDRAW_AMOUNT, - }); - - await sendAndConfirmTransaction(connection, withdraw, [authorized], { - preflightCommitment: 'confirmed', - }); - const recipientBalance = await connection.getBalance(recipient.publicKey); - expect(recipientBalance).to.eq( - SYSTEM_ACCOUNT_MIN_BALANCE + WITHDRAW_AMOUNT, - ); - - // Split stake - const newStake = Keypair.generate(); - let split = StakeProgram.split( - { - stakePubkey: newAccountPubkey, - authorizedPubkey: authorized.publicKey, - splitStakePubkey: newStake.publicKey, - lamports: MIN_STAKE_DELEGATION, - }, - STAKE_ACCOUNT_MIN_BALANCE, - ); - await sendAndConfirmTransaction( - connection, - split, - [authorized, newStake], - { - preflightCommitment: 'confirmed', - }, - ); - const balance = await connection.getBalance(newStake.publicKey); - expect(balance).to.eq(STAKE_ACCOUNT_MIN_BALANCE + MIN_STAKE_DELEGATION); - - // Split stake with seed - const seed2 = 'test string 2'; - const newStake2 = await PublicKey.createWithSeed( - payer.publicKey, - seed2, - StakeProgram.programId, - ); - let splitWithSeed = StakeProgram.splitWithSeed( - { - stakePubkey: newAccountPubkey, - authorizedPubkey: authorized.publicKey, - lamports: MIN_STAKE_DELEGATION, - splitStakePubkey: newStake2, - basePubkey: payer.publicKey, - seed: seed2, - }, - STAKE_ACCOUNT_MIN_BALANCE, - ); - await sendAndConfirmTransaction( - connection, - splitWithSeed, - [payer, authorized], - { - preflightCommitment: 'confirmed', - }, - ); - expect(await connection.getBalance(newStake2)).to.eq( - STAKE_ACCOUNT_MIN_BALANCE + MIN_STAKE_DELEGATION, - ); - - // Merge stake - const preMergeBalance = await connection.getBalance(newAccountPubkey); - let merge = StakeProgram.merge({ - stakePubkey: newAccountPubkey, - sourceStakePubKey: newStake.publicKey, - authorizedPubkey: authorized.publicKey, - }); - await sendAndConfirmTransaction(connection, merge, [authorized], { - preflightCommitment: 'confirmed', - }); - const postMergeBalance = await connection.getBalance(newAccountPubkey); - expect(postMergeBalance - preMergeBalance).to.eq( - STAKE_ACCOUNT_MIN_BALANCE + MIN_STAKE_DELEGATION, - ); - - // Resplit - split = StakeProgram.split( - { - stakePubkey: newAccountPubkey, - authorizedPubkey: authorized.publicKey, - splitStakePubkey: newStake.publicKey, - // use a different amount than the first split so that this - // transaction is different and won't require a fresh blockhash - lamports: MIN_STAKE_DELEGATION, - }, - STAKE_ACCOUNT_MIN_BALANCE, - ); - await sendAndConfirmTransaction( - connection, - split, - [authorized, newStake], - { - preflightCommitment: 'confirmed', - }, - ); - - // Authorize to new account - const newAuthorized = Keypair.generate(); - await connection.requestAirdrop( - newAuthorized.publicKey, - LAMPORTS_PER_SOL, - ); - - let authorize = StakeProgram.authorize({ - stakePubkey: newAccountPubkey, - authorizedPubkey: authorized.publicKey, - newAuthorizedPubkey: newAuthorized.publicKey, - stakeAuthorizationType: StakeAuthorizationLayout.Withdrawer, - }); - await sendAndConfirmTransaction(connection, authorize, [authorized], { - preflightCommitment: 'confirmed', - }); - authorize = StakeProgram.authorize({ - stakePubkey: newAccountPubkey, - authorizedPubkey: authorized.publicKey, - newAuthorizedPubkey: newAuthorized.publicKey, - stakeAuthorizationType: StakeAuthorizationLayout.Staker, - }); - await sendAndConfirmTransaction(connection, authorize, [authorized], { - preflightCommitment: 'confirmed', - }); - - // Test old authorized can't delegate - let delegateNotAuthorized = StakeProgram.delegate({ - stakePubkey: newAccountPubkey, - authorizedPubkey: authorized.publicKey, - votePubkey, - }); - await expect( - sendAndConfirmTransaction( - connection, - delegateNotAuthorized, - [authorized], - { - preflightCommitment: 'confirmed', - }, - ), - ).to.be.rejected; - - // Test accounts with different authorities can't be merged - let mergeNotAuthorized = StakeProgram.merge({ - stakePubkey: newStake.publicKey, - sourceStakePubKey: newAccountPubkey, - authorizedPubkey: authorized.publicKey, - }); - await expect( - sendAndConfirmTransaction( - connection, - mergeNotAuthorized, - [authorized], - { - preflightCommitment: 'confirmed', - }, - ), - ).to.be.rejected; - - // Authorize a derived address - authorize = StakeProgram.authorize({ - stakePubkey: newAccountPubkey, - authorizedPubkey: newAuthorized.publicKey, - newAuthorizedPubkey: newAccountPubkey, - stakeAuthorizationType: StakeAuthorizationLayout.Withdrawer, - }); - await sendAndConfirmTransaction(connection, authorize, [newAuthorized], { - preflightCommitment: 'confirmed', - }); - - // Restore the previous authority using a derived address - authorize = StakeProgram.authorizeWithSeed({ - stakePubkey: newAccountPubkey, - authorityBase: payer.publicKey, - authoritySeed: seed, - authorityOwner: StakeProgram.programId, - newAuthorizedPubkey: newAuthorized.publicKey, - stakeAuthorizationType: StakeAuthorizationLayout.Withdrawer, - }); - await sendAndConfirmTransaction(connection, authorize, [payer], { - preflightCommitment: 'confirmed', - }); - }).timeout(10 * 1000); - } -}); diff --git a/packages/library-legacy/test/program-tests/system.test.ts b/packages/library-legacy/test/program-tests/system.test.ts deleted file mode 100644 index 089cba09e4d1..000000000000 --- a/packages/library-legacy/test/program-tests/system.test.ts +++ /dev/null @@ -1,625 +0,0 @@ -import {Buffer} from 'buffer'; -import {expect} from 'chai'; - -import { - Keypair, - Connection, - PublicKey, - StakeProgram, - SystemInstruction, - SystemProgram, - Transaction, - TransactionInstruction, - sendAndConfirmTransaction, - LAMPORTS_PER_SOL, -} from '../../src'; -import {NONCE_ACCOUNT_LENGTH} from '../../src/nonce-account'; -import {sleep} from '../../src/utils/sleep'; -import {helpers} from '../mocks/rpc-http'; -import {url} from '../url'; - -describe('SystemProgram', () => { - it('createAccount', () => { - const params = { - fromPubkey: Keypair.generate().publicKey, - newAccountPubkey: Keypair.generate().publicKey, - lamports: 123, - space: 0, - programId: SystemProgram.programId, - }; - const transaction = new Transaction().add( - SystemProgram.createAccount(params), - ); - expect(transaction.instructions).to.have.length(1); - const [systemInstruction] = transaction.instructions; - expect(params).to.eql( - SystemInstruction.decodeCreateAccount(systemInstruction), - ); - }); - - it('transfer', () => { - const params = { - fromPubkey: Keypair.generate().publicKey, - toPubkey: Keypair.generate().publicKey, - lamports: 123, - }; - const transaction = new Transaction().add(SystemProgram.transfer(params)); - expect(transaction.instructions).to.have.length(1); - const [systemInstruction] = transaction.instructions; - const decodedParams = { - ...params, - lamports: BigInt(params.lamports), - }; - expect(decodedParams).to.eql( - SystemInstruction.decodeTransfer(systemInstruction), - ); - }); - - it('transferWithSeed', () => { - const params = { - fromPubkey: Keypair.generate().publicKey, - basePubkey: Keypair.generate().publicKey, - toPubkey: Keypair.generate().publicKey, - lamports: 123, - seed: '你好', - programId: Keypair.generate().publicKey, - }; - const transaction = new Transaction().add(SystemProgram.transfer(params)); - expect(transaction.instructions).to.have.length(1); - const [systemInstruction] = transaction.instructions; - const decodedParams = { - ...params, - lamports: BigInt(params.lamports), - }; - expect(decodedParams).to.eql( - SystemInstruction.decodeTransferWithSeed(systemInstruction), - ); - }); - - it('allocate', () => { - const params = { - accountPubkey: Keypair.generate().publicKey, - space: 42, - }; - const transaction = new Transaction().add(SystemProgram.allocate(params)); - expect(transaction.instructions).to.have.length(1); - const [systemInstruction] = transaction.instructions; - expect(params).to.eql(SystemInstruction.decodeAllocate(systemInstruction)); - }); - - it('allocateWithSeed', () => { - const params = { - accountPubkey: Keypair.generate().publicKey, - basePubkey: Keypair.generate().publicKey, - seed: '你好', - space: 42, - programId: Keypair.generate().publicKey, - }; - const transaction = new Transaction().add(SystemProgram.allocate(params)); - expect(transaction.instructions).to.have.length(1); - const [systemInstruction] = transaction.instructions; - expect(params).to.eql( - SystemInstruction.decodeAllocateWithSeed(systemInstruction), - ); - }); - - it('assign', () => { - const params = { - accountPubkey: Keypair.generate().publicKey, - programId: Keypair.generate().publicKey, - }; - const transaction = new Transaction().add(SystemProgram.assign(params)); - expect(transaction.instructions).to.have.length(1); - const [systemInstruction] = transaction.instructions; - expect(params).to.eql(SystemInstruction.decodeAssign(systemInstruction)); - }); - - it('assignWithSeed', () => { - const params = { - accountPubkey: Keypair.generate().publicKey, - basePubkey: Keypair.generate().publicKey, - seed: '你好', - programId: Keypair.generate().publicKey, - }; - const transaction = new Transaction().add(SystemProgram.assign(params)); - expect(transaction.instructions).to.have.length(1); - const [systemInstruction] = transaction.instructions; - expect(params).to.eql( - SystemInstruction.decodeAssignWithSeed(systemInstruction), - ); - }); - - it('createAccountWithSeed', () => { - const fromPubkey = Keypair.generate().publicKey; - const params = { - fromPubkey, - newAccountPubkey: Keypair.generate().publicKey, - basePubkey: fromPubkey, - seed: 'hi there', - lamports: 123, - space: 0, - programId: SystemProgram.programId, - }; - const transaction = new Transaction().add( - SystemProgram.createAccountWithSeed(params), - ); - expect(transaction.instructions).to.have.length(1); - const [systemInstruction] = transaction.instructions; - expect(params).to.eql( - SystemInstruction.decodeCreateWithSeed(systemInstruction), - ); - }); - - it('createNonceAccount', () => { - const fromPubkey = Keypair.generate().publicKey; - const params = { - fromPubkey, - noncePubkey: Keypair.generate().publicKey, - authorizedPubkey: fromPubkey, - lamports: 123, - }; - - const transaction = new Transaction().add( - SystemProgram.createNonceAccount(params), - ); - expect(transaction.instructions).to.have.length(2); - const [createInstruction, initInstruction] = transaction.instructions; - - const createParams = { - fromPubkey: params.fromPubkey, - newAccountPubkey: params.noncePubkey, - lamports: params.lamports, - space: NONCE_ACCOUNT_LENGTH, - programId: SystemProgram.programId, - }; - expect(createParams).to.eql( - SystemInstruction.decodeCreateAccount(createInstruction), - ); - - const initParams = { - noncePubkey: params.noncePubkey, - authorizedPubkey: fromPubkey, - }; - expect(initParams).to.eql( - SystemInstruction.decodeNonceInitialize(initInstruction), - ); - }); - - it('createNonceAccount with seed', () => { - const fromPubkey = Keypair.generate().publicKey; - const params = { - fromPubkey, - noncePubkey: Keypair.generate().publicKey, - authorizedPubkey: fromPubkey, - basePubkey: fromPubkey, - seed: 'hi there', - lamports: 123, - }; - - const transaction = new Transaction().add( - SystemProgram.createNonceAccount(params), - ); - expect(transaction.instructions).to.have.length(2); - const [createInstruction, initInstruction] = transaction.instructions; - - const createParams = { - fromPubkey: params.fromPubkey, - newAccountPubkey: params.noncePubkey, - basePubkey: fromPubkey, - seed: 'hi there', - lamports: params.lamports, - space: NONCE_ACCOUNT_LENGTH, - programId: SystemProgram.programId, - }; - expect(createParams).to.eql( - SystemInstruction.decodeCreateWithSeed(createInstruction), - ); - - const initParams = { - noncePubkey: params.noncePubkey, - authorizedPubkey: fromPubkey, - }; - expect(initParams).to.eql( - SystemInstruction.decodeNonceInitialize(initInstruction), - ); - }); - - it('nonceAdvance', () => { - const params = { - noncePubkey: Keypair.generate().publicKey, - authorizedPubkey: Keypair.generate().publicKey, - }; - const instruction = SystemProgram.nonceAdvance(params); - expect(params).to.eql(SystemInstruction.decodeNonceAdvance(instruction)); - }); - - it('nonceWithdraw', () => { - const params = { - noncePubkey: Keypair.generate().publicKey, - authorizedPubkey: Keypair.generate().publicKey, - toPubkey: Keypair.generate().publicKey, - lamports: 123, - }; - const transaction = new Transaction().add( - SystemProgram.nonceWithdraw(params), - ); - expect(transaction.instructions).to.have.length(1); - const [instruction] = transaction.instructions; - expect(params).to.eql(SystemInstruction.decodeNonceWithdraw(instruction)); - }); - - it('nonceAuthorize', () => { - const params = { - noncePubkey: Keypair.generate().publicKey, - authorizedPubkey: Keypair.generate().publicKey, - newAuthorizedPubkey: Keypair.generate().publicKey, - }; - - const transaction = new Transaction().add( - SystemProgram.nonceAuthorize(params), - ); - expect(transaction.instructions).to.have.length(1); - const [instruction] = transaction.instructions; - expect(params).to.eql(SystemInstruction.decodeNonceAuthorize(instruction)); - }); - - it('non-SystemInstruction error', () => { - const from = Keypair.generate(); - const to = Keypair.generate(); - - const badProgramId = { - keys: [ - {pubkey: from.publicKey, isSigner: true, isWritable: true}, - {pubkey: to.publicKey, isSigner: false, isWritable: true}, - ], - programId: StakeProgram.programId, - data: Buffer.from([2, 0, 0, 0]), - }; - expect(() => { - SystemInstruction.decodeInstructionType( - new TransactionInstruction(badProgramId), - ); - }).to.throw(); - - const stakePubkey = Keypair.generate().publicKey; - const authorizedPubkey = Keypair.generate().publicKey; - const params = {stakePubkey, authorizedPubkey}; - const transaction = StakeProgram.deactivate(params); - - expect(() => { - SystemInstruction.decodeInstructionType(transaction.instructions[1]); - }).to.throw(); - - transaction.instructions[0].data[0] = 11; - expect(() => { - SystemInstruction.decodeInstructionType(transaction.instructions[0]); - }).to.throw(); - }); - - if (process.env.TEST_LIVE) { - it('live Nonce actions', async () => { - const connection = new Connection(url, 'confirmed'); - const nonceAccount = Keypair.generate(); - const from = Keypair.generate(); - await helpers.airdrop({ - connection, - address: from.publicKey, - amount: 2 * LAMPORTS_PER_SOL, - }); - - const to = Keypair.generate(); - const newAuthority = Keypair.generate(); - await helpers.airdrop({ - connection, - address: newAuthority.publicKey, - amount: LAMPORTS_PER_SOL, - }); - - const minimumAmount = - await connection.getMinimumBalanceForRentExemption( - NONCE_ACCOUNT_LENGTH, - ); - - let createNonceAccount = new Transaction().add( - SystemProgram.createNonceAccount({ - fromPubkey: from.publicKey, - noncePubkey: nonceAccount.publicKey, - authorizedPubkey: from.publicKey, - lamports: minimumAmount, - }), - ); - await sendAndConfirmTransaction( - connection, - createNonceAccount, - [from, nonceAccount], - {preflightCommitment: 'confirmed'}, - ); - const nonceBalance = await connection.getBalance(nonceAccount.publicKey); - expect(nonceBalance).to.eq(minimumAmount); - - const nonceQuery1 = await connection.getNonce(nonceAccount.publicKey); - if (nonceQuery1 === null) { - expect(nonceQuery1).not.to.be.null; - return; - } - - const nonceQuery2 = await connection.getNonce(nonceAccount.publicKey); - if (nonceQuery2 === null) { - expect(nonceQuery2).not.to.be.null; - return; - } - - expect(nonceQuery1.nonce).to.eq(nonceQuery2.nonce); - - // Wait for blockhash to advance - await sleep(500); - - const advanceNonce = new Transaction().add( - SystemProgram.nonceAdvance({ - noncePubkey: nonceAccount.publicKey, - authorizedPubkey: from.publicKey, - }), - ); - await sendAndConfirmTransaction(connection, advanceNonce, [from], { - preflightCommitment: 'confirmed', - }); - const nonceQuery3 = await connection.getNonce(nonceAccount.publicKey); - if (nonceQuery3 === null) { - expect(nonceQuery3).not.to.be.null; - return; - } - expect(nonceQuery1.nonce).not.to.eq(nonceQuery3.nonce); - const nonce = nonceQuery3.nonce; - - // Wait for blockhash to advance - await sleep(500); - - const authorizeNonce = new Transaction().add( - SystemProgram.nonceAuthorize({ - noncePubkey: nonceAccount.publicKey, - authorizedPubkey: from.publicKey, - newAuthorizedPubkey: newAuthority.publicKey, - }), - ); - await sendAndConfirmTransaction(connection, authorizeNonce, [from], { - preflightCommitment: 'confirmed', - }); - - let transfer = new Transaction().add( - SystemProgram.transfer({ - fromPubkey: from.publicKey, - toPubkey: to.publicKey, - lamports: minimumAmount, - }), - ); - transfer.nonceInfo = { - nonce, - nonceInstruction: SystemProgram.nonceAdvance({ - noncePubkey: nonceAccount.publicKey, - authorizedPubkey: newAuthority.publicKey, - }), - }; - - await sendAndConfirmTransaction( - connection, - transfer, - [from, newAuthority], - { - preflightCommitment: 'confirmed', - }, - ); - const toBalance = await connection.getBalance(to.publicKey); - expect(toBalance).to.eq(minimumAmount); - - // Wait for blockhash to advance - await sleep(500); - - const withdrawAccount = Keypair.generate(); - const withdrawNonce = new Transaction().add( - SystemProgram.nonceWithdraw({ - noncePubkey: nonceAccount.publicKey, - authorizedPubkey: newAuthority.publicKey, - lamports: minimumAmount, - toPubkey: withdrawAccount.publicKey, - }), - ); - await sendAndConfirmTransaction( - connection, - withdrawNonce, - [newAuthority], - { - preflightCommitment: 'confirmed', - }, - ); - expect(await connection.getBalance(nonceAccount.publicKey)).to.eq(0); - const withdrawBalance = await connection.getBalance( - withdrawAccount.publicKey, - ); - expect(withdrawBalance).to.eq(minimumAmount); - }).timeout(10 * 1000); - - it('live withSeed actions', async () => { - const connection = new Connection(url, 'confirmed'); - const baseAccount = Keypair.generate(); - await helpers.airdrop({ - connection, - address: baseAccount.publicKey, - amount: 2 * LAMPORTS_PER_SOL, - }); - const basePubkey = baseAccount.publicKey; - const seed = 'hi there'; - const programId = Keypair.generate().publicKey; - const createAccountWithSeedAddress = await PublicKey.createWithSeed( - basePubkey, - seed, - programId, - ); - const space = 0; - - const minimumAmount = - await connection.getMinimumBalanceForRentExemption(space); - - // Test CreateAccountWithSeed - const createAccountWithSeedParams = { - fromPubkey: basePubkey, - newAccountPubkey: createAccountWithSeedAddress, - basePubkey, - seed, - lamports: minimumAmount, - space, - programId, - }; - const createAccountWithSeedTransaction = new Transaction().add( - SystemProgram.createAccountWithSeed(createAccountWithSeedParams), - ); - await sendAndConfirmTransaction( - connection, - createAccountWithSeedTransaction, - [baseAccount], - {preflightCommitment: 'confirmed'}, - ); - const createAccountWithSeedBalance = await connection.getBalance( - createAccountWithSeedAddress, - ); - expect(createAccountWithSeedBalance).to.eq(minimumAmount); - - // Test CreateAccountWithSeed where fromPubkey != basePubkey - const uniqueFromAccount = Keypair.generate(); - const newBaseAccount = Keypair.generate(); - const createAccountWithSeedAddress2 = await PublicKey.createWithSeed( - newBaseAccount.publicKey, - seed, - programId, - ); - await helpers.airdrop({ - connection, - address: uniqueFromAccount.publicKey, - amount: 2 * LAMPORTS_PER_SOL, - }); - const createAccountWithSeedParams2 = { - fromPubkey: uniqueFromAccount.publicKey, - newAccountPubkey: createAccountWithSeedAddress2, - basePubkey: newBaseAccount.publicKey, - seed, - lamports: minimumAmount, - space, - programId, - }; - const createAccountWithSeedTransaction2 = new Transaction().add( - SystemProgram.createAccountWithSeed(createAccountWithSeedParams2), - ); - await sendAndConfirmTransaction( - connection, - createAccountWithSeedTransaction2, - [uniqueFromAccount, newBaseAccount], - {preflightCommitment: 'confirmed'}, - ); - const createAccountWithSeedBalance2 = await connection.getBalance( - createAccountWithSeedAddress2, - ); - expect(createAccountWithSeedBalance2).to.eq(minimumAmount); - - // Transfer to a derived address to prep for TransferWithSeed - const programId2 = Keypair.generate().publicKey; - const transferWithSeedAddress = await PublicKey.createWithSeed( - basePubkey, - seed, - programId2, - ); - await sendAndConfirmTransaction( - connection, - new Transaction().add( - SystemProgram.transfer({ - fromPubkey: baseAccount.publicKey, - toPubkey: transferWithSeedAddress, - lamports: 3 * minimumAmount, - }), - ), - [baseAccount], - {preflightCommitment: 'confirmed'}, - ); - let transferWithSeedAddressBalance = await connection.getBalance( - transferWithSeedAddress, - ); - expect(transferWithSeedAddressBalance).to.eq(3 * minimumAmount); - - // Test TransferWithSeed - const programId3 = Keypair.generate(); - const toPubkey = await PublicKey.createWithSeed( - basePubkey, - seed, - programId3.publicKey, - ); - const transferWithSeedParams = { - fromPubkey: transferWithSeedAddress, - basePubkey, - toPubkey, - lamports: 2 * minimumAmount, - seed, - programId: programId2, - }; - const transferWithSeedTransaction = new Transaction().add( - SystemProgram.transfer(transferWithSeedParams), - ); - await sendAndConfirmTransaction( - connection, - transferWithSeedTransaction, - [baseAccount], - {preflightCommitment: 'confirmed'}, - ); - const toBalance = await connection.getBalance(toPubkey); - expect(toBalance).to.eq(2 * minimumAmount); - transferWithSeedAddressBalance = await connection.getBalance( - createAccountWithSeedAddress, - ); - expect(transferWithSeedAddressBalance).to.eq(minimumAmount); - - // Test AllocateWithSeed - const allocateWithSeedParams = { - accountPubkey: toPubkey, - basePubkey, - seed, - space: 10, - programId: programId3.publicKey, - }; - const allocateWithSeedTransaction = new Transaction().add( - SystemProgram.allocate(allocateWithSeedParams), - ); - await sendAndConfirmTransaction( - connection, - allocateWithSeedTransaction, - [baseAccount], - {preflightCommitment: 'confirmed'}, - ); - let account = await connection.getAccountInfo(toPubkey); - if (account === null) { - expect(account).not.to.be.null; - return; - } - expect(account.data).to.have.length(10); - - // Test AssignWithSeed - const assignWithSeedParams = { - accountPubkey: toPubkey, - basePubkey, - seed, - programId: programId3.publicKey, - }; - const assignWithSeedTransaction = new Transaction().add( - SystemProgram.assign(assignWithSeedParams), - ); - await sendAndConfirmTransaction( - connection, - assignWithSeedTransaction, - [baseAccount], - {preflightCommitment: 'confirmed'}, - ); - account = await connection.getAccountInfo(toPubkey); - if (account === null) { - expect(account).not.to.be.null; - return; - } - expect(account.owner).to.eql(programId3.publicKey); - }).timeout(10 * 1000); - } -}); diff --git a/packages/library-legacy/test/program-tests/vote.test.ts b/packages/library-legacy/test/program-tests/vote.test.ts deleted file mode 100644 index 9d9b8d6605c0..000000000000 --- a/packages/library-legacy/test/program-tests/vote.test.ts +++ /dev/null @@ -1,405 +0,0 @@ -import {expect, use} from 'chai'; -import chaiAsPromised from 'chai-as-promised'; - -import { - Keypair, - LAMPORTS_PER_SOL, - VoteAuthorizationLayout, - VoteInit, - VoteInstruction, - VoteProgram, - sendAndConfirmTransaction, - SystemInstruction, - Connection, - PublicKey, -} from '../../src'; -import {helpers} from '../mocks/rpc-http'; -import {url} from '../url'; - -use(chaiAsPromised); - -describe('VoteProgram', () => { - it('createAccount', () => { - const fromPubkey = Keypair.generate().publicKey; - const newAccountPubkey = Keypair.generate().publicKey; - const authorizedPubkey = Keypair.generate().publicKey; - const nodePubkey = Keypair.generate().publicKey; - const commission = 5; - const voteInit = new VoteInit( - nodePubkey, - authorizedPubkey, - authorizedPubkey, - commission, - ); - const lamports = 123; - const transaction = VoteProgram.createAccount({ - fromPubkey, - votePubkey: newAccountPubkey, - voteInit, - lamports, - }); - expect(transaction.instructions).to.have.length(2); - const [systemInstruction, voteInstruction] = transaction.instructions; - const systemParams = { - fromPubkey, - newAccountPubkey, - lamports, - space: VoteProgram.space, - programId: VoteProgram.programId, - }; - expect(systemParams).to.eql( - SystemInstruction.decodeCreateAccount(systemInstruction), - ); - - const initParams = {votePubkey: newAccountPubkey, nodePubkey, voteInit}; - expect(initParams).to.eql( - VoteInstruction.decodeInitializeAccount(voteInstruction), - ); - }); - - it('initialize', () => { - const newAccountPubkey = Keypair.generate().publicKey; - const authorizedPubkey = Keypair.generate().publicKey; - const nodePubkey = Keypair.generate().publicKey; - const voteInit = new VoteInit( - nodePubkey, - authorizedPubkey, - authorizedPubkey, - 5, - ); - const initParams = { - votePubkey: newAccountPubkey, - nodePubkey, - voteInit, - }; - const initInstruction = VoteProgram.initializeAccount(initParams); - expect(initParams).to.eql( - VoteInstruction.decodeInitializeAccount(initInstruction), - ); - }); - - it('authorize', () => { - const votePubkey = Keypair.generate().publicKey; - const authorizedPubkey = Keypair.generate().publicKey; - const newAuthorizedPubkey = Keypair.generate().publicKey; - const voteAuthorizationType = VoteAuthorizationLayout.Voter; - const params = { - votePubkey, - authorizedPubkey, - newAuthorizedPubkey, - voteAuthorizationType, - }; - const transaction = VoteProgram.authorize(params); - expect(transaction.instructions).to.have.length(1); - const [authorizeInstruction] = transaction.instructions; - expect(params).to.eql( - VoteInstruction.decodeAuthorize(authorizeInstruction), - ); - }); - - it('authorize with seed', () => { - const votePubkey = Keypair.generate().publicKey; - const currentAuthorityDerivedKeyBasePubkey = Keypair.generate().publicKey; - const currentAuthorityDerivedKeyOwnerPubkey = Keypair.generate().publicKey; - const currentAuthorityDerivedKeySeed = 'sunflower'; - const newAuthorizedPubkey = Keypair.generate().publicKey; - const voteAuthorizationType = VoteAuthorizationLayout.Voter; - const params = { - currentAuthorityDerivedKeyBasePubkey, - currentAuthorityDerivedKeyOwnerPubkey, - currentAuthorityDerivedKeySeed, - newAuthorizedPubkey, - voteAuthorizationType, - votePubkey, - }; - const transaction = VoteProgram.authorizeWithSeed(params); - expect(transaction.instructions).to.have.length(1); - const [authorizeWithSeedInstruction] = transaction.instructions; - expect(params).to.eql( - VoteInstruction.decodeAuthorizeWithSeed(authorizeWithSeedInstruction), - ); - }); - - it('withdraw', () => { - const votePubkey = Keypair.generate().publicKey; - const authorizedWithdrawerPubkey = Keypair.generate().publicKey; - const toPubkey = Keypair.generate().publicKey; - const params = { - votePubkey, - authorizedWithdrawerPubkey, - lamports: 123, - toPubkey, - }; - const transaction = VoteProgram.withdraw(params); - expect(transaction.instructions).to.have.length(1); - const [withdrawInstruction] = transaction.instructions; - expect(params).to.eql(VoteInstruction.decodeWithdraw(withdrawInstruction)); - }); - - if (process.env.TEST_LIVE) { - it('change authority from derived key', async () => { - const connection = new Connection(url, 'confirmed'); - - const newVoteAccount = Keypair.generate(); - const nodeAccount = Keypair.generate(); - const derivedKeyOwnerProgram = Keypair.generate(); - const derivedKeySeed = 'sunflower'; - const newAuthorizedWithdrawer = Keypair.generate(); - - const derivedKeyBaseKeypair = Keypair.generate(); - const [ - _1, // eslint-disable-line @typescript-eslint/no-unused-vars - _2, // eslint-disable-line @typescript-eslint/no-unused-vars - minimumAmount, - derivedKey, - ] = await Promise.all([ - (async () => { - await helpers.airdrop({ - connection, - address: derivedKeyBaseKeypair.publicKey, - amount: 12 * LAMPORTS_PER_SOL, - }); - expect( - await connection.getBalance(derivedKeyBaseKeypair.publicKey), - ).to.eq(12 * LAMPORTS_PER_SOL); - })(), - (async () => { - await helpers.airdrop({ - connection, - address: newAuthorizedWithdrawer.publicKey, - amount: 0.1 * LAMPORTS_PER_SOL, - }); - expect( - await connection.getBalance(newAuthorizedWithdrawer.publicKey), - ).to.eq(0.1 * LAMPORTS_PER_SOL); - })(), - connection.getMinimumBalanceForRentExemption(VoteProgram.space), - PublicKey.createWithSeed( - derivedKeyBaseKeypair.publicKey, - derivedKeySeed, - derivedKeyOwnerProgram.publicKey, - ), - ]); - - // Create initialized Vote account - const createAndInitialize = VoteProgram.createAccount({ - fromPubkey: derivedKeyBaseKeypair.publicKey, - votePubkey: newVoteAccount.publicKey, - voteInit: new VoteInit( - nodeAccount.publicKey, - derivedKey, - derivedKey, - 5, - ), - lamports: minimumAmount + 10 * LAMPORTS_PER_SOL, - }); - await sendAndConfirmTransaction( - connection, - createAndInitialize, - [derivedKeyBaseKeypair, newVoteAccount, nodeAccount], - {preflightCommitment: 'confirmed'}, - ); - expect(await connection.getBalance(newVoteAccount.publicKey)).to.eq( - minimumAmount + 10 * LAMPORTS_PER_SOL, - ); - - // Authorize a new Withdrawer. - const authorize = VoteProgram.authorizeWithSeed({ - currentAuthorityDerivedKeyBasePubkey: derivedKeyBaseKeypair.publicKey, - currentAuthorityDerivedKeyOwnerPubkey: derivedKeyOwnerProgram.publicKey, - currentAuthorityDerivedKeySeed: derivedKeySeed, - newAuthorizedPubkey: newAuthorizedWithdrawer.publicKey, - voteAuthorizationType: VoteAuthorizationLayout.Withdrawer, - votePubkey: newVoteAccount.publicKey, - }); - await sendAndConfirmTransaction( - connection, - authorize, - [derivedKeyBaseKeypair], - {preflightCommitment: 'confirmed'}, - ); - - // Test newAuthorizedWithdrawer may withdraw. - const recipient = Keypair.generate(); - const withdraw = VoteProgram.withdraw({ - votePubkey: newVoteAccount.publicKey, - authorizedWithdrawerPubkey: newAuthorizedWithdrawer.publicKey, - lamports: LAMPORTS_PER_SOL, - toPubkey: recipient.publicKey, - }); - await sendAndConfirmTransaction( - connection, - withdraw, - [newAuthorizedWithdrawer], - {preflightCommitment: 'confirmed'}, - ); - expect(await connection.getBalance(recipient.publicKey)).to.eq( - LAMPORTS_PER_SOL, - ); - }); - - it('live vote actions', async () => { - const connection = new Connection(url, 'confirmed'); - - const newVoteAccount = Keypair.generate(); - const nodeAccount = Keypair.generate(); - - const payer = Keypair.generate(); - await helpers.airdrop({ - connection, - address: payer.publicKey, - amount: 12 * LAMPORTS_PER_SOL, - }); - expect(await connection.getBalance(payer.publicKey)).to.eq( - 12 * LAMPORTS_PER_SOL, - ); - - const authorized = Keypair.generate(); - await helpers.airdrop({ - connection, - address: authorized.publicKey, - amount: 12 * LAMPORTS_PER_SOL, - }); - expect(await connection.getBalance(authorized.publicKey)).to.eq( - 12 * LAMPORTS_PER_SOL, - ); - - const minimumAmount = await connection.getMinimumBalanceForRentExemption( - VoteProgram.space, - ); - - // Create initialized Vote account - let createAndInitialize = VoteProgram.createAccount({ - fromPubkey: payer.publicKey, - votePubkey: newVoteAccount.publicKey, - voteInit: new VoteInit( - nodeAccount.publicKey, - authorized.publicKey, - authorized.publicKey, - 5, - ), - lamports: minimumAmount + 10 * LAMPORTS_PER_SOL, - }); - await sendAndConfirmTransaction( - connection, - createAndInitialize, - [payer, newVoteAccount, nodeAccount], - {preflightCommitment: 'confirmed'}, - ); - expect(await connection.getBalance(newVoteAccount.publicKey)).to.eq( - minimumAmount + 10 * LAMPORTS_PER_SOL, - ); - - // Withdraw from Vote account - let recipient = Keypair.generate(); - const voteBalance = await connection.getBalance(newVoteAccount.publicKey); - - expect(() => - VoteProgram.safeWithdraw( - { - votePubkey: newVoteAccount.publicKey, - authorizedWithdrawerPubkey: authorized.publicKey, - lamports: voteBalance - minimumAmount + 1, - toPubkey: recipient.publicKey, - }, - voteBalance, - minimumAmount, - ), - ).to.throw('Withdraw will leave vote account with insufficient funds.'); - - let withdraw = VoteProgram.withdraw({ - votePubkey: newVoteAccount.publicKey, - authorizedWithdrawerPubkey: authorized.publicKey, - lamports: LAMPORTS_PER_SOL, - toPubkey: recipient.publicKey, - }); - await sendAndConfirmTransaction(connection, withdraw, [authorized], { - preflightCommitment: 'confirmed', - }); - expect(await connection.getBalance(recipient.publicKey)).to.eq( - LAMPORTS_PER_SOL, - ); - - const newAuthorizedWithdrawer = Keypair.generate(); - await helpers.airdrop({ - connection, - address: newAuthorizedWithdrawer.publicKey, - amount: LAMPORTS_PER_SOL, - }); - expect( - await connection.getBalance(newAuthorizedWithdrawer.publicKey), - ).to.eq(LAMPORTS_PER_SOL); - - // Authorize a new Withdrawer. - let authorize = VoteProgram.authorize({ - votePubkey: newVoteAccount.publicKey, - authorizedPubkey: authorized.publicKey, - newAuthorizedPubkey: newAuthorizedWithdrawer.publicKey, - voteAuthorizationType: VoteAuthorizationLayout.Withdrawer, - }); - await sendAndConfirmTransaction(connection, authorize, [authorized], { - preflightCommitment: 'confirmed', - }); - - // Test old authorized cannot withdraw anymore. - withdraw = VoteProgram.withdraw({ - votePubkey: newVoteAccount.publicKey, - authorizedWithdrawerPubkey: authorized.publicKey, - lamports: minimumAmount, - toPubkey: recipient.publicKey, - }); - await expect( - sendAndConfirmTransaction(connection, withdraw, [authorized], { - preflightCommitment: 'confirmed', - }), - ).to.be.rejected; - - // Test newAuthorizedWithdrawer may withdraw. - recipient = Keypair.generate(); - withdraw = VoteProgram.withdraw({ - votePubkey: newVoteAccount.publicKey, - authorizedWithdrawerPubkey: newAuthorizedWithdrawer.publicKey, - lamports: LAMPORTS_PER_SOL, - toPubkey: recipient.publicKey, - }); - await sendAndConfirmTransaction( - connection, - withdraw, - [newAuthorizedWithdrawer], - { - preflightCommitment: 'confirmed', - }, - ); - expect(await connection.getBalance(recipient.publicKey)).to.eq( - LAMPORTS_PER_SOL, - ); - - const newAuthorizedVoter = Keypair.generate(); - await helpers.airdrop({ - connection, - address: newAuthorizedVoter.publicKey, - amount: LAMPORTS_PER_SOL, - }); - expect(await connection.getBalance(newAuthorizedVoter.publicKey)).to.eq( - LAMPORTS_PER_SOL, - ); - - // The authorized Withdrawer may sign to authorize a new Voter, see - // https://github.com/solana-labs/solana/issues/22521 - authorize = VoteProgram.authorize({ - votePubkey: newVoteAccount.publicKey, - authorizedPubkey: newAuthorizedWithdrawer.publicKey, - newAuthorizedPubkey: newAuthorizedVoter.publicKey, - voteAuthorizationType: VoteAuthorizationLayout.Voter, - }); - await sendAndConfirmTransaction( - connection, - authorize, - [newAuthorizedWithdrawer], - { - preflightCommitment: 'confirmed', - }, - ); - }).timeout(10 * 1000); - } -}); diff --git a/packages/library-legacy/test/publickey.test.ts b/packages/library-legacy/test/publickey.test.ts deleted file mode 100644 index bc4b9cb4c3fa..000000000000 --- a/packages/library-legacy/test/publickey.test.ts +++ /dev/null @@ -1,262 +0,0 @@ -import BN from 'bn.js'; -import {Buffer} from 'buffer'; -import {expect, use} from 'chai'; -import chaiAsPromised from 'chai-as-promised'; - -import {Keypair} from '../src/keypair'; -import {PublicKey, MAX_SEED_LENGTH} from '../src/publickey'; - -use(chaiAsPromised); - -describe('PublicKey', function () { - it('invalid', () => { - expect(() => { - new PublicKey([ - 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, - ]); - }).to.throw(); - - expect(() => { - new PublicKey( - '0x300000000000000000000000000000000000000000000000000000000000000000000', - ); - }).to.throw(); - - expect(() => { - new PublicKey( - '0x300000000000000000000000000000000000000000000000000000000000000', - ); - }).to.throw(); - - expect(() => { - new PublicKey( - '135693854574979916511997248057056142015550763280047535983739356259273198796800000', - ); - }).to.throw(); - - expect(() => { - new PublicKey('12345'); - }).to.throw(); - }); - - it('equals', () => { - const arrayKey = new PublicKey([ - 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, - ]); - const base58Key = new PublicKey( - 'CiDwVBFgWV9E5MvXWoLgnEgn2hK7rJikbvfWavzAQz3', - ); - - expect(arrayKey.equals(base58Key)).to.be.true; - }); - - it('toBase58', () => { - const key = new PublicKey('CiDwVBFgWV9E5MvXWoLgnEgn2hK7rJikbvfWavzAQz3'); - expect(key.toBase58()).to.eq('CiDwVBFgWV9E5MvXWoLgnEgn2hK7rJikbvfWavzAQz3'); - expect(key.toString()).to.eq('CiDwVBFgWV9E5MvXWoLgnEgn2hK7rJikbvfWavzAQz3'); - - const key2 = new PublicKey('1111111111111111111111111111BukQL'); - expect(key2.toBase58()).to.eq('1111111111111111111111111111BukQL'); - expect(key2.toString()).to.eq('1111111111111111111111111111BukQL'); - - const key3 = new PublicKey('11111111111111111111111111111111'); - expect(key3.toBase58()).to.eq('11111111111111111111111111111111'); - - const key4 = new PublicKey([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, - ]); - expect(key4.toBase58()).to.eq('11111111111111111111111111111111'); - }); - - it('toJSON', () => { - const key = new PublicKey('CiDwVBFgWV9E5MvXWoLgnEgn2hK7rJikbvfWavzAQz3'); - expect(key.toJSON()).to.eq('CiDwVBFgWV9E5MvXWoLgnEgn2hK7rJikbvfWavzAQz3'); - expect(JSON.stringify(key)).to.eq( - '"CiDwVBFgWV9E5MvXWoLgnEgn2hK7rJikbvfWavzAQz3"', - ); - expect(JSON.stringify({key})).to.eq( - '{"key":"CiDwVBFgWV9E5MvXWoLgnEgn2hK7rJikbvfWavzAQz3"}', - ); - }); - - it('toBuffer', () => { - const key = new PublicKey('CiDwVBFgWV9E5MvXWoLgnEgn2hK7rJikbvfWavzAQz3'); - expect(key.toBuffer()).to.have.length(32); - expect(key.toBase58()).to.eq('CiDwVBFgWV9E5MvXWoLgnEgn2hK7rJikbvfWavzAQz3'); - - const key2 = new PublicKey('11111111111111111111111111111111'); - expect(key2.toBuffer()).to.have.length(32); - expect(key2.toBase58()).to.eq('11111111111111111111111111111111'); - - const key3 = new PublicKey(0); - expect(key3.toBuffer()).to.have.length(32); - expect(key3.toBase58()).to.eq('11111111111111111111111111111111'); - }); - - it('equals (II)', () => { - const key1 = new PublicKey([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1, - ]); - const key2 = new PublicKey(key1.toBuffer()); - - expect(key1.equals(key2)).to.be.true; - }); - - it('createWithSeed', async () => { - const defaultPublicKey = new PublicKey('11111111111111111111111111111111'); - const derivedKey = await PublicKey.createWithSeed( - defaultPublicKey, - 'limber chicken: 4/45', - defaultPublicKey, - ); - - expect( - derivedKey.equals( - new PublicKey('9h1HyLCW5dZnBVap8C5egQ9Z6pHyjsh5MNy83iPqqRuq'), - ), - ).to.be.true; - }); - - it('createProgramAddress', async () => { - const programId = new PublicKey( - 'BPFLoader1111111111111111111111111111111111', - ); - const publicKey = new PublicKey( - 'SeedPubey1111111111111111111111111111111111', - ); - - let programAddress = await PublicKey.createProgramAddress( - [Buffer.from('', 'utf8'), Buffer.from([1])], - programId, - ); - expect( - programAddress.equals( - new PublicKey('3gF2KMe9KiC6FNVBmfg9i267aMPvK37FewCip4eGBFcT'), - ), - ).to.be.true; - - programAddress = await PublicKey.createProgramAddress( - [Buffer.from('☉', 'utf8')], - programId, - ); - expect( - programAddress.equals( - new PublicKey('7ytmC1nT1xY4RfxCV2ZgyA7UakC93do5ZdyhdF3EtPj7'), - ), - ).to.be.true; - - programAddress = await PublicKey.createProgramAddress( - [Buffer.from('Talking', 'utf8'), Buffer.from('Squirrels', 'utf8')], - programId, - ); - expect( - programAddress.equals( - new PublicKey('HwRVBufQ4haG5XSgpspwKtNd3PC9GM9m1196uJW36vds'), - ), - ).to.be.true; - - programAddress = await PublicKey.createProgramAddress( - [publicKey.toBuffer()], - programId, - ); - expect( - programAddress.equals( - new PublicKey('GUs5qLUfsEHkcMB9T38vjr18ypEhRuNWiePW2LoK4E3K'), - ), - ).to.be.true; - - const programAddress2 = await PublicKey.createProgramAddress( - [Buffer.from('Talking', 'utf8')], - programId, - ); - expect(programAddress.equals(programAddress2)).to.eq(false); - - await expect( - PublicKey.createProgramAddress( - [Buffer.alloc(MAX_SEED_LENGTH + 1)], - programId, - ), - ).to.be.rejectedWith('Max seed length exceeded'); - - // https://github.com/solana-labs/solana/issues/11950 - { - let seeds = [ - new PublicKey( - 'H4snTKK9adiU15gP22ErfZYtro3aqR9BTMXiH3AwiUTQ', - ).toBuffer(), - new BN(2).toArrayLike(Buffer, 'le', 8), - ]; - let programId = new PublicKey( - '4ckmDgGdxQoPDLUkDT3vHgSAkzA3QRdNq5ywwY4sUSJn', - ); - programAddress = await PublicKey.createProgramAddress(seeds, programId); - expect( - programAddress.equals( - new PublicKey('12rqwuEgBYiGhBrDJStCiqEtzQpTTiZbh7teNVLuYcFA'), - ), - ).to.be.true; - } - - // Should work in promise mode, for backwards compatibility - PublicKey.createProgramAddress( - [Buffer.from('', 'utf8'), Buffer.from([1])], - programId, - ).then(); - }); - - it('findProgramAddress', async () => { - const programId = new PublicKey( - 'BPFLoader1111111111111111111111111111111111', - ); - let [programAddress, nonce] = await PublicKey.findProgramAddress( - [Buffer.from('', 'utf8')], - programId, - ); - expect( - programAddress.equals( - await PublicKey.createProgramAddress( - [Buffer.from('', 'utf8'), Buffer.from([nonce])], - programId, - ), - ), - ).to.be.true; - - // Should work in promise mode, for backwards compatibility - PublicKey.findProgramAddress([Buffer.from('', 'utf8')], programId).then(); - }); - - it('isOnCurve', () => { - let onCurve = Keypair.generate().publicKey; - expect(PublicKey.isOnCurve(onCurve.toBuffer())).to.be.true; - expect(PublicKey.isOnCurve(onCurve.toBase58())).to.be.true; - expect(PublicKey.isOnCurve(onCurve)).to.be.true; - // A program address, yanked from one of the above tests. This is a pretty - // poor test vector since it was created by the same code it is testing. - // Unfortunately, I've been unable to find a golden negative example input - // for curve25519 point decompression :/ - let offCurve = new PublicKey( - '12rqwuEgBYiGhBrDJStCiqEtzQpTTiZbh7teNVLuYcFA', - ); - expect(PublicKey.isOnCurve(offCurve.toBuffer())).to.be.false; - expect(PublicKey.isOnCurve(offCurve.toBase58())).to.be.false; - expect(PublicKey.isOnCurve(offCurve)).to.be.false; - }); - - it('canBeSerializedWithBorsh', () => { - const publicKey = Keypair.generate().publicKey; - const encoded = publicKey.encode(); - const decoded = PublicKey.decode(encoded); - expect(decoded.equals(publicKey)).to.be.true; - }); - - it('canBeDeserializedUncheckedWithBorsh', () => { - const publicKey = Keypair.generate().publicKey; - const encoded = Buffer.concat([publicKey.encode(), new Uint8Array(10)]); - const decoded = PublicKey.decodeUnchecked(encoded); - expect(decoded.equals(publicKey)).to.be.true; - }); -}); diff --git a/packages/library-legacy/test/shortvec-encoding.test.ts b/packages/library-legacy/test/shortvec-encoding.test.ts deleted file mode 100644 index 68f8415862cd..000000000000 --- a/packages/library-legacy/test/shortvec-encoding.test.ts +++ /dev/null @@ -1,74 +0,0 @@ -import {expect} from 'chai'; - -import {decodeLength, encodeLength} from '../src/utils/shortvec-encoding'; - -function checkDecodedArray(array: Array, expectedValue: number) { - expect(decodeLength(array)).to.eq(expectedValue); - expect(array).to.have.length(0); -} - -function checkEncodedArray( - array: Array, - len: number, - prevLength: number, - addedLength: number, - expectedArray: Array, -) { - encodeLength(array, len); - expect(array).to.have.length(prevLength); - expect(array.slice(-addedLength)).to.eql(expectedArray); -} - -describe('shortvec', () => { - it('decodeLength', () => { - let array: number[] = []; - checkDecodedArray(array, 0); - - array = [5]; - checkDecodedArray(array, 5); - - array = [0x7f]; - checkDecodedArray(array, 0x7f); - - array = [0x80, 0x01]; - checkDecodedArray(array, 0x80); - - array = [0xff, 0x01]; - checkDecodedArray(array, 0xff); - - array = [0x80, 0x02]; - checkDecodedArray(array, 0x100); - - array = [0xff, 0xff, 0x01]; - checkDecodedArray(array, 0x7fff); - - array = [0x80, 0x80, 0x80, 0x01]; - checkDecodedArray(array, 0x200000); - }); - - it('encodeLength', () => { - let array: number[] = []; - let prevLength = 1; - checkEncodedArray(array, 0, prevLength, 1, [0]); - - checkEncodedArray(array, 5, (prevLength += 1), 1, [5]); - - checkEncodedArray(array, 0x7f, (prevLength += 1), 1, [0x7f]); - - checkEncodedArray(array, 0x80, (prevLength += 2), 2, [0x80, 0x01]); - - checkEncodedArray(array, 0xff, (prevLength += 2), 2, [0xff, 0x01]); - - checkEncodedArray(array, 0x100, (prevLength += 2), 2, [0x80, 0x02]); - - checkEncodedArray(array, 0x7fff, (prevLength += 3), 3, [0xff, 0xff, 0x01]); - - checkEncodedArray( - array, - 0x200000, - (prevLength += 4), - 4, - [0x80, 0x80, 0x80, 0x01], - ); - }); -}); diff --git a/packages/library-legacy/test/transaction-payer.test.ts b/packages/library-legacy/test/transaction-payer.test.ts deleted file mode 100644 index 46b1841ba9e3..000000000000 --- a/packages/library-legacy/test/transaction-payer.test.ts +++ /dev/null @@ -1,132 +0,0 @@ -import base58 from 'bs58'; -import {expect} from 'chai'; - -import { - Keypair, - Connection, - Transaction, - SystemProgram, - LAMPORTS_PER_SOL, -} from '../src'; -import invariant from '../src/utils/assert'; -import {MOCK_PORT, url} from './url'; -import {helpers, mockRpcResponse, mockServer} from './mocks/rpc-http'; -import {stubRpcWebSocket, restoreRpcWebSocket} from './mocks/rpc-websocket'; - -describe('Transaction Payer', () => { - let connection: Connection; - beforeEach(() => { - connection = new Connection(url); - }); - - if (mockServer) { - const server = mockServer; - beforeEach(() => { - server.start(MOCK_PORT); - stubRpcWebSocket(connection); - }); - - afterEach(() => { - server.stop(); - restoreRpcWebSocket(connection); - }); - } - - it('transaction-payer', async () => { - const accountPayer = Keypair.generate(); - const accountFrom = Keypair.generate(); - const accountTo = Keypair.generate(); - - await helpers.airdrop({ - connection, - address: accountPayer.publicKey, - amount: LAMPORTS_PER_SOL, - }); - - await mockRpcResponse({ - method: 'getMinimumBalanceForRentExemption', - params: [0], - value: 50, - }); - - const minimumAmount = await connection.getMinimumBalanceForRentExemption(0); - - await helpers.airdrop({ - connection, - address: accountFrom.publicKey, - amount: minimumAmount + 12, - }); - - await helpers.airdrop({ - connection, - address: accountTo.publicKey, - amount: minimumAmount + 21, - }); - - const transaction = new Transaction().add( - SystemProgram.transfer({ - fromPubkey: accountFrom.publicKey, - toPubkey: accountTo.publicKey, - lamports: 10, - }), - ); - - await helpers.processTransaction({ - connection, - transaction, - signers: [accountPayer, accountFrom], - commitment: 'confirmed', - }); - - invariant(transaction.signature); - const signature = base58.encode(transaction.signature); - - await mockRpcResponse({ - method: 'getSignatureStatuses', - params: [[signature]], - value: [ - { - slot: 0, - confirmations: 11, - status: {Ok: null}, - err: null, - }, - ], - withContext: true, - }); - const {value} = await connection.getSignatureStatus(signature); - if (value !== null) { - expect(typeof value.slot).to.eq('number'); - expect(value.err).to.be.null; - } else { - expect(value).not.to.be.null; - } - - await mockRpcResponse({ - method: 'getBalance', - params: [accountPayer.publicKey.toBase58(), {commitment: 'confirmed'}], - value: LAMPORTS_PER_SOL - 1, - withContext: true, - }); - - // accountPayer should be less than LAMPORTS_PER_SOL as it paid for the transaction - // (exact amount less depends on the current cluster fees) - const balance = await connection.getBalance( - accountPayer.publicKey, - 'confirmed', - ); - expect(balance).to.be.greaterThan(0); - expect(balance).to.be.at.most(LAMPORTS_PER_SOL); - - // accountFrom should have exactly 2, since it didn't pay for the transaction - await mockRpcResponse({ - method: 'getBalance', - params: [accountFrom.publicKey.toBase58(), {commitment: 'confirmed'}], - value: minimumAmount + 2, - withContext: true, - }); - expect( - await connection.getBalance(accountFrom.publicKey, 'confirmed'), - ).to.eq(minimumAmount + 2); - }).timeout(30 * 1000); -}); diff --git a/packages/library-legacy/test/transaction-tests/message.test.ts b/packages/library-legacy/test/transaction-tests/message.test.ts deleted file mode 100644 index ce4937c04374..000000000000 --- a/packages/library-legacy/test/transaction-tests/message.test.ts +++ /dev/null @@ -1,160 +0,0 @@ -import bs58 from 'bs58'; -import {expect} from 'chai'; -import {sha256} from '@noble/hashes/sha256'; - -import { - Transaction, - TransactionInstruction, - TransactionMessage, -} from '../../src/transaction'; -import {PublicKey} from '../../src/publickey'; -import {AddressLookupTableAccount} from '../../src/programs'; -import {Message, MessageV0} from '../../src/message'; - -function createTestKeys(count: number): Array { - return new Array(count).fill(0).map(() => PublicKey.unique()); -} - -function createTestLookupTable( - addresses: Array, -): AddressLookupTableAccount { - const U64_MAX = BigInt('0xffffffffffffffff'); - return new AddressLookupTableAccount({ - key: PublicKey.unique(), - state: { - lastExtendedSlot: 0, - lastExtendedSlotStartIndex: 0, - deactivationSlot: U64_MAX, - authority: PublicKey.unique(), - addresses, - }, - }); -} - -describe('TransactionMessage', () => { - it('decompiles a legacy message', () => { - const keys = createTestKeys(7); - const recentBlockhash = bs58.encode(sha256('test')); - const payerKey = keys[0]; - const instructions = [ - new TransactionInstruction({ - programId: keys[5], - keys: [ - {pubkey: keys[0], isSigner: true, isWritable: true}, - {pubkey: keys[6], isSigner: false, isWritable: false}, - {pubkey: keys[1], isSigner: false, isWritable: true}, - {pubkey: keys[3], isSigner: false, isWritable: false}, - {pubkey: keys[4], isSigner: false, isWritable: false}, - {pubkey: keys[2], isSigner: false, isWritable: false}, - ], - data: Buffer.alloc(1), - }), - ]; - - const message = Message.compile({ - instructions, - payerKey, - recentBlockhash, - }); - - expect(() => TransactionMessage.decompile(message)).not.to.throw( - 'Failed to get account keys because address table lookups were not resolved', - ); - - const decompiledMessage = TransactionMessage.decompile(message); - - expect(decompiledMessage.payerKey).to.eql(payerKey); - expect(decompiledMessage.recentBlockhash).to.eq(recentBlockhash); - expect(decompiledMessage.instructions).to.eql(instructions); - }); - - // Regression test for https://github.com/solana-labs/solana/issues/28900 - it('decompiles a legacy message the same way as the old API', () => { - const accountKeys = createTestKeys(7); - const legacyMessage = new Message({ - header: { - numRequiredSignatures: 1, - numReadonlySignedAccounts: 0, - numReadonlyUnsignedAccounts: 5, - }, - recentBlockhash: bs58.encode(sha256('test')), - accountKeys, - instructions: [ - { - accounts: [0, 6, 1, 3, 4, 2], - data: '', - programIdIndex: 5, - }, - ], - }); - - const transactionFromLegacyAPI = Transaction.populate(legacyMessage); - const transactionMessage = TransactionMessage.decompile(legacyMessage); - - expect(transactionMessage.payerKey).to.eql( - transactionFromLegacyAPI.feePayer, - ); - expect(transactionMessage.instructions).to.eql( - transactionFromLegacyAPI.instructions, - ); - expect(transactionMessage.recentBlockhash).to.eql( - transactionFromLegacyAPI.recentBlockhash, - ); - }); - - it('decompiles a V0 message', () => { - const keys = createTestKeys(7); - const recentBlockhash = bs58.encode(sha256('test')); - const payerKey = keys[0]; - const instructions = [ - new TransactionInstruction({ - programId: keys[4], - keys: [ - {pubkey: keys[1], isSigner: true, isWritable: true}, - {pubkey: keys[2], isSigner: true, isWritable: false}, - {pubkey: keys[3], isSigner: false, isWritable: true}, - {pubkey: keys[5], isSigner: false, isWritable: true}, - {pubkey: keys[6], isSigner: false, isWritable: false}, - ], - data: Buffer.alloc(1), - }), - new TransactionInstruction({ - programId: keys[1], - keys: [], - data: Buffer.alloc(2), - }), - new TransactionInstruction({ - programId: keys[3], - keys: [], - data: Buffer.alloc(3), - }), - ]; - - const addressLookupTableAccounts = [createTestLookupTable(keys)]; - const message = MessageV0.compile({ - payerKey, - recentBlockhash, - instructions, - addressLookupTableAccounts, - }); - - expect(() => TransactionMessage.decompile(message)).to.throw( - 'Failed to get account keys because address table lookups were not resolved', - ); - - const accountKeys = message.getAccountKeys({addressLookupTableAccounts}); - const decompiledMessage = TransactionMessage.decompile(message, { - addressLookupTableAccounts, - }); - - expect(decompiledMessage.payerKey).to.eql(payerKey); - expect(decompiledMessage.recentBlockhash).to.eq(recentBlockhash); - expect(decompiledMessage.instructions).to.eql(instructions); - - expect(decompiledMessage).to.eql( - TransactionMessage.decompile(message, { - accountKeysFromLookups: accountKeys.accountKeysFromLookups!, - }), - ); - }); -}); diff --git a/packages/library-legacy/test/transaction.test.ts b/packages/library-legacy/test/transaction.test.ts deleted file mode 100644 index 95c42695b03c..000000000000 --- a/packages/library-legacy/test/transaction.test.ts +++ /dev/null @@ -1,1226 +0,0 @@ -import bs58 from 'bs58'; -import {Buffer} from 'buffer'; -import {expect} from 'chai'; - -import {Connection} from '../src/connection'; -import {Keypair} from '../src/keypair'; -import {PublicKey} from '../src/publickey'; -import { - Transaction, - TransactionInstruction, - TransactionMessage, - VersionedTransaction, -} from '../src/transaction'; -import {StakeProgram, SystemProgram} from '../src/programs'; -import {Message} from '../src/message'; -import invariant from '../src/utils/assert'; -import {toBuffer} from '../src/utils/to-buffer'; -import {helpers} from './mocks/rpc-http'; -import {url} from './url'; -import {sign} from '../src/utils/ed25519'; - -describe('Transaction', () => { - describe('compileMessage', () => { - it('accountKeys are ordered', () => { - // These pubkeys are chosen specially to be in sort order. - const payer = new PublicKey( - '3qMLYYyNvaxNZP7nW8u5abHMoJthYqQehRLbFVPNNcvQ', - ); - const accountWritableSigner2 = new PublicKey( - '3XLtLo5Z4DG8b6PteJidF6kFPNDfxWjxv4vTLrjaHTvd', - ); - const accountWritableSigner3 = new PublicKey( - '4rvqGPb4sXgyUKQcvmPxnWEZTTiTqNUZ2jjnw7atKVxa', - ); - const accountSigner4 = new PublicKey( - '5oGjWjyoKDoXGpboGBfqm9a5ZscyAjRi3xuGYYu1ayQg', - ); - const accountSigner5 = new PublicKey( - '65Rkc3VmDEV6zTRGtgdwkTcQUxDJnJszj2s4WoXazYpC', - ); - const accountWritable6 = new PublicKey( - '72BxBZ9eD9Ue6zoJ9bzfit7MuaDAnq1qhirgAoFUXz9q', - ); - const accountWritable7 = new PublicKey( - 'BtYrPUeVphVgRHJkf2bKz8DLRxJdQmZyANrTM12xFqZL', - ); - const accountRegular8 = new PublicKey( - 'Di1MbqFwpodKzNrkjGaUHhXC4TJ1SHUAxo9agPZphNH1', - ); - const accountRegular9 = new PublicKey( - 'DYzzsfHTgaNhCgn7wMaciAYuwYsGqtVNg9PeFZhH93Pc', - ); - const programId = new PublicKey( - 'Fx9svCTdxnACvmEmx672v2kP1or4G1zC73tH7XsXbKkP', - ); - - const recentBlockhash = Keypair.generate().publicKey.toBase58(); - const transaction = new Transaction({ - blockhash: recentBlockhash, - lastValidBlockHeight: 9999, - }).add({ - keys: [ - // Regular accounts - {pubkey: accountRegular9, isSigner: false, isWritable: false}, - {pubkey: accountRegular8, isSigner: false, isWritable: false}, - // Writable accounts - {pubkey: accountWritable7, isSigner: false, isWritable: true}, - {pubkey: accountWritable6, isSigner: false, isWritable: true}, - // Signers - {pubkey: accountSigner5, isSigner: true, isWritable: false}, - {pubkey: accountSigner4, isSigner: true, isWritable: false}, - // Writable Signers - {pubkey: accountWritableSigner3, isSigner: true, isWritable: true}, - {pubkey: accountWritableSigner2, isSigner: true, isWritable: true}, - // Payer. - {pubkey: payer, isSigner: true, isWritable: true}, - ], - programId, - }); - - transaction.feePayer = payer; - - const message = transaction.compileMessage(); - // Payer comes first. - expect(message.accountKeys[0].equals(payer)).to.be.true; - // Writable signers come next, in pubkey order. - expect(message.accountKeys[1].equals(accountWritableSigner2)).to.be.true; - expect(message.accountKeys[2].equals(accountWritableSigner3)).to.be.true; - // Signers come next, in pubkey order. - expect(message.accountKeys[3].equals(accountSigner4)).to.be.true; - expect(message.accountKeys[4].equals(accountSigner5)).to.be.true; - // Writable accounts come next, in pubkey order. - expect(message.accountKeys[5].equals(accountWritable6)).to.be.true; - expect(message.accountKeys[6].equals(accountWritable7)).to.be.true; - // Everything else afterward, in pubkey order. - expect(message.accountKeys[7].equals(accountRegular8)).to.be.true; - expect(message.accountKeys[8].equals(accountRegular9)).to.be.true; - expect(message.accountKeys[9].equals(programId)).to.be.true; - }); - - it('accountKeys collapses signedness and writability of duplicate accounts', () => { - // These pubkeys are chosen specially to be in sort order. - const payer = new PublicKey( - '2eBgaMN8dCnCjx8B8Wrwk974v5WHwA6Vvj4N2mW9KDyt', - ); - const account2 = new PublicKey( - 'DL8FErokCN7rerLdmJ7tQvsL1FsqDu1sTKLLooWmChiW', - ); - const account3 = new PublicKey( - 'EdPiTYbXFxNrn1vqD7ZdDyauRKG4hMR6wY54RU1YFP2e', - ); - const account4 = new PublicKey( - 'FThXbyKK4kYJBngSSuvo9e6kc7mwPHEgw4V8qdmz1h3k', - ); - const programId = new PublicKey( - 'Gcatgv533efD1z2knsH9UKtkrjRWCZGi12f8MjNaDzmN', - ); - const account5 = new PublicKey( - 'rBtwG4bx85Exjr9cgoupvP1c7VTe7u5B36rzCg1HYgi', - ); - - const recentBlockhash = Keypair.generate().publicKey.toBase58(); - const transaction = new Transaction({ - blockhash: recentBlockhash, - lastValidBlockHeight: 9999, - }).add({ - keys: [ - // Should sort last. - {pubkey: account5, isSigner: false, isWritable: false}, - {pubkey: account5, isSigner: false, isWritable: false}, - // Should be considered writeable. - {pubkey: account4, isSigner: false, isWritable: false}, - {pubkey: account4, isSigner: false, isWritable: true}, - // Should be considered a signer. - {pubkey: account3, isSigner: false, isWritable: false}, - {pubkey: account3, isSigner: true, isWritable: false}, - // Should be considered a writable signer. - {pubkey: account2, isSigner: false, isWritable: true}, - {pubkey: account2, isSigner: true, isWritable: false}, - // Payer. - {pubkey: payer, isSigner: true, isWritable: true}, - ], - programId, - }); - - transaction.feePayer = payer; - - const message = transaction.compileMessage(); - // Payer comes first. - expect(message.accountKeys[0].equals(payer)).to.be.true; - // Writable signer comes first. - expect(message.accountKeys[1].equals(account2)).to.be.true; - // Signer comes next. - expect(message.accountKeys[2].equals(account3)).to.be.true; - // Writable account comes next. - expect(message.accountKeys[3].equals(account4)).to.be.true; - // Regular accounts come last. - expect(message.accountKeys[4].equals(programId)).to.be.true; - expect(message.accountKeys[5].equals(account5)).to.be.true; - }); - - it('payer is first account meta', () => { - const payer = Keypair.generate(); - const other = Keypair.generate(); - const recentBlockhash = Keypair.generate().publicKey.toBase58(); - const programId = Keypair.generate().publicKey; - const transaction = new Transaction({ - blockhash: recentBlockhash, - lastValidBlockHeight: 9999, - }).add({ - keys: [ - {pubkey: other.publicKey, isSigner: true, isWritable: true}, - {pubkey: payer.publicKey, isSigner: true, isWritable: true}, - ], - programId, - }); - - transaction.sign(payer, other); - const message = transaction.compileMessage(); - expect(message.accountKeys[0]).to.eql(payer.publicKey); - expect(message.accountKeys[1]).to.eql(other.publicKey); - expect(message.header.numRequiredSignatures).to.eq(2); - expect(message.header.numReadonlySignedAccounts).to.eq(0); - expect(message.header.numReadonlyUnsignedAccounts).to.eq(1); - }); - - it('validation', () => { - const payer = Keypair.generate(); - const recentBlockhash = Keypair.generate().publicKey.toBase58(); - - const transaction = new Transaction(); - expect(() => { - transaction.compileMessage(); - }).to.throw('Transaction recentBlockhash required'); - - transaction.recentBlockhash = recentBlockhash; - - expect(() => { - transaction.compileMessage(); - }).to.throw('Transaction fee payer required'); - - transaction.setSigners(payer.publicKey, Keypair.generate().publicKey); - - expect(() => { - transaction.compileMessage(); - }).to.throw('unknown signer'); - - // Expect compile to succeed with implicit fee payer from signers - transaction.setSigners(payer.publicKey); - transaction.compileMessage(); - - // Expect compile to succeed with fee payer and no signers - transaction.signatures = []; - transaction.feePayer = payer.publicKey; - transaction.compileMessage(); - }); - - it('payer is writable', () => { - const payer = Keypair.generate(); - const recentBlockhash = Keypair.generate().publicKey.toBase58(); - const programId = Keypair.generate().publicKey; - const transaction = new Transaction({ - blockhash: recentBlockhash, - lastValidBlockHeight: 9999, - }).add({ - keys: [{pubkey: payer.publicKey, isSigner: true, isWritable: false}], - programId, - }); - - transaction.sign(payer); - const message = transaction.compileMessage(); - expect(message.accountKeys[0]).to.eql(payer.publicKey); - expect(message.header.numRequiredSignatures).to.eq(1); - expect(message.header.numReadonlySignedAccounts).to.eq(0); - expect(message.header.numReadonlyUnsignedAccounts).to.eq(1); - }); - - it('uses the nonce as the recent blockhash when compiling nonce-based transactions', () => { - const nonce = new PublicKey(1); - const nonceAuthority = new PublicKey(2); - const nonceInfo = { - nonce: nonce.toBase58(), - nonceInstruction: SystemProgram.nonceAdvance({ - noncePubkey: nonce, - authorizedPubkey: nonceAuthority, - }), - }; - const transaction = new Transaction({ - feePayer: nonceAuthority, - nonceInfo, - }); - const message = transaction.compileMessage(); - expect(message.recentBlockhash).to.equal(nonce.toBase58()); - }); - - it('prepends the nonce advance instruction when compiling nonce-based transactions', () => { - const nonce = new PublicKey(1); - const nonceAuthority = new PublicKey(2); - const nonceInfo = { - nonce: nonce.toBase58(), - nonceInstruction: SystemProgram.nonceAdvance({ - noncePubkey: nonce, - authorizedPubkey: nonceAuthority, - }), - }; - const transaction = new Transaction({ - feePayer: nonceAuthority, - nonceInfo, - }).add( - SystemProgram.transfer({ - fromPubkey: nonceAuthority, - lamports: 1, - toPubkey: new PublicKey(3), - }), - ); - const message = transaction.compileMessage(); - expect(message.instructions).to.have.length(2); - const expectedNonceAdvanceCompiledInstruction = { - accounts: [1, 4, 0], - data: (() => { - const expectedData = Buffer.alloc(4); - expectedData.writeInt32LE( - 4 /* SystemInstruction::AdvanceNonceAccount */, - 0, - ); - return bs58.encode(expectedData); - })(), - programIdIndex: (() => { - let foundIndex = -1; - message.accountKeys.find((publicKey, ii) => { - if (publicKey.equals(SystemProgram.programId)) { - foundIndex = ii; - return true; - } - return; - }); - return foundIndex; - })(), - }; - expect(message.instructions[0]).to.deep.equal( - expectedNonceAdvanceCompiledInstruction, - ); - }); - - it('does not prepend the nonce advance instruction when compiling nonce-based transactions if it is already there', () => { - const nonce = new PublicKey(1); - const nonceAuthority = new PublicKey(2); - const nonceInfo = { - nonce: nonce.toBase58(), - nonceInstruction: SystemProgram.nonceAdvance({ - noncePubkey: nonce, - authorizedPubkey: nonceAuthority, - }), - }; - const transaction = new Transaction({ - feePayer: nonceAuthority, - nonceInfo, - }) - .add(nonceInfo.nonceInstruction) - .add( - SystemProgram.transfer({ - fromPubkey: nonceAuthority, - lamports: 1, - toPubkey: new PublicKey(3), - }), - ); - const message = transaction.compileMessage(); - expect(message.instructions).to.have.length(2); - const expectedNonceAdvanceCompiledInstruction = { - accounts: [1, 4, 0], - data: (() => { - const expectedData = Buffer.alloc(4); - expectedData.writeInt32LE( - 4 /* SystemInstruction::AdvanceNonceAccount */, - 0, - ); - return bs58.encode(expectedData); - })(), - programIdIndex: (() => { - let foundIndex = -1; - message.accountKeys.find((publicKey, ii) => { - if (publicKey.equals(SystemProgram.programId)) { - foundIndex = ii; - return true; - } - return; - }); - return foundIndex; - })(), - }; - expect(message.instructions[0]).to.deep.equal( - expectedNonceAdvanceCompiledInstruction, - ); - }); - }); - - if (process.env.TEST_LIVE) { - it('getEstimatedFee', async () => { - const connection = new Connection(url); - const accountFrom = Keypair.generate(); - const accountTo = Keypair.generate(); - - const latestBlockhash = await helpers.latestBlockhash({connection}); - - const transaction = new Transaction({ - feePayer: accountFrom.publicKey, - ...latestBlockhash, - }).add( - SystemProgram.transfer({ - fromPubkey: accountFrom.publicKey, - toPubkey: accountTo.publicKey, - lamports: 10, - }), - ); - - const fee = await transaction.getEstimatedFee(connection); - expect(fee).to.eq(5000); - }); - } - - it('partialSign', () => { - const account1 = Keypair.generate(); - const account2 = Keypair.generate(); - const recentBlockhash = account1.publicKey.toBase58(); // Fake recentBlockhash - const transfer = SystemProgram.transfer({ - fromPubkey: account1.publicKey, - toPubkey: account2.publicKey, - lamports: 123, - }); - - const transaction = new Transaction({ - blockhash: recentBlockhash, - lastValidBlockHeight: 9999, - }).add(transfer); - transaction.sign(account1, account2); - - const partialTransaction = new Transaction({ - blockhash: recentBlockhash, - lastValidBlockHeight: 9999, - }).add(transfer); - partialTransaction.setSigners(account1.publicKey, account2.publicKey); - expect(partialTransaction.signatures[0].signature).to.be.null; - expect(partialTransaction.signatures[1].signature).to.be.null; - - partialTransaction.partialSign(account1); - expect(partialTransaction.signatures[0].signature).not.to.be.null; - expect(partialTransaction.signatures[1].signature).to.be.null; - - expect(() => partialTransaction.serialize()).to.throw(); - expect(() => - partialTransaction.serialize({requireAllSignatures: false}), - ).not.to.throw(); - - partialTransaction.partialSign(account2); - - expect(partialTransaction.signatures[0].signature).not.to.be.null; - expect(partialTransaction.signatures[1].signature).not.to.be.null; - - expect(() => partialTransaction.serialize()).not.to.throw(); - - expect(partialTransaction).to.eql(transaction); - - invariant(partialTransaction.signatures[0].signature); - partialTransaction.signatures[0].signature.fill(1); - expect(() => - partialTransaction.serialize({requireAllSignatures: false}), - ).to.throw(); - expect(() => - partialTransaction.serialize({ - verifySignatures: false, - requireAllSignatures: false, - }), - ).not.to.throw(); - }); - - describe('dedupe', () => { - const payer = Keypair.generate(); - const duplicate1 = payer; - const duplicate2 = payer; - const recentBlockhash = Keypair.generate().publicKey.toBase58(); - const programId = Keypair.generate().publicKey; - - it('setSigners', () => { - const transaction = new Transaction({ - blockhash: recentBlockhash, - lastValidBlockHeight: 9999, - }).add({ - keys: [ - {pubkey: duplicate1.publicKey, isSigner: true, isWritable: true}, - {pubkey: payer.publicKey, isSigner: false, isWritable: true}, - {pubkey: duplicate2.publicKey, isSigner: true, isWritable: false}, - ], - programId, - }); - - transaction.setSigners( - payer.publicKey, - duplicate1.publicKey, - duplicate2.publicKey, - ); - - expect(transaction.signatures).to.have.length(1); - expect(transaction.signatures[0].publicKey).to.eql(payer.publicKey); - - const message = transaction.compileMessage(); - expect(message.accountKeys[0]).to.eql(payer.publicKey); - expect(message.header.numRequiredSignatures).to.eq(1); - expect(message.header.numReadonlySignedAccounts).to.eq(0); - expect(message.header.numReadonlyUnsignedAccounts).to.eq(1); - - transaction.signatures; - }); - - it('sign', () => { - const transaction = new Transaction({ - blockhash: recentBlockhash, - lastValidBlockHeight: 9999, - }).add({ - keys: [ - {pubkey: duplicate1.publicKey, isSigner: true, isWritable: true}, - {pubkey: payer.publicKey, isSigner: false, isWritable: true}, - {pubkey: duplicate2.publicKey, isSigner: true, isWritable: false}, - ], - programId, - }); - - transaction.sign(payer, duplicate1, duplicate2); - - expect(transaction.signatures).to.have.length(1); - expect(transaction.signatures[0].publicKey).to.eql(payer.publicKey); - - const message = transaction.compileMessage(); - expect(message.accountKeys[0]).to.eql(payer.publicKey); - expect(message.header.numRequiredSignatures).to.eq(1); - expect(message.header.numReadonlySignedAccounts).to.eq(0); - expect(message.header.numReadonlyUnsignedAccounts).to.eq(1); - - transaction.signatures; - }); - }); - - it('transfer signatures', () => { - const account1 = Keypair.generate(); - const account2 = Keypair.generate(); - const recentBlockhash = account1.publicKey.toBase58(); // Fake recentBlockhash - const transfer1 = SystemProgram.transfer({ - fromPubkey: account1.publicKey, - toPubkey: account2.publicKey, - lamports: 123, - }); - const transfer2 = SystemProgram.transfer({ - fromPubkey: account2.publicKey, - toPubkey: account1.publicKey, - lamports: 123, - }); - - const latestBlockhash = { - blockhash: recentBlockhash, - lastValidBlockHeight: 9999, - }; - - const orgTransaction = new Transaction({ - ...latestBlockhash, - }).add(transfer1, transfer2); - orgTransaction.sign(account1, account2); - - const newTransaction = new Transaction({ - ...latestBlockhash, - signatures: orgTransaction.signatures, - }).add(transfer1, transfer2); - - expect(newTransaction).to.eql(orgTransaction); - }); - - it('dedup signatures', () => { - const account1 = Keypair.generate(); - const account2 = Keypair.generate(); - const recentBlockhash = account1.publicKey.toBase58(); // Fake recentBlockhash - const transfer1 = SystemProgram.transfer({ - fromPubkey: account1.publicKey, - toPubkey: account2.publicKey, - lamports: 123, - }); - const transfer2 = SystemProgram.transfer({ - fromPubkey: account1.publicKey, - toPubkey: account2.publicKey, - lamports: 123, - }); - - const orgTransaction = new Transaction({ - blockhash: recentBlockhash, - lastValidBlockHeight: 9999, - }).add(transfer1, transfer2); - orgTransaction.sign(account1); - }); - - it('use nonce', () => { - const account1 = Keypair.generate(); - const account2 = Keypair.generate(); - const nonceAccount = Keypair.generate(); - const nonce = account2.publicKey.toBase58(); // Fake Nonce hash - - const nonceInfo = { - nonce, - nonceInstruction: SystemProgram.nonceAdvance({ - noncePubkey: nonceAccount.publicKey, - authorizedPubkey: account1.publicKey, - }), - }; - - const transferTransaction = new Transaction({nonceInfo}).add( - SystemProgram.transfer({ - fromPubkey: account1.publicKey, - toPubkey: account2.publicKey, - lamports: 123, - }), - ); - transferTransaction.sign(account1); - - expect(transferTransaction.instructions).to.have.length(1); - expect(transferTransaction.recentBlockhash).to.be.undefined; - - const stakeAccount = Keypair.generate(); - const voteAccount = Keypair.generate(); - const stakeTransaction = new Transaction({nonceInfo}).add( - StakeProgram.delegate({ - stakePubkey: stakeAccount.publicKey, - authorizedPubkey: account1.publicKey, - votePubkey: voteAccount.publicKey, - }), - ); - stakeTransaction.sign(account1); - - expect(stakeTransaction.instructions).to.have.length(1); - expect(stakeTransaction.recentBlockhash).to.be.undefined; - }); - - it('parse wire format and serialize', () => { - const sender = Keypair.fromSeed(Uint8Array.from(Array(32).fill(8))); // Arbitrary known account - const recentBlockhash = 'EETubP5AKHgjPAhzPAFcb8BAY1hMH639CWCFTqi3hq1k'; // Arbitrary known recentBlockhash - const recipient = new PublicKey( - 'J3dxNj7nDRRqRRXuEMynDG57DkZK4jYRuv3Garmb1i99', - ); // Arbitrary known public key - const transfer = SystemProgram.transfer({ - fromPubkey: sender.publicKey, - toPubkey: recipient, - lamports: 49, - }); - const expectedTransaction = new Transaction({ - blockhash: recentBlockhash, - feePayer: sender.publicKey, - lastValidBlockHeight: 9999, - }).add(transfer); - expectedTransaction.sign(sender); - - const serializedTransaction = Buffer.from( - 'AVuErQHaXv0SG0/PchunfxHKt8wMRfMZzqV0tkC5qO6owYxWU2v871AoWywGoFQr4z+q/7mE8lIufNl/kxj+nQ0BAAEDE5j2LG0aRXxRumpLXz29L2n8qTIWIY3ImX5Ba9F9k8r9Q5/Mtmcn8onFxt47xKj+XdXXd3C8j/FcPu7csUrz/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxJrndgN4IFTxep3s6kO0ROug7bEsbx0xxuDkqEvwUusBAgIAAQwCAAAAMQAAAAAAAAA=', - 'base64', - ); - const deserializedTransaction = Transaction.from(serializedTransaction); - - expect(expectedTransaction.serialize()).to.eql(serializedTransaction); - expect(deserializedTransaction.serialize()).to.eql(serializedTransaction); - }); - - it('populate transaction', () => { - const recentBlockhash = new PublicKey(1).toString(); - const message = { - accountKeys: [ - new PublicKey(1).toString(), - new PublicKey(2).toString(), - new PublicKey(3).toString(), - new PublicKey(4).toString(), - new PublicKey(5).toString(), - ], - header: { - numReadonlySignedAccounts: 0, - numReadonlyUnsignedAccounts: 3, - numRequiredSignatures: 2, - }, - instructions: [ - { - accounts: [1, 2, 3], - data: bs58.encode(Buffer.alloc(5).fill(9)), - programIdIndex: 4, - }, - ], - recentBlockhash, - }; - - const signatures = [ - bs58.encode(Buffer.alloc(64).fill(1)), - bs58.encode(Buffer.alloc(64).fill(2)), - ]; - - const transaction = Transaction.populate(new Message(message), signatures); - expect(transaction.instructions).to.have.length(1); - expect(transaction.signatures).to.have.length(2); - expect(transaction.recentBlockhash).to.eq(recentBlockhash); - }); - - it('populate then compile transaction', () => { - const recentBlockhash = new PublicKey(1).toString(); - const message = new Message({ - accountKeys: [ - new PublicKey(1).toString(), - new PublicKey(2).toString(), - new PublicKey(3).toString(), - new PublicKey(4).toString(), - new PublicKey(5).toString(), - ], - header: { - numReadonlySignedAccounts: 0, - numReadonlyUnsignedAccounts: 3, - numRequiredSignatures: 2, - }, - instructions: [ - { - accounts: [1, 2, 3], - data: bs58.encode(Buffer.alloc(5).fill(9)), - programIdIndex: 2, - }, - ], - recentBlockhash, - }); - - const signatures = [ - bs58.encode(Buffer.alloc(64).fill(1)), - bs58.encode(Buffer.alloc(64).fill(2)), - ]; - - const transaction = Transaction.populate(message, signatures); - const compiledMessage = transaction.compileMessage(); - expect(compiledMessage).to.eql(message); - - // show that without caching the message, the populated message - // might not be the same when re-compiled - transaction._message = undefined; - const compiledMessage2 = transaction.compileMessage(); - expect(compiledMessage2).not.to.eql(message); - - // show that even if message is cached, transaction may still - // be modified - transaction._message = message; - transaction.recentBlockhash = new PublicKey(100).toString(); - const compiledMessage3 = transaction.compileMessage(); - expect(compiledMessage3).not.to.eql(message); - }); - - it('constructs a transaction with nonce info', () => { - const nonce = new PublicKey(1); - const nonceAuthority = new PublicKey(2); - const nonceInfo = { - nonce: nonce.toBase58(), - nonceInstruction: SystemProgram.nonceAdvance({ - noncePubkey: nonce, - authorizedPubkey: nonceAuthority, - }), - }; - const transaction = new Transaction({nonceInfo}); - expect(transaction.recentBlockhash).to.be.undefined; - expect(transaction.lastValidBlockHeight).to.be.undefined; - expect(transaction.nonceInfo).to.equal(nonceInfo); - }); - - it('constructs a transaction with last valid block height', () => { - const blockhash = 'EETubP5AKHgjPAhzPAFcb8BAY1hMH639CWCFTqi3hq1k'; - const lastValidBlockHeight = 1234; - const transaction = new Transaction({ - blockhash, - lastValidBlockHeight, - }); - expect(transaction.recentBlockhash).to.eq(blockhash); - expect(transaction.lastValidBlockHeight).to.eq(lastValidBlockHeight); - }); - - it('constructs a transaction with nonce information', () => { - const nonceAuthority = new PublicKey(1); - const nonceAccountPubkey = new PublicKey(2); - const nonceValue = 'EETubP5AKHgjPAhzPAFcb8BAY1hMH639CWCFTqi3hq1k'; - const nonceInfo = { - nonce: nonceValue, - nonceInstruction: SystemProgram.nonceAdvance({ - noncePubkey: nonceAccountPubkey, - authorizedPubkey: nonceAuthority, - }), - }; - const minContextSlot = 1234; - const transaction = new Transaction({ - nonceInfo, - minContextSlot, - }); - expect(transaction.recentBlockhash).to.be.undefined; - expect(transaction.lastValidBlockHeight).to.be.undefined; - expect(transaction.minNonceContextSlot).to.eq(minContextSlot); - expect(transaction.nonceInfo).to.eq(nonceInfo); - }); - - it('constructs a transaction with only a recent blockhash', () => { - const recentBlockhash = 'EETubP5AKHgjPAhzPAFcb8BAY1hMH639CWCFTqi3hq1k'; - const transaction = new Transaction({ - recentBlockhash, - }); - expect(transaction.recentBlockhash).to.eq(recentBlockhash); - expect(transaction.lastValidBlockHeight).to.be.undefined; - }); - - it('serialize unsigned transaction', () => { - const sender = Keypair.fromSeed(Uint8Array.from(Array(32).fill(8))); // Arbitrary known account - const recentBlockhash = 'EETubP5AKHgjPAhzPAFcb8BAY1hMH639CWCFTqi3hq1k'; // Arbitrary known recentBlockhash - const recipient = new PublicKey( - 'J3dxNj7nDRRqRRXuEMynDG57DkZK4jYRuv3Garmb1i99', - ); // Arbitrary known public key - const transfer = SystemProgram.transfer({ - fromPubkey: sender.publicKey, - toPubkey: recipient, - lamports: 49, - }); - const expectedTransaction = new Transaction({ - blockhash: recentBlockhash, - lastValidBlockHeight: 9999, - }).add(transfer); - - // Empty signature array fails. - expect(expectedTransaction.signatures).to.have.length(0); - expect(() => { - expectedTransaction.serialize(); - }).to.throw('Transaction fee payer required'); - expect(() => { - expectedTransaction.serialize({verifySignatures: false}); - }).to.throw('Transaction fee payer required'); - expect(() => { - expectedTransaction.serializeMessage(); - }).to.throw('Transaction fee payer required'); - - expectedTransaction.feePayer = sender.publicKey; - - // Serializing without signatures is allowed if sigverify disabled. - expectedTransaction.serialize({verifySignatures: false}); - - // Serializing the message is allowed when signature array has null signatures - expectedTransaction.serializeMessage(); - - const expectedSerializationWithNoSignatures = Buffer.from( - 'AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' + - 'AAAAAAAAAAAAAAAAAAABAAEDE5j2LG0aRXxRumpLXz29L2n8qTIWIY3ImX5Ba9F9k8r9' + - 'Q5/Mtmcn8onFxt47xKj+XdXXd3C8j/FcPu7csUrz/AAAAAAAAAAAAAAAAAAAAAAAAAAA' + - 'AAAAAAAAAAAAAAAAxJrndgN4IFTxep3s6kO0ROug7bEsbx0xxuDkqEvwUusBAgIAAQwC' + - 'AAAAMQAAAAAAAAA=', - 'base64', - ); - expect(expectedTransaction.serialize({requireAllSignatures: false})).to.eql( - expectedSerializationWithNoSignatures, - ); - - // Properly signed transaction succeeds - expectedTransaction.partialSign(sender); - expect(expectedTransaction.signatures).to.have.length(1); - const expectedSerialization = Buffer.from( - 'AVuErQHaXv0SG0/PchunfxHKt8wMRfMZzqV0tkC5qO6owYxWU2v871AoWywGoFQr4z+q/7mE8lIufNl/' + - 'kxj+nQ0BAAEDE5j2LG0aRXxRumpLXz29L2n8qTIWIY3ImX5Ba9F9k8r9Q5/Mtmcn8onFxt47xKj+XdXX' + - 'd3C8j/FcPu7csUrz/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxJrndgN4IFTxep3s6kO0' + - 'ROug7bEsbx0xxuDkqEvwUusBAgIAAQwCAAAAMQAAAAAAAAA=', - 'base64', - ); - expect(expectedTransaction.serialize()).to.eql(expectedSerialization); - expect(expectedTransaction.signatures).to.have.length(1); - }); - - it('throws for invalid signatures', () => { - const sender = Keypair.fromSeed(Uint8Array.from(Array(32).fill(8))); // Arbitrary known account - const recentBlockhash = 'EETubP5AKHgjPAhzPAFcb8BAY1hMH639CWCFTqi3hq1k'; // Arbitrary known recentBlockhash - const recipient = new PublicKey( - 'J3dxNj7nDRRqRRXuEMynDG57DkZK4jYRuv3Garmb1i99', - ); // Arbitrary known public key - const transfer = SystemProgram.transfer({ - fromPubkey: sender.publicKey, - toPubkey: recipient, - lamports: 49, - }); - const sampleTransaction = new Transaction({ - blockhash: recentBlockhash, - lastValidBlockHeight: 9999, - }).add(transfer); - sampleTransaction.feePayer = sender.publicKey; - - // Transactions with missing signatures will fail sigverify. - expect(() => { - sampleTransaction.serialize(); - }).to.throw( - `Signature verification failed.\nMissing signature for public key [\`${sender.publicKey.toBase58()}\`].`, - ); - - // Serializing without signatures is allowed if sigverify disabled. - sampleTransaction.serialize({verifySignatures: false}); - - // Serializing the message is allowed when signature array has null signatures - sampleTransaction.serializeMessage(); - - sampleTransaction.feePayer = undefined; - sampleTransaction.setSigners(sender.publicKey); - expect(sampleTransaction.signatures).to.have.length(1); - sampleTransaction.signatures[0].signature = Buffer.allocUnsafe(64).fill(0); - - // Transactions with invalid signature will fail sigverify. - expect(() => { - sampleTransaction.serialize(); - }).to.throw( - `Signature verification failed.\nInvalid signature for public key [\`${sender.publicKey.toBase58()}\`].`, - ); - - const tempKey = Keypair.generate(); - sampleTransaction.feePayer = tempKey.publicKey; - sampleTransaction.signatures[0] = { - signature: null, - publicKey: tempKey.publicKey, - }; - sampleTransaction.signatures[1] = { - signature: Buffer.allocUnsafe(64).fill(42), - publicKey: sender.publicKey, - }; - - // Transactions with invalid signature and missing signature will fail sigverify and throw both. - expect(() => { - sampleTransaction.serialize(); - }).to.throw( - `Signature verification failed.\nInvalid signature for public key [\`${sender.publicKey.toBase58()}\`].\nMissing signature for public key [\`${tempKey.publicKey.toBase58()}\`].`, - ); - }); - - describe('partially signed transaction signature verification tests', () => { - const sender = Keypair.fromSeed(Uint8Array.from(Array(32).fill(8))); // Arbitrary known account - const feePayer = Keypair.fromSeed(Uint8Array.from(Array(32).fill(9))); // Arbitrary known account - const fakeKey = Keypair.fromSeed(Uint8Array.from(Array(32).fill(10))); // Arbitrary known account - const recentBlockhash = 'EETubP5AKHgjPAhzPAFcb8BAY1hMH639CWCFTqi3hq1k'; // Arbitrary known recentBlockhash - const recipient = new PublicKey( - 'J3dxNj7nDRRqRRXuEMynDG57DkZK4jYRuv3Garmb1i99', - ); // Arbitrary known public key - const transfer = SystemProgram.transfer({ - fromPubkey: sender.publicKey, - toPubkey: recipient, - lamports: 49, - }); - let expectedTransaction: Transaction; - beforeEach(() => { - expectedTransaction = new Transaction({ - blockhash: recentBlockhash, - lastValidBlockHeight: 9999, - }).add(transfer); - // To have 2 required signers we add a feepayer - expectedTransaction.feePayer = feePayer.publicKey; - }); - - it('verifies for no sigs', () => { - expect(expectedTransaction.signatures).to.have.length(0); - - // No extra param should require all sigs, should be false for no sigs - expect(expectedTransaction.verifySignatures()).to.be.false; - - // True should require all sigs, should be false for no sigs - expect(expectedTransaction.verifySignatures(true)).to.be.false; - - // False should verify only the available sigs, should be true for no sigs - expect(expectedTransaction.verifySignatures(false)).to.be.true; - }); - - it('verifies for one sig', () => { - // Add one required sig - expectedTransaction.partialSign(sender); - - expect( - expectedTransaction.signatures.filter(sig => sig.signature !== null), - ).to.have.length(1); - - // No extra param should require all sigs, should be false for one missing sig - expect(expectedTransaction.verifySignatures()).to.be.false; - - // True should require all sigs, should be false one missing sigs - expect(expectedTransaction.verifySignatures(true)).to.be.false; - - // False should verify only the available sigs, should be true one valid sig - expect(expectedTransaction.verifySignatures(false)).to.be.true; - }); - - it('verifies for all sigs', () => { - // Add all required sigs - expectedTransaction.partialSign(sender); - expectedTransaction.partialSign(feePayer); - - expect( - expectedTransaction.signatures.filter(sig => sig.signature !== null), - ).to.have.length(2); - - // No extra param should require all sigs, should be true for no missing sig - expect(expectedTransaction.verifySignatures()).to.be.true; - - // True should require all sigs, should be true for no missing sig - expect(expectedTransaction.verifySignatures(true)).to.be.true; - - // False should verify only the available sigs, should be true for no missing sig - expect(expectedTransaction.verifySignatures(false)).to.be.true; - }); - - it('throws for wrong sig with only one sig present', () => { - // Add one required sigs - expectedTransaction.partialSign(feePayer); - - // Add a wrong signature - expectedTransaction.signatures[0].publicKey = fakeKey.publicKey; - - // No extra param should require all sigs, should throw for wrong sig - expect(() => expectedTransaction.verifySignatures()).to.throw( - 'unknown signer: ' + fakeKey.publicKey.toBase58(), - ); - - // True should require all sigs, should throw for wrong sig - expect(() => expectedTransaction.verifySignatures(true)).to.throw( - 'unknown signer: ' + fakeKey.publicKey.toBase58(), - ); - - // False should verify only the available sigs, should throw for wrong sig - expect(() => expectedTransaction.verifySignatures(false)).to.throw( - 'unknown signer: ' + fakeKey.publicKey.toBase58(), - ); - }); - - it('throws for wrong sig with all sigs present', () => { - // Add all required sigs - expectedTransaction.partialSign(sender); - expectedTransaction.partialSign(feePayer); - - // Add a wrong signature - expectedTransaction.signatures[0].publicKey = fakeKey.publicKey; - - // No extra param should require all sigs, should throw for wrong sig - expect(() => expectedTransaction.verifySignatures()).to.throw( - 'unknown signer: ' + fakeKey.publicKey.toBase58(), - ); - - // True should require all sigs, should throw for wrong sig - expect(() => expectedTransaction.verifySignatures(true)).to.throw( - 'unknown signer: ' + fakeKey.publicKey.toBase58(), - ); - - // False should verify only the available sigs, should throw for wrong sig - expect(() => expectedTransaction.verifySignatures(false)).to.throw( - 'unknown signer: ' + fakeKey.publicKey.toBase58(), - ); - }); - }); - - it('deprecated - externally signed stake delegate', () => { - const authority = Keypair.fromSeed(Uint8Array.from(Array(32).fill(1))); - const stake = new PublicKey(2); - const recentBlockhash = new PublicKey(3).toBuffer(); - const vote = new PublicKey(4); - var tx = StakeProgram.delegate({ - stakePubkey: stake, - authorizedPubkey: authority.publicKey, - votePubkey: vote, - }); - const from = authority; - tx.recentBlockhash = bs58.encode(recentBlockhash); - tx.setSigners(from.publicKey); - const tx_bytes = tx.serializeMessage(); - const signature = sign(tx_bytes, from.secretKey); - tx.addSignature(from.publicKey, toBuffer(signature)); - expect(tx.verifySignatures()).to.be.true; - }); - - it('externally signed stake delegate', () => { - const authority = Keypair.fromSeed(Uint8Array.from(Array(32).fill(1))); - const stake = new PublicKey(2); - const recentBlockhash = new PublicKey(3).toBuffer(); - const vote = new PublicKey(4); - var tx = StakeProgram.delegate({ - stakePubkey: stake, - authorizedPubkey: authority.publicKey, - votePubkey: vote, - }); - const from = authority; - tx.recentBlockhash = bs58.encode(recentBlockhash); - tx.feePayer = from.publicKey; - const tx_bytes = tx.serializeMessage(); - const signature = sign(tx_bytes, from.secretKey); - tx.addSignature(from.publicKey, toBuffer(signature)); - expect(tx.verifySignatures()).to.be.true; - }); - - it('can serialize, deserialize, and reserialize with a partial signer', () => { - const signer = Keypair.generate(); - const acc0Writable = Keypair.generate(); - const acc1Writable = Keypair.generate(); - const acc2Writable = Keypair.generate(); - const t0 = new Transaction({ - blockhash: 'HZaTsZuhN1aaz9WuuimCFMyH7wJ5xiyMUHFCnZSMyguH', - feePayer: signer.publicKey, - lastValidBlockHeight: 9999, - }); - t0.add( - new TransactionInstruction({ - keys: [ - { - pubkey: signer.publicKey, - isWritable: true, - isSigner: true, - }, - { - pubkey: acc0Writable.publicKey, - isWritable: true, - isSigner: false, - }, - ], - programId: Keypair.generate().publicKey, - }), - ); - t0.add( - new TransactionInstruction({ - keys: [ - { - pubkey: acc1Writable.publicKey, - isWritable: false, - isSigner: false, - }, - ], - programId: Keypair.generate().publicKey, - }), - ); - t0.add( - new TransactionInstruction({ - keys: [ - { - pubkey: acc2Writable.publicKey, - isWritable: true, - isSigner: false, - }, - ], - programId: Keypair.generate().publicKey, - }), - ); - t0.add( - new TransactionInstruction({ - keys: [ - { - pubkey: signer.publicKey, - isWritable: true, - isSigner: true, - }, - { - pubkey: acc0Writable.publicKey, - isWritable: false, - isSigner: false, - }, - { - pubkey: acc2Writable.publicKey, - isWritable: false, - isSigner: false, - }, - { - pubkey: acc1Writable.publicKey, - isWritable: true, - isSigner: false, - }, - ], - programId: Keypair.generate().publicKey, - }), - ); - const t1 = Transaction.from(t0.serialize({requireAllSignatures: false})); - t1.partialSign(signer); - t1.serialize(); - }); -}); - -describe('VersionedTransaction', () => { - it('deserializes versioned transactions', () => { - const serializedVersionedTx = Buffer.from( - 'AdTIDASR42TgVuXKkd7mJKk373J3LPVp85eyKMVcrboo9KTY8/vm6N/Cv0NiHqk2I8iYw6VX5ZaBKG8z' + - '9l1XjwiAAQACA+6qNbqfjaIENwt9GzEK/ENiB/ijGwluzBUmQ9xlTAMcCaS0ctnyxTcXXlJr7u2qtnaM' + - 'gIAO2/c7RBD0ipHWUcEDBkZv5SEXMv/srbpyw5vnvIzlu8X3EmssQ5s6QAAAAJbI7VNs6MzREUlnzRaJ' + - 'pBKP8QQoDn2dWQvD0KIgHFDiAwIACQAgoQcAAAAAAAIABQEAAAQAATYPBwAKBDIBAyQWIw0oCxIdCA4i' + - 'JzQRKwUZHxceHCohMBUJJiwpMxAaGC0TLhQxGyAMBiU2NS8VDgAAAADuAgAAAAAAAAIAAAAAAAAAAdGCT' + - 'Qiq5yw3+3m1sPoRNj0GtUNNs0FIMocxzt3zuoSZHQABAwQFBwgLDA8RFBcYGhwdHh8iIyUnKiwtLi8yF' + - 'wIGCQoNDhASExUWGRsgISQmKCkrMDEz', - 'base64', - ); - - expect(() => Transaction.from(serializedVersionedTx)).to.throw( - 'Versioned messages must be deserialized with VersionedMessage.deserialize()', - ); - - const versionedTx = VersionedTransaction.deserialize(serializedVersionedTx); - expect(versionedTx.message.version).to.eq(0); - }); - - describe('addSignature', () => { - const signer1 = Keypair.generate(); - const signer2 = Keypair.generate(); - const signer3 = Keypair.generate(); - - const recentBlockhash = new PublicKey(3).toBuffer(); - - const message = new TransactionMessage({ - payerKey: signer1.publicKey, - instructions: [ - new TransactionInstruction({ - data: Buffer.from('Hello!'), - keys: [ - { - pubkey: signer1.publicKey, - isSigner: true, - isWritable: true, - }, - { - pubkey: signer2.publicKey, - isSigner: true, - isWritable: true, - }, - { - pubkey: signer3.publicKey, - isSigner: false, - isWritable: false, - }, - ], - programId: new PublicKey( - 'MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr', - ), - }), - ], - recentBlockhash: bs58.encode(recentBlockhash), - }); - - const transaction = new VersionedTransaction(message.compileToV0Message()); - - it('appends externally generated signatures at correct indexes', () => { - const signature1 = sign( - transaction.message.serialize(), - signer1.secretKey, - ); - const signature2 = sign( - transaction.message.serialize(), - signer2.secretKey, - ); - - transaction.addSignature(signer2.publicKey, signature2); - transaction.addSignature(signer1.publicKey, signature1); - - expect(transaction.signatures).to.have.length(2); - expect(transaction.signatures[0]).to.eq(signature1); - expect(transaction.signatures[1]).to.eq(signature2); - }); - - it('fatals when the signature is the wrong length', () => { - expect(() => { - transaction.addSignature(signer1.publicKey, new Uint8Array(32)); - }).to.throw('Signature must be 64 bytes long'); - }); - - it('fatals when adding a signature for a public key that has not been marked as a signer', () => { - expect(() => { - transaction.addSignature(signer3.publicKey, new Uint8Array(64)); - }).to.throw( - `Can not add signature; \`${signer3.publicKey.toBase58()}\` is not required to sign this transaction`, - ); - }); - }); -}); diff --git a/packages/library-legacy/test/url.ts b/packages/library-legacy/test/url.ts deleted file mode 100644 index 025d81b4d9db..000000000000 --- a/packages/library-legacy/test/url.ts +++ /dev/null @@ -1,29 +0,0 @@ -import {AbortController as AbortControllerPolyfill} from 'node-abort-controller'; -/** - * The connection url to use when running unit tests against a live cluster - */ -export const MOCK_PORT = 9999; - -declare var process: { - env: { - TEST_LIVE: string; - }; - version: string; -}; - -export const url = process.env.TEST_LIVE - ? 'http://127.0.0.1:8899/' - : 'http://127.0.0.1:9999/'; - -export const wsUrl = process.env.TEST_LIVE - ? 'ws://127.0.0.1:8900/' - : 'ws://127.0.0.1:9999/'; - -export const nodeVersion = Number(process.version.split('.')[0]); - -export const Node14Controller = function () { - return new AbortControllerPolyfill(); -}; - -//export const url = 'https://api.devnet.solana.com/'; -//export const url = 'http://api.devnet.solana.com/'; diff --git a/packages/library-legacy/test/validator-info.test.ts b/packages/library-legacy/test/validator-info.test.ts deleted file mode 100644 index 1f9970d2886e..000000000000 --- a/packages/library-legacy/test/validator-info.test.ts +++ /dev/null @@ -1,38 +0,0 @@ -import {Buffer} from 'buffer'; -import {expect} from 'chai'; - -import {Keypair} from '../src/keypair'; -import {PublicKey} from '../src/publickey'; -import {ValidatorInfo} from '../src/validator-info'; - -describe('ValidatorInfo', () => { - it('from config account data', () => { - const keypair = Keypair.fromSeed(Uint8Array.from(Array(32).fill(8))); - - const expectedValidatorInfo = new ValidatorInfo( - new PublicKey(keypair.publicKey), - { - name: 'Validator', - keybaseUsername: 'validator_id', - iconUrl: 'https://example.com/icon', - }, - ); - - // Config data string steps: - // 1) Generate a keypair - // 2) Airdrop lamports to the account - // 3) Modify the `solana-validator-info` tool - // a) Remove the keybase id verification step - // b) Print base64 account data in the `get --all` codepath - // c) Add `println!("Account data: {:?}", base64::encode(&account.data));` - // 4) Use modified `solana-validator-info` tool to publish validator info - // 5) And then use it again to fetch the data! (feel free to trim some A's) - const configData = Buffer.from( - 'AgdRlwF0SPKsXcI8nrx6x4wKJyV6xhRFjeCk8W+AAAAAABOY9ixtGkV8UbpqS189vS9p/KkyFiGNyJl+QWvRfZPKAVoAAAAAAAAAeyJrZXliYXNlVXNlcm5hbWUiOiJ2YWxpZGF0b3JfaWQiLCJuYW1lIjoiVmFsaWRhdG9yIiwiaWNvblVybCI6Imh0dHBzOi8vZXhhbXBsZS5jb20vaWNvbiJ9', - 'base64', - ); - const info = ValidatorInfo.fromConfigData(configData); - - expect(info).to.eql(expectedValidatorInfo); - }); -}); diff --git a/packages/library-legacy/test/websocket.test.ts b/packages/library-legacy/test/websocket.test.ts deleted file mode 100644 index 625c725641b6..000000000000 --- a/packages/library-legacy/test/websocket.test.ts +++ /dev/null @@ -1,94 +0,0 @@ -import bs58 from 'bs58'; -import {Buffer} from 'buffer'; -import {expect, use} from 'chai'; -import chaiAsPromised from 'chai-as-promised'; - -import {Connection} from '../src'; -import {url, wsUrl} from './url'; -import {sleep} from '../src/utils/sleep'; - -use(chaiAsPromised); - -if (process.env.TEST_LIVE) { - describe('websocket', () => { - const connection = new Connection(url); - - it('connect and disconnect', async () => { - const testSignature = bs58.encode(Buffer.alloc(64)); - const id = connection.onSignature(testSignature, () => {}); - - // wait for websocket to connect - await sleep(100); - expect(connection._rpcWebSocketConnected).to.be.true; - expect(connection._rpcWebSocketHeartbeat).not.to.eq(null); - - // test if socket is open - let open = false; - while (!open) { - try { - await connection._rpcWebSocket.notify('ping'); - open = true; - } catch { - continue; - } - } - - await connection.removeSignatureListener(id); - expect(connection._rpcWebSocketConnected).to.eq(false); - expect(connection._rpcWebSocketHeartbeat).not.to.eq(null); - expect(connection._rpcWebSocketIdleTimeout).not.to.eq(null); - - // wait for websocket to disconnect - await sleep(1100); - expect(connection._rpcWebSocketConnected).to.eq(false); - expect(connection._rpcWebSocketHeartbeat).to.eq(null); - expect(connection._rpcWebSocketIdleTimeout).to.eq(null); - - // test if socket is closed - await expect(connection._rpcWebSocket.notify('ping')).to.be.rejectedWith( - 'Tried to send a JSON-RPC notification `ping` but the socket was not `CONNECTING` or `OPEN` (`readyState` was 3)', - ); - }); - - it('idle timeout', async () => { - const testSignature = bs58.encode(Buffer.alloc(64)); - const id = connection.onSignature(testSignature, () => {}); - - // wait for websocket to connect - await sleep(100); - expect(connection._rpcWebSocketIdleTimeout).to.eq(null); - - await connection.removeSignatureListener(id); - expect(connection._rpcWebSocketIdleTimeout).not.to.eq(null); - - const nextId = connection.onSignature(testSignature, () => {}); - - // wait for websocket to connect - await sleep(100); - expect(connection._rpcWebSocketIdleTimeout).to.eq(null); - - await connection.removeSignatureListener(nextId); - expect(connection._rpcWebSocketIdleTimeout).not.to.eq(null); - - // wait for websocket to disconnect - await sleep(1100); - expect(connection._rpcWebSocketIdleTimeout).to.eq(null); - }); - - it('connect by websocket endpoint from options', async () => { - let connection = new Connection('http://127.0.0.1', { - wsEndpoint: wsUrl, - }); - - const testSignature = bs58.encode(Buffer.alloc(64)); - const id = connection.onSignature(testSignature, () => {}); - - // wait for websocket to connect - await sleep(100); - expect(connection._rpcWebSocketConnected).to.be.true; - expect(connection._rpcWebSocketHeartbeat).not.to.eq(null); - - await connection.removeSignatureListener(id); - }); - }); -} diff --git a/packages/library-legacy/tsconfig.d.json b/packages/library-legacy/tsconfig.d.json deleted file mode 100644 index c7596c0229d2..000000000000 --- a/packages/library-legacy/tsconfig.d.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "emitDeclarationOnly": true, - "stripInternal": true, - "paths": { - "@types/jest": [ - "./test/__shadow-jest-types.d.ts" - ] - } - }, - "include": [ - "src" - ] -} \ No newline at end of file diff --git a/packages/library-legacy/tsconfig.json b/packages/library-legacy/tsconfig.json deleted file mode 100755 index 2aae957d75a7..000000000000 --- a/packages/library-legacy/tsconfig.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "$schema": "https://json.schemastore.org/tsconfig", - "display": "@solana/web3.js", - "compilerOptions": { - "allowJs": true, - "allowSyntheticDefaultImports": true, - "declarationDir": "declarations", - "module": "esnext", - "noImplicitReturns": true, - "outDir": "lib", - "resolveJsonModule": true, - "strict": true, - "paths": { - "@types/jest": ["./test/__shadow-jest-types.d.ts"] - } - }, - "extends": "../tsconfig/base.json", - "include": ["src", "test"], - "exclude": ["declarations", "lib", "node_modules"] -} diff --git a/packages/library-legacy/typedoc.json b/packages/library-legacy/typedoc.json deleted file mode 100644 index 30655cef36c6..000000000000 --- a/packages/library-legacy/typedoc.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "$schema": "https://typedoc.org/schema.json", - "entryPoints": ["./src/index.ts"], - "excludeInternal": true, - "excludePrivate": true, - "intentionallyNotExported": ["src/fetch-impl.ts:default"], - "out": "doc" -} diff --git a/packages/library/CHANGELOG.md b/packages/library/CHANGELOG.md index 08220fd09f15..3fa68f15152d 100644 --- a/packages/library/CHANGELOG.md +++ b/packages/library/CHANGELOG.md @@ -1,4 +1,4 @@ -# @solana/web3.js-experimental +# @solana/web3.js ## 2.0.0-preview.4 diff --git a/packages/library/README.md b/packages/library/README.md index 091ad7413b95..567cc879d0ad 100644 --- a/packages/library/README.md +++ b/packages/library/README.md @@ -6,861 +6,57 @@ [code-style-prettier-image]: https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square [code-style-prettier-url]: https://github.com/prettier/prettier -[npm-downloads-image]: https://img.shields.io/npm/dm/@solana/web3.js/preview.svg?style=flat -[npm-image]: https://img.shields.io/npm/v/@solana/web3.js/preview.svg?style=flat -[npm-url]: https://www.npmjs.com/package/@solana/web3.js/v/preview +[npm-downloads-image]: https://img.shields.io/npm/dm/@solana/web3.js/experimental.svg?style=flat +[npm-image]: https://img.shields.io/npm/v/@solana/web3.js/experimental.svg?style=flat +[npm-url]: https://www.npmjs.com/package/@solana/web3.js/v/experimental [semantic-release-image]: https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg [semantic-release-url]: https://github.com/semantic-release/semantic-release -# Solana JavaScript SDK 2.0 Release Candidate +# @solana/web3.js -If you build JavaScript applications on Solana, it’s likely you’ve worked with `@solana/web3.js` or a library powered by it. With 350K+ weekly downloads on npm, it’s the most-used library in the ecosystem for building program clients, web applications, block explorers, and more. +This is the JavaScript SDK for building Solana apps for Node, web, and React Native. -Here’s an example of a common code snippet from `@solana/web3.js`: +## Functions -```ts -const connection = new Connection('https://api.mainnet-beta.solana.com'); -const instruction = SystemProgram.transfer({ fromPubkey, toPubkey, lamports }); -const transaction = new Transaction().add(instruction); -await sendAndConfirmTransaction(connection, transaction, [payer]); -``` - -In response to your feedback, we began a process of modernizing the library to prepare for the next generation of Solana applications. A Release Candidate of the new web3.js is now available for you to evaluate. - -Before leaving the Release Candidate stage, we want to collect as much of your feeback and bug reports as possible. If you find a bug or can not achieve your goals because of the design of the new APIs, please file [a GitHub issue here](https://github.com/solana-labs/solana-web3.js/issues/new/choose). - -# Installation - -For use in a Node.js or web application: - -```shell -npm install --save @solana/web3.js@rc -``` - -For use in a browser, without a build system: - -```html - - - - - -``` - -# Examples - -To get a feel for the new API, run and modify the live examples in the `examples/` directory. There, you will find a series of single-purpose Node scripts that demonstrate a specific feature or use case. You will also find a React application that you can run in a browser, that demonstrates being able to create, sign, and send transactions using browser wallets. - -# What's New - -Version 2.0 of the Solana JavaScript SDK is a response to many of the pain points you have communicated to us when developing Solana applications with web3.js. We’ve heard you loud and clear. - -## Tree-Shakability - -The object-oriented design of the web3.js (1.x) API prevents optimizing compilers from being able to ‘tree-shake’ unused code from your production builds. No matter how much of the web3.js API you use in your application, you have until now been forced to package all of it. - -Read more about tree-shaking here: - -- [Mozilla Developer Docs: Tree Shaking](https://developer.mozilla.org/en-US/docs/Glossary/Tree_shaking) -- [WebPack Docs: Tree Shaking](https://webpack.js.org/guides/tree-shaking/) -- [Web.Dev Blog Article: Reduce JavaScript Payloads with Tree Shaking](https://web.dev/articles/reduce-javascript-payloads-with-tree-shaking) - -One example of an API that can’t be tree-shaken is the `Connection` class. It has dozens of methods, but because it’s a _class_ you have no choice but to include every method in your application’s final bundle, no matter how many you _actually_ use. - -Needlessly large JavaScript bundles can cause issues with deployments to cloud compute providers like Cloudflare or AWS Lambda. They also impact webapp startup performance because of longer download and JavaScript parse times. - -Version 2.0 is fully tree-shakable and will remain so, enforced by build-time checks. Optimizing compilers can now eliminate those parts of the library that your application does not use. - -The new library itself is comprised of several smaller, modular packages under the `@solana` organization, including: - -- `@solana/accounts`: For fetching and decoding accounts -- `@solana/codecs`: For composing data (de)serializers from a set of primitives or building custom ones -- `@solana/errors`: For identifying and refining coded errors thrown in the `@solana` namespace -- `@solana/rpc`: For sending RPC requests -- `@solana/rpc-subscriptions`: For subscribing to RPC notifications -- `@solana/signers`: For building message and/or transaction signer objects -- `@solana/sysvars`: For fetching and decoding sysvar accounts -- `@solana/transaction-messages`: For building and transforming Solana transaction message objects -- `@solana/transactions`: For compiling and signing transactions for submission to the network -- And many more! - -Some of these packages are themselves composed of smaller packages. For instance, `@solana/rpc` is composed of `@solana/rpc-spec` (for core JSON RPC specification types), `@solana/rpc-api` (for the Solana-specific RPC methods), `@solana/rpc-transport-http` (for the default HTTP transport) and so on. - -Developers can use the default configurations within the main library (`@solana/web3.js@rc`) or import any of its subpackages where customization-through-composition is desired. - -## Composable Internals - -Depending on your use case and your tolerance for certain application behaviours, you may wish to configure your application to make a different set of tradeoffs than another developer. The web3.js (1.x) API imposed a rigid set of common-case defaults on _all_ developers, some of which were impossible to change. - -The inability to customize web3.js up until now has been a source of frustration: - -- The Mango team wanted to customize the transaction confirmation strategy, but all of that functionality is hidden away behind `confirmTransaction` – a static method of `Connection`. [Here’s the code for `confirmTransaction` on GitHub](https://github.com/solana-labs/solana-web3.js/blob/69a8ad25ef09f9e6d5bff1ffa8428d9be0bd32ac/packages/library-legacy/src/connection.ts#L3734). -- Solana developer ‘mPaella’ [wanted us to add a feature in the RPC](https://github.com/solana-labs/solana-web3.js/issues/1143#issuecomment-1435927152) that would failover to a set of backup URLs in case the primary one failed. -- Solana developer ‘epicfaace’ wanted first-class support for automatic time-windowed batching in the RPC transport. [Here’s their pull request](https://github.com/solana-labs/solana/pull/23628). -- Multiple folks have expressed the need for custom retry logic for failed requests or transactions. [Here’s a pull request from ‘dafyddd’](https://github.com/solana-labs/solana/pull/11811) and [another from ‘abrkn’](https://github.com/solana-labs/solana-web3.js/issues/1041) attempting to modify retry logic to suit their individual use cases. - -Version 2.0 exposes far more of its internals, particularly where communication with an RPC is concerned, and allows willing developers the ability to compose new implementations from the default ones that manifest a nearly limitless array of customizations. - -The individual modules that make up web3.js are assembled in a **default** configuration reminiscent of the legacy library as part of the npm package `@solana/web3.js@rc`, but those who wish to assemble them in different configurations may do so. - -Generic types are offered in numerous places, allowing you to specify new functionality, to make extensions to each API via composition and supertypes, and to encourage you to create higher-level opinionated abstractions of your own. - -In fact, we expect you to do so, and to open source some of those for use by others with similar needs. - -## Modern JavaScript; Zero-Dependency - -The advance of modern JavaScript features presents an opportunity to developers of crypto applications, such as the ability to use native Ed25519 keys and to express large values as native `bigint`. - -The Web Incubator Community Group has advocated for the addition of Ed25519 support to the [Web Crypto API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API), and support has already landed in _most_ modern JavaScript runtimes. - -Engine support for `bigint` values has also become commonplace. The older `number` primitive in JavaScript has a maximum value of 2^53 - 1, whereas Rust’s `u64` can represent values up to 2^64. - -Version 2.0 eliminates userspace implementations of Ed25519 cryptography, large number polyfills, and more, in favour of custom implementations or the use of native JavaScript features, reducing the size of the library. It has no third-party dependencies. - -## Functional Architecture - -The object oriented, class-based architecture of web3.js (1.x) causes unnecessary bundle bloat. Your application has no choice but to bundle _all_ of the functionality and dependencies of a class no matter how many methods you actually use at runtime. - -Class-based architecture also presents unique risks to developers who trigger the dual-package hazard. This describes a situation you can find yourself in if you build for both CommonJS and ES modules. It arises when two copies of the same class are present in the dependency tree, causing checks like `instanceof` to fail. This introduces aggravating and difficult to debug problems. - -Read more about dual-package hazard: - -- [NodeJS: Dual Package Hazard](https://nodejs.org/api/packages.html#dual-package-hazard) - -Version 2.0 implements no classes (with the notable exception of the `SolanaError` class) and implements the thinnest possible interfaces at function boundaries. - -## Statistics - -Consider these statistical comparisons between version 2.0 and the legacy 1.x. - -| | 1.x (Legacy) | 2.0 | +/- % | -| ------------------------------------------------------------------------------------------------------ | ------------ | ---------- | ----- | -| Total minified size of library | 81 KB | 57.5 KB | -29% | -| Total minified size of library (when runtime supports Ed25519) | 81 KB | 53 KB | -33% | -| Bundled size of a web application that executes a transfer of lamports | 111 KB | 23.9 KB | -78% | -| Bundled size of a web application that executes a transfer of lamports (when runtime supports Ed25519) | 111 KB | 18.2 KB | -83% | -| Performance of key generation, signing, and verifying signatures (Brave with Experimental API flag) | 700 ops/s | 7000 ops/s | +900% | -| First-load size for Solana Explorer | 311 KB | 228 KB | -26% | - -The re-engineered library achieves these speedups and reductions in bundle size in large part through use of modern JavaScript APIs. - -To validate our work, we replaced the legacy 1.x library with the new 2.0 library on the homepage of the Solana Explorer. Total first-load bundle size dropped by 26% without removing a single feature. [Here’s an X thread](https://twitter.com/callum_codes/status/1679124485218226176) by Callum McIntyre if you would like to dig deeper. - -# A Tour of the Version 2.0 API - -Here’s an overview of how to use the new library to interact with the RPC, configure network transports, work with Ed25519 keys, and to serialize data. - -## RPC - -Version 2.0 ships with an implementation of the [JSON RPC specification](https://www.jsonrpc.org/specification) and a type spec for the [Solana JSON RPC](https://docs.solana.com/api). - -The main package responsible for managing communication with an RPC is `@solana/rpc`. However, this package makes use of more granular packages to break down the RPC logic into smaller pieces. Namely, these packages are: - -- `@solana/rpc`: Contains all logic related to sending Solana RPC calls. -- `@solana/rpc-api`: Describes all Solana RPC methods using types. -- `@solana/rpc-transport-http`: Provides a concrete implementation of an RPC transport using HTTP requests. -- `@solana/rpc-spec`: Defines the JSON RPC spec for sending RPC requests. -- `@solana/rpc-spec-types`: Shared JSON RPC specifications types and helpers that are used by both `@solana/rpc` and `@solana/rpc-subscriptions` (described in the next section). -- `@solana/rpc-types`: Shared Solana RPC types and helpers that are used by both `@solana/rpc` and `@solana/rpc-subscriptions`. - -The main `@solana/web3.js` package re-exports the `@solana/rpc` package so, going forward, we will import RPC types and functions from the library directly. - -### RPC Calls - -You can use the `createSolanaRpc` function by providing the URL of a Solana JSON RPC server. This will create a default client for interacting with the Solana JSON RPC API. - -```ts -import { createSolanaRpc } from '@solana/web3.js'; - -// Create an RPC client. -const rpc = createSolanaRpc('http://127.0.0.1:8899'); -// ^? Rpc - -// Send a request. -const slot = await rpc.getSlot().send(); -``` - -### Custom RPC Transports - -The `createSolanaRpc` function communicates with the RPC server using a default HTTP transport that should satisfy most use cases. You can provide your own transport or wrap an existing one to communicate with RPC servers in any way you see fit. In the example below, we explicitly create a transport and use it to create a new RPC client via the `createSolanaRpcFromTransport` function. - -```ts -import { createSolanaRpcFromTransport, createDefaultRpcTransport } from '@solana/web3.js'; - -// Create an HTTP transport or any custom transport of your choice. -const transport = createDefaultRpcTransport({ url: 'https://api.devnet.solana.com' }); - -// Create an RPC client using that transport. -const rpc = createSolanaRpcFromTransport(transport); -// ^? Rpc - -// Send a request. -const slot = await rpc.getSlot().send(); -``` - -A custom transport can implement specialized functionality such as coordinating multiple transports, implementing retries, and more. Let's take a look at some concrete examples. - -#### Round Robin - -A ‘round robin’ transport is one that distributes requests to a list of endpoints in sequence. - -```ts -import { createDefaultRpcTransport, createSolanaRpcFromTransport, type RpcTransport } from '@solana/web3.js'; - -// Create an HTTP transport for each RPC server. -const transports = [ - createDefaultRpcTransport({ url: 'https://mainnet-beta.my-server-1.com' }), - createDefaultRpcTransport({ url: 'https://mainnet-beta.my-server-2.com' }), - createDefaultRpcTransport({ url: 'https://mainnet-beta.my-server-3.com' }), -]; - -// Set up the round-robin transport. -let nextTransport = 0; -async function roundRobinTransport(...args: Parameters): Promise { - const transport = transports[nextTransport]; - nextTransport = (nextTransport + 1) % transports.length; - return await transport(...args); -} - -// Create an RPC client using the round-robin transport. -const rpc = createSolanaRpcFromTransport(roundRobinTransport); -``` - -#### Sharding - -A sharding transport is a kind of distributing transport that sends requests to a particular server based on something about the request itself. Here’s an example that sends requests to different servers depending on the name of the method: - -```ts -import { createDefaultRpcTransport, createSolanaRpcFromTransport, type RpcTransport } from '@solana/web3.js'; - -// Create multiple transports. -const transportA = createDefaultRpcTransport({ url: 'https://mainnet-beta.my-server-1.com' }); -const transportB = createDefaultRpcTransport({ url: 'https://mainnet-beta.my-server-2.com' }); -const transportC = createDefaultRpcTransport({ url: 'https://mainnet-beta.my-server-3.com' }); -const transportD = createDefaultRpcTransport({ url: 'https://mainnet-beta.my-server-4.com' }); - -// Function to determine which shard to use based on the request method. -function selectShard(method: string): RpcTransport { - switch (method) { - case 'getAccountInfo': - case 'getBalance': - return transportA; - case 'getTransaction': - case 'getRecentBlockhash': - return transportB; - case 'sendTransaction': - return transportC; - default: - return transportD; - } -} - -// Create a transport that selects the correct transport given the request method name. -async function shardingTransport(...args: Parameters): Promise { - const payload = args[0].payload as { method: string }; - const selectedTransport = selectShard(payload.method); - return (await selectedTransport(...args)) as TResponse; -} - -// Create an RPC client using the sharding transport. -const rpc = createSolanaRpcFromTransport(shardingTransport); -``` - -#### Retry - -A custom transport is a good place to implement global retry logic for every request: - -```ts -import { createDefaultRpcTransport, createSolanaRpcFromTransport, type RpcTransport } from '@solana/web3.js'; - -// Set the maximum number of attempts to retry a request. -const MAX_ATTEMPTS = 4; - -// Create the default transport. -const defaultTransport = createDefaultRpcTransport({ url: 'https://mainnet-beta.my-server-1.com' }); - -// Sleep function to wait for a given number of milliseconds. -function sleep(ms: number): Promise { - return new Promise(resolve => setTimeout(resolve, ms)); -} - -// Calculate the delay for a given attempt. -function calculateRetryDelay(attempt: number): number { - // Exponential backoff with a maximum of 1.5 seconds. - return Math.min(100 * Math.pow(2, attempt), 1500); -} - -// A retrying transport that will retry up to MAX_ATTEMPTS times before failing. -async function retryingTransport(...args: Parameters): Promise { - let requestError; - for (let attempts = 0; attempts < MAX_ATTEMPTS; attempts++) { - try { - return await defaultTransport(...args); - } catch (err) { - requestError = err; - // Only sleep if we have more attempts remaining. - if (attempts < MAX_ATTEMPTS - 1) { - const retryDelay = calculateRetryDelay(attempts); - await sleep(retryDelay); - } - } - } - throw requestError; -} - -// Create the RPC client using the retrying transport. -const rpc = createSolanaRpcFromTransport(retryingTransport); -``` - -#### Failover - -Support for handling network failures can be implemented in the transport itself. Here’s an example of some failover logic integrated into a transport: - -```ts -// TODO: Your turn; send us a pull request with an example. -``` - -### Augmenting/Constraining the RPC API - -Using the `createSolanaRpc` or `createSolanaRpcFromTransport` methods, we always get the same API that includes the Solana RPC API methods. Since the RPC API is described using types only, it is possible to augment those types to add your own methods. - -When constraining the API scope, keep in mind that types don’t affect bundle size. You may still like to constrain the type-spec for a variety of reasons, including reducing TypeScript noise. - -#### Constraining by Cluster - -If you're using a specific cluster, you may wrap your RPC URL inside a helper function like `mainnet` or `devnet` to inject that information into the RPC type system. - -```ts -import { createSolanaRpc, mainnet, devnet } from '@solana/web3.js'; - -const mainnetRpc = createSolanaRpc(mainnet('https://api.mainnet-beta.solana.com')); -// ^? RpcMainnet - -const devnetRpc = createSolanaRpc(devnet('https://api.devnet.solana.com')); -// ^? RpcDevnet -``` - -In the example above, `devnetRpc.requestAirdrop(..)` will work, but `mainnetRpc.requestAirdrop(..)` will raise a TypeScript error since `requestAirdrop` is not a valid method of the mainnet cluster. - -#### Cherry-Picking API Methods - -You can constrain the API’s type-spec even further so you are left only with the methods you need. The simplest way to do this is to cast the created RPC client to a type that only includes the required methods. - -```ts -import { createSolanaRpc, type Rpc, type GetAccountInfoApi, type GetMultipleAccountsApi } from '@solana/web3.js'; - -const rpc = createSolanaRpc('http://127.0.0.1:8899') as Rpc; -``` - -Alternatively, you can explicitly create the RPC API using the `createSolanaRpcApi` function. You will need to create your own transport and bind the two together using the `createRpc` function. - -```ts -import { - createDefaultRpcTransport, - createRpc, - createSolanaRpcApi, - DEFAULT_RPC_CONFIG, - type GetAccountInfoApi, - type GetMultipleAccountsApi, -} from '@solana/web3.js'; - -const api = createSolanaRpcApi(DEFAULT_RPC_CONFIG); -const transport = createDefaultRpcTransport({ url: 'http:127.0.0.1:8899' }); - -const rpc = createRpc({ api, transport }); -``` - -Note that the `createSolanaRpcApi` function is a wrapper on top of the `createRpcApi` function which adds some Solana-specific transformers such as setting a default commitment on all methods or throwing an error when an integer overflow is detected. - -#### Creating Your Own API Methods - -The new library’s RPC specification supports an _infinite_ number of JSON-RPC methods with **zero increase** in bundle size. - -This means the library can support future additions to the official [Solana JSON RPC](https://docs.solana.com/api), or [custom RPC methods](https://docs.helius.dev/compression-and-das-api/digital-asset-standard-das-api/get-asset) defined by some RPC provider. - -Here’s an example of how a developer at might build a custom RPC type-spec for an RPC provider's implementation of the Metaplex Digital Asset Standard's `getAsset` method: - -```ts -import { RpcApiMethods } from '@solana/web3.js'; - -// Define the method's response payload. -type GetAssetApiResponse = Readonly<{ - interface: DasApiAssetInterface; - id: Address; - content: Readonly<{ - files?: readonly { - mime?: string; - uri?: string; - [key: string]: unknown; - }[]; - json_uri: string; - links?: readonly { - [key: string]: unknown; - }[]; - metadata: DasApiMetadata; - }>; - /* ...etc... */ -}>; - -// Set up an interface for the request method. -interface GetAssetApi extends RpcApiMethods { - // Define the method's name, parameters and response type - getAsset(args: { id: Address }): GetAssetApiResponse; -} - -// Export the type spec for downstream users. -export type MetaplexDASApi = GetAssetApi; -``` - -Here’s how a developer might use it: - -```ts -import { createDefaultRpcTransport, createRpc, createRpcApi } from '@solana/web3.js'; - -// Create the custom API. -const api = createRpcApi(); - -// Set up an HTTP transport to a server that supports the custom API. -const transport = createDefaultRpcTransport({ - url: 'https://mainnet.helius-rpc.com/?api-key=', -}); - -// Create the RPC client. -const metaplexDASRpc = createRpc({ api, transport }); -// ^? Rpc -``` - -As long as a particular JSON RPC method adheres to the [official JSON RPC specification](https://www.jsonrpc.org/specification), it will be supported by version 2.0. - -### Aborting RPC Requests - -RPC requests are now abortable with modern `AbortControllers`. When calling an RPC method such as `getSlot`, it will return a `PendingRpcRequest` proxy object that contains a `send` method to send the request to the server. - -```ts -const pendingRequest: PendingRpcRequest = rpc.getSlot(); - -const slot: Slot = await pendingRequest.send(); -``` - -The arguments of the `getSlot` method are reserved for the request payload, but the `send` method is where additional arguments such as an `AbortSignal` can be accepted in the context of the request. - -Aborting RPC requests can be useful for a variety of things such as setting a timeout on a request or cancelling a request when a user navigates away from a page. - -```ts -import { createSolanaRpc } from '@solana/web3.js'; - -const rpc = createSolanaRpc('http://127.0.0.1:8900'); - -// Create a new AbortController. -const abortController = new AbortController(); - -// Abort the request when the user navigates away from the current page. -function onUserNavigateAway() { - abortController.abort(); -} - -// The request will be aborted if and only if the user navigates away from the page. -const slot = await rpc.getSlot().send({ abortSignal: abortController.signal }); -``` - -Read more about `AbortController` here: - -- [Mozilla Developer Docs: `AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController) -- [Mozilla Developer Docs: `AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) -- [JavaScript.info: Fetch: Abort](https://javascript.info/fetch-abort) - -## RPC Subscriptions - -Subscriptions in the legacy library do not allow custom retry logic and do not allow you to recover from potentially missed messages. The new version does away with silent retries, surfaces transport errors to your application, and gives you the opportunity to recover from gap events. - -The main package responsible for managing communication with RPC subscriptions is `@solana/rpc-subscriptions`. However, similarly to `@solana/rpc`, this package also makes use of more granular packages. These packages are: - -- `@solana/rpc-subscriptions`: Contains all logic related to subscribing to Solana RPC notifications. -- `@solana/rpc-subscriptions-api`: Describes all Solana RPC subscriptions using types. -- `@solana/rpc-subscriptions-transport-websocket`: Provides a concrete implementation of an RPC Subscriptions transport using WebSockets. -- `@solana/rpc-subscriptions-spec`: Defines the JSON RPC spec for subscribing to RPC notifications. -- `@solana/rpc-spec-types`: Shared JSON RPC specifications types and helpers that are used by both `@solana/rpc` and `@solana/rpc-subscriptions`. -- `@solana/rpc-types`: Shared Solana RPC types and helpers that are used by both `@solana/rpc` and `@solana/rpc-subscriptions`. - -Since the main `@solana/web3.js` library also re-exports the `@solana/rpc-subscriptions` package we will import RPC Subscriptions types and functions directly from the main library going forward. - -### Getting Started with RPC Subscriptions - -To get started with RPC Subscriptions, you may use the `createSolanaRpcSubscriptions` function by providing the WebSocket URL of a Solana JSON RPC server. This will create a default client for interacting with Solana RPC Subscriptions. - -```ts -import { createSolanaRpcSubscriptions } from '@solana/web3.js'; - -// Create an RPC Subscriptions client. -const rpcSubscriptions = createSolanaRpcSubscriptions('ws://127.0.0.1:8900'); -// ^? RpcSubscriptions -``` - -### Subscriptions as `AsyncIterators` - -The new subscriptions API vends subscription notifications as an `AsyncIterator`. The `AsyncIterator` conforms to the [async iterator protocol](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#the_async_iterator_and_async_iterable_protocols), which allows developers to consume messages using a `for await...of` loop. - -Here’s an example of working with a subscription in the new library: - -```ts -import { address, createSolanaRpcSubscriptions, createDefaultRpcSubscriptionsTransport } from '@solana/web3.js'; - -// Create the RPC Subscriptions client. -const rpcSubscriptions = createSolanaRpcSubscriptions('ws://127.0.0.1:8900'); - -// Set up an abort controller. -const abortController = new AbortController(); - -// Subscribe to account notifications. -const accountNotifications = await rpcSubscriptions - .accountNotifications(address('AxZfZWeqztBCL37Mkjkd4b8Hf6J13WCcfozrBY6vZzv3'), { commitment: 'confirmed' }) - .subscribe({ abortSignal: abortController.signal }); - -try { - // Consume messages. - for await (const notification of accountNotifications) { - console.log('New balance', notification.value.lamports); - } -} catch (e) { - // The subscription went down. - // Retry it and then recover from potentially having missed - // a balance update, here (eg. by making a `getBalance()` call). -} -``` - -You can read more about `AsyncIterator` at the following links: - -- [Mozilla Developer Docs: `AsyncIterator`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncIterator) -- [Luciano Mammino (Blog): JavaScript Async Iterators](https://www.nodejsdesignpatterns.com/blog/javascript-async-iterators/) - -### Aborting RPC Subscriptions - -Similarly to RPC calls, applications can terminate active subscriptions using an `AbortController` attribute on the `subscribe` method. In fact, this parameter is _required_ for subscriptions to encourage you to clean up subscriptions that your application no longer needs. - -Let's take a look at some concrete examples that demonstrate how to abort subscriptions. - -#### Subscription Timeout - -Here's an example of an `AbortController` used to abort a subscription after a 5-second timeout: - -```ts -import { createSolanaRpcSubscriptions } from '@solana/web3.js'; - -const rpcSubscriptions = createSolanaRpcSubscriptions('ws://127.0.0.1:8900'); - -// Subscribe for slot notifications using an AbortSignal that times out after 5 seconds. -const slotNotifications = await rpcSubscriptions - .slotNotifications() - .subscribe({ abortSignal: AbortSignal.timeout(5000) }); - -// Log slot notifications. -for await (const notification of slotNotifications) { - console.log('Slot notification', notification); -} - -console.log('Done.'); -``` - -Read more about `AbortController` at the following links: - -- [Mozilla Developer Docs: `AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController) -- [Mozilla Developer Docs: `AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) -- [JavaScript.info: Fetch: Abort](https://javascript.info/fetch-abort) - -#### Cancelling Subscriptions - -It is also possible to abort a subscription inside the `for await...of` loop. This enables us to cancel a subscription based on some condition, such as a change in the state of an account. For instance, the following example cancels a subscription when the owner of an account changes: - -```ts -// Subscribe to account notifications. -const accountNotifications = await rpc - .accountNotifications(address('AxZfZWeqztBCL37Mkjkd4b8Hf6J13WCcfozrBY6vZzv3'), { commitment: 'confirmed' }) - .subscribe({ abortSignal }); - -// Consume messages. -let previousOwner = null; -for await (const notification of accountNotifications) { - const { - value: { owner }, - } = notification; - // Check the owner to see if it has changed - if (previousOwner && owner !== previousOwner) { - // If so, abort the subscription - abortController.abort(); - } else { - console.log(notification); - } - previousOwner = owner; -} -``` - -### Failed vs. Aborted Subscriptions - -It is important to note that a subscription failure behaves differently from a subscription abort. A subscription failure occurs when the subscription goes down and will throw an error that can be intercepted in a `try/catch`. However, an aborted subscription will not throw an error, but will instead exit the `for await...of` loop. - -```ts -try { - for await (const notification of notifications) { - // Consume messages. - } - // [ABORTED] Reaching this line means the subscription was aborted — i.e. unsubscribed. -} catch (e) { - // [FAILED] Reaching this line means the subscription went down. - // Retry it, then recover from potential missed messages. -} finally { - // [ABORTED or FAILED] Whether the subscription failed or was aborted, you can run cleanup code here. -} -``` - -### Message Gap Recovery - -One of the most crucial aspects of any subscription API is managing potential missed messages. Missing messages, such as account state updates, could be catastrophic for an application. That’s why the new library provides native support for recovering missed messages using the `AsyncIterator`. - -When a connection fails unexpectedly, any messages you miss while disconnected can result in your UI falling behind or becoming corrupt. Because subscription failure is now made explicit in the new API, you can implement ‘catch-up’ logic after re-establishing the subscription. - -Here’s an example of such logic: - -```ts -try { - for await (const notif of accountNotifications) { - updateAccountBalance(notif.lamports); - } -} catch (e) { - // The subscription failed. - // First, re-establish the subscription. - await setupAccountBalanceSubscription(address); - // Then make a one-shot request to 'catch up' on any missed balance changes. - const { value: lamports } = await rpc.getBalance(address).send(); - updateAccountBalance(lamports); -} -``` - -### Using Custom RPC Subscriptions Transports - -The `createSolanaRpcSubscriptions` function communicates with the RPC server using a default WebSocket transport that should satisfy most use cases. However, you may here as well provide your own transport or decorate existing ones to communicate with RPC servers in any way you see fit. In the example below, we explicitly create a WebSocket transport and use it to create a new RPC Subscriptions client via the `createSolanaRpcSubscriptionsFromTransport` function. - -```ts -import { createDefaultRpcSubscriptionsTransport, createSolanaRpcSubscriptionsFromTransport } from '@solana/web3.js'; - -// Create a WebSocket transport or any custom transport of your choice. -const transport = createDefaultRpcSubscriptionsTransport({ url: 'ws://127.0.0.1:8900' }); - -// Create an RPC client using that transport. -const rpcSubscriptions = createSolanaRpcSubscriptionsFromTransport(transport); -// ^? RpcSubscriptions -``` - -### Augmenting/Constraining the RPC Subscriptions API - -Using the `createSolanaRpcSubscriptions` or `createSolanaRpcSubscriptionsFromTransport` functions, we always get the same RPC Subscriptions API, including all Solana RPC stable subscriptions. However, since the RPC Subscriptions API is described using types only, it is possible to constrain the API to a specific set of subscriptions or even add your own custom subscriptions. - -#### Constraining by Cluster - -If you're using a specific cluster, you may wrap your RPC URL inside a helper function like `mainnet` or `devnet` to inject that information into the RPC type system. - -```ts -import { createSolanaRpcSubscriptions, mainnet, devnet } from '@solana/web3.js'; - -const mainnetRpc = createSolanaRpcSubscriptions(mainnet('https://api.mainnet-beta.solana.com')); -// ^? RpcSubscriptionsMainnet - -const devnetRpc = createSolanaRpcSubscriptions(devnet('https://api.devnet.solana.com')); -// ^? RpcSubscriptionsDevnet -``` - -#### Including Unstable Subscriptions - -If your app needs access to [unstable RPC Subscriptions](https://docs.solana.com/api/websocket#blocksubscribe) — e.g. `BlockNotificationsApi` or `SlotsUpdatesNotificationsApi` — and your RPC server supports them, you may use the `createSolanaRpcSubscriptions_UNSTABLE` and `createSolanaRpcSubscriptionsFromTransport_UNSTABLE` functions to create an RPC Subscriptions client that includes those subscriptions. - -```ts -import { - createSolanaRpcSubscriptions_UNSTABLE, - createSolanaRpcSubscriptionsFromTransport_UNSTABLE, -} from '@solana/web3.js'; - -// Using the default WebSocket transport. -const rpcSubscriptions = createSolanaRpcSubscriptions_UNSTABLE('ws://127.0.0.1:8900'); -// ^? RpcSubscriptions - -// Using a custom transport. -const transport = createDefaultRpcSubscriptionsTransport({ url: 'ws://127.0.0.1:8900' }); -const rpcSubscriptions = createSolanaRpcSubscriptionsFromTransport_UNSTABLE(transport); -// ^? RpcSubscriptions -``` - -#### Cherry-Picking API Methods - -You may constrain the scope of the Subscription API even further so you are left only with the subscriptions you need. The simplest way to do this is to cast the created RPC client to a type that only includes the methods you need. - -```ts -import { - createSolanaRpcSubscriptions, - type RpcSubscriptions, - type AccountNotificationsApi, - type SlotNotificationsApi, -} from '@solana/web3.js'; - -const rpc = createSolanaRpcSubscriptions('ws://127.0.0.1:8900') as RpcSubscriptions< - AccountNotificationsApi & SlotNotificationsApi ->; -``` - -Alternatively, you may explicitly create the RPC Subscriptions API using the `createSolanaRpcSubscriptionsApi` function. You will then need to create your own transport explicitly and bind the two together using the `createSubscriptionRpc` function. - -```ts -import { - createDefaultRpcSubscriptionsTransport, - createSubscriptionRpc, - createSolanaRpcSubscriptionsApi, - DEFAULT_RPC_CONFIG, - type AccountNotificationsApi, - type SlotNotificationsApi, -} from '@solana/web3.js'; - -const api = createSolanaRpcSubscriptionsApi(DEFAULT_RPC_CONFIG); -const transport = createDefaultRpcSubscriptionsTransport({ url: 'ws://127.0.0.1:8900' }); -const rpcSubscriptions = createSubscriptionRpc({ api, transport }); -``` - -Note that the `createSolanaRpcSubscriptionsApi` function is a wrapper on top of the `createRpcSubscriptionsApi` function which adds some Solana-specific transformers such as setting a default commitment on all methods or throwing an error when an integer overflow is detected. - -## Keys - -The new library takes a brand-new approach to Solana key pairs and addresses, which will feel quite different from the classes `PublicKey` and `Keypair` from version 1.x. - -### Web Crypto API - -All key operations now use the native Ed25519 implementation in JavaScript’s Web Crypto API. - -The API itself is designed to be a more reliably secure way to manage highly sensitive secret key information, but **developers should still use extreme caution when dealing with secret key bytes in their applications**. - -One thing to note is that many operations from Web Crypto – such as importing, generating, signing, and verifying are now **asynchronous**. - -Here’s an example of generating a `CryptoKeyPair` using the Web Crypto API and signing a message: - -```ts -import { generateKeyPair, signBytes, verifySignature } from '@solana/web3.js'; - -const keyPair: CryptoKeyPair = await generateKeyPair(); - -const message = new Uint8Array(8).fill(0); - -const signedMessage = await signBytes(keyPair.privateKey, message); -// ^? Signature - -const verified = await verifySignature(keyPair.publicKey, signedMessage, message); -``` - -### Web Crypto Polyfill - -Wherever Ed25519 is not supported, we offer a polyfill for Web Crypto’s Ed25519 API. - -This polyfill can be found at `@solana/webcrypto-ed25519-polyfill` and mimics the functionality of the Web Crypto API for Ed25519 key pairs using the same userspace implementation we used in web3.js 1.x. It does not polyfill other algorithms. - -Determine if your target runtime supports Ed25519, and install the polyfill if it does not: - -```ts -import install from '@solana/webcrypto-ed25519-polyfill'; -import { generateKeyPair, signBytes, verifySignature } from '@solana/web3.js'; - -install(); -const keyPair: CryptoKeyPair = await generateKeyPair(); - -/* Remaining logic */ -``` - -You can see where Ed25519 is currently supported in [this GitHub issue](https://github.com/WICG/webcrypto-secure-curves/issues/20) on the Web Crypto repository. Consider sniffing the user-agent when deciding whether or not to deliver the polyfill to browsers. - -Operations on `CryptoKey` objects using the Web Crypto API _or_ the polyfill are mostly handled by the `@solana/keys` package. - -### String Addresses - -All addresses are now JavaScript strings. They are represented by the opaque type `Address`, which describes exactly what a Solana address actually is. - -Consequently, that means no more `PublicKey`. - -Here’s what they look like in development: - -```ts -import { Address, address, getAddressFromPublicKey, generateKeyPair } from '@solana/web3.js'; - -// Coerce a string to an `Address` -const myOtherAddress = address('AxZfZWeqztBCL37Mkjkd4b8Hf6J13WCcfozrBY6vZzv3'); - -// Typecast it instead -const myAddress = - 'AxZfZWeqztBCL37Mkjkd4b8Hf6J13WCcfozrBY6vZzv3' as Address<'AxZfZWeqztBCL37Mkjkd4b8Hf6J13WCcfozrBY6vZzv3'>; - -// From CryptoKey -const keyPair = await generateKeyPair(); -const myPublicKeyAsAddress = await getAddressFromPublicKey(keyPair.publicKey); -``` - -Some tooling for working with base58-encoded addresses can be found in the `@solana/addresses` package. - -## Transactions - -### Creating Transaction Messages +In addition to rexporting functions from packages in the `@solana/*` namespace, this package offers additional helpers for building Solana applications, with sensible defaults. -Like many other familiar aspects of the 1.0 library, transactions have received a makeover. +### `airdropFactory({rpc, rpcSubscriptions})` -For starters, all transaction messages are now version-aware, so there’s no longer a need to juggle two different types (eg. `Transaction` vs. `VersionedTransaction`). - -Address lookups are now completely described inside transaction message instructions, so you don’t have to materialize `addressTableLookups` anymore. - -Here’s a simple example of creating a transaction message – notice how its type is refined at each step of the process: +Returns a function that you can call to airdrop a certain amount of `Lamports` to a Solana address. ```ts import { address, - createTransactionMessage, - setTransactionMessageFeePayer, - setTransactionMessageLifetimeUsingBlockhash, - Blockhash, + airdropFactory, + createSolanaRpc, + createSolanaRpcSubscriptions, + devnet, + lamports, } from '@solana/web3.js'; -const recentBlockhash = { - blockhash: '4uhcVJyU9pJkvQyS88uRDiswHXSCkY3zQawwpjk2NsNY' as Blockhash, - lastValidBlockHeight: 196055492n, -}; -const feePayer = address('AxZfZWeqztBCL37Mkjkd4b8Hf6J13WCcfozrBY6vZzv3'); - -// Create a new transaction message -const transactionMessage = createTransactionMessage({ version: 0 }); -// ^? V0TransactionMessage +const rpc = createSolanaRpc(devnet('http://127.0.0.1:8899')); +const rpcSubscriptions = createSolanaRpcSubscriptions(devnet('ws://127.0.0.1:8900')); -// Set the fee payer -const transactionMessageWithFeePayer = setTransactionMessageFeePayer(feePayer, transactionMessage); -// ^? V0TransactionMessage & ITransactionMessageWithFeePayer +const airdrop = airdropFactory({ rpc, rpcSubscriptions }); -const transactionMessageWithFeePayerAndLifetime = setTransactionMessageLifetimeUsingBlockhash( - // ^? V0TransactionMessage & ITransactionMessageWithFeePayer & TransactionMessageWithBlockhashLifetime - recentBlockhash, - transactionMessageWithFeePayer, -); +await airdrop({ + commitment: 'confirmed', + recipientAddress: address('FnHyam9w4NZoWR6mKN1CuGBritdsEWZQa4Z4oawLZGxa'), + lamports: lamports(10_000_000n), +}); ``` -As you can see, each time a transaction message is modified, the type reflects its new shape. If you add a fee payer, you’ll get a type representing a transaction message with a fee payer, and so on. - -Transaction message objects are also **frozen by these functions** to prevent them from being mutated in place. +> [!NOTE] This only works on test clusters. -### Signing Transaction Messages +### `decodeTransactionMessage(compiledTransactionMessage, rpc, config)` -The `signTransaction(..)` function will raise a type error if your transaction message is not already equipped with a fee payer and a lifetime. This helps you catch errors at author-time instead of runtime. +Returns a `TransactionMessage` from a `CompiledTransactionMessage`. If any of the accounts in the compiled message require an address lookup table to find their address, this function will use the supplied RPC instance to fetch the contents of the address lookup table from the network. -```ts -const feePayer = address('AxZfZWeqztBCL37Mkjkd4b8Hf6J13WCcfozrBY6vZzv3'); -const signer = await generateKeyPair(); - -const transactionMessage = createTransactionMessage({ version: 'legacy' }); -const transactionMessageWithFeePayer = setTransactionMessageFeePayer(feePayer, transactionMessage); +### `fetchLookupTables(lookupTableAddresses, rpc, config)` -// Attempting to sign the transaction message without a lifetime will throw a type error -const signedTransaction = await signTransaction([signer], transactionMessageWithFeePayer); -// => "Property 'lifetimeConstraint' is missing in type" -``` +Given a list of addresses belonging to address lookup tables, returns a map of lookup table addresses to an ordered array of the addresses they contain. -### Calibrating a Transaction Message's Compute Unit Budget +### `getComputeUnitEstimateForTransactionMessageFactory({rpc})` Correctly budgeting a compute unit limit for your transaction message can increase the probability that your transaction will be accepted for processing. If you don't declare a compute unit limit on your transaction, validators will assume an upper limit of 200K compute units (CU) per instruction. @@ -900,532 +96,75 @@ const transactionMessageWithComputeUnitLimit = prependTransactionMessageInstruct > [!NOTE] > If you are preparing an _unsigned_ transaction, destined to be signed and submitted to the network by a wallet, you might like to leave it up to the wallet to determine the compute unit limit. Consider that the wallet might have a more global view of how many compute units certain types of transactions consume, and might be able to make better estimates of an appropriate compute unit budget. -### Helpers For Building Transaction Messages +### `sendAndConfirmDurableNonceTransactionFactory({rpc, rpcSubscriptions})` -Building transaction messages in this manner might feel different from what you’re used to. Also, we certainly wouldn’t want you to have to bind transformed transaction messages to a new variable at each step, so we have released a functional programming library dubbed `@solana/functional` that lets you build transaction messages in **pipelines**. Here’s how it can be used: +Returns a function that you can call to send a nonce-based transaction to the network and to wait until it has been confirmed. ```ts -import { pipe } from '@solana/functional'; import { - address, - createTransactionMessage, - setTransactionMessageFeePayer, - setTransactionMessageLifetimeUsingBlockhash, - Blockhash, + isSolanaError, + sendAndConfirmDurableNonceTransactionFactory, + SOLANA_ERROR__INVALID_NONCE, + SOLANA_ERROR__NONCE_ACCOUNT_NOT_FOUND, } from '@solana/web3.js'; -// Use `pipe(..)` to create a pipeline of transaction message transformation operations -const transactionMessage = pipe( - createTransactionMessage({ version: 0 }), - tx => setTransactionMessageFeePayer(feePayer, tx), - tx => setTransactionMessageLifetimeUsingBlockhash(recentBlockhash, tx), -); -``` - -Note that `pipe(..)` is general-purpose, so it can be used to pipeline any functional transforms. - -## Codecs - -We have taken steps to make it easier to write data (de)serializers, especially as they pertain to Rust datatypes and byte buffers. - -Solana’s codecs libraries are broken up into modular components so you only need to import the ones you need. They are: - -- `@solana/codecs-core`: The core codecs library for working with codecs serializers and creating custom ones -- `@solana/codecs-numbers`: Used for serialization of numbers (little-endian and big-endian bytes, etc.) -- `@solana/codecs-strings`: Used for serialization of strings -- `@solana/codecs-data-structures`: Codecs and serializers for structs -- `@solana/options`: Designed to build codecs and serializers for types that mimic Rust’s enums, which can include embedded data within their variants such as values, tuples, and structs - -These packages are included in the main `@solana/web3.js` library but you may also import them from `@solana/codecs` if you only need the codecs. - -Here’s an example of encoding and decoding a custom struct with some strings and numbers: - -```ts -import { addCodecSizePrefix } from '@solana/codecs-core'; -import { getStructCodec } from '@solana/codecs-data-structures'; -import { getU32Codec, getU64Codec, getU8Codec } from '@solana/codecs-numbers'; -import { getUtf8Codec } from '@solana/codecs-strings'; - -// Equivalent in Rust: -// struct { -// amount: u64, -// decimals: u8, -// name: String, -// } -const structCodec = getStructCodec([ - ['amount', getU64Codec()], - ['decimals', getU8Codec()], - ['name', addCodecSizePrefix(getUtf8Codec(), getU32Codec())], -]); - -const myToken = { - amount: 1000000000000000n, // `bigint` or `number` is supported - decimals: 2, - name: 'My Token', -}; - -const myEncodedToken: Uint8Array = structCodec.encode(myToken); -const myDecodedToken = structCodec.decode(myEncodedToken); - -myDecodedToken satisfies { - amount: bigint; - decimals: number; - name: string; -}; -``` - -You may only need to encode or decode data, but not both. Importing one or the other allows your optimizing compiler to tree-shake the other implementation away: - -```ts -import { Codec, combineCodec, Decoder, Encoder, addDecoderSizePrefix, addEncoderSizePrefix } from '@solana/codecs-core'; -import { getStructDecoder, getStructEncoder } from '@solana/codecs-data-structures'; -import { - getU8Decoder, - getU8Encoder, - getU32Decoder, - getU32Encoder, - getU64Decoder, - getU64Encoder, -} from '@solana/codecs-numbers'; -import { getUtf8Decoder, getUtf8Encoder } from '@solana/codecs-strings'; - -export type MyToken = { - amount: bigint; - decimals: number; - name: string; -}; - -export type MyTokenArgs = { - amount: number | bigint; - decimals: number; - name: string; -}; - -export const getMyTokenEncoder = (): Encoder => - getStructEncoder([ - ['amount', getU64Encoder()], - ['decimals', getU8Encoder()], - ['name', addEncoderSizePrefix(getUtf8Encoder(), getU32Encoder())], - ]); - -export const getMyTokenDecoder = (): Decoder => - getStructDecoder([ - ['amount', getU64Decoder()], - ['decimals', getU8Decoder()], - ['name', addDecoderSizePrefix(getUtf8Decoder(), getU32Decoder())], - ]); - -export const getMyTokenCodec = (): Codec => - combineCodec(getMyTokenEncoder(), getMyTokenDecoder()); -``` - -You can read me about codecs in [the official Codec documentation](https://github.com/solana-labs/solana-web3.js/blob/master/packages/codecs/README.md). - -## Type-Safety - -The new library makes use of some advanced TypeScript features, including generic types, conditional types, `Parameters<..>`, `ReturnType<..>` and more. - -We’ve described the RPC API in detail so that TypeScript can determine the _exact_ type of the result you will receive from the server given a particular input. Change the type of the input, and you will see the return type reflect that change. - -### RPC Types - -The RPC methods – both HTTP and subscriptions – are built with multiple overloads and conditional types. The expected HTTP response payload or subscription message format will be reflected in the return type of the function you’re working with when you provide the inputs in your code. - -Here’s an example of this in action: - -```ts -// Provide one set of parameters, get a certain type -// These parameters resolve to return type: -// { -// blockhash: Blockhash; -// blockHeight: bigint; -// blockTime: UnixTimestamp; -// parentSlot: bigint; -// previousBlockhash: Blockhash; -// } -const blockResponse = await rpc - .getBlock(0n, { - rewards: false, - transactionDetails: 'none', - }) - .send(); - -// Switch `rewards` to `true`, get `rewards` in the return type -// { -// /* ... Previous response */ -// rewards: Reward[]; -// } -const blockWithRewardsResponse = await rpc - .getBlock(0n, { - rewards: true, - transactionDetails: 'none', - }) - .send(); - -// Switch `transactionDetails` to `full`, get `transactions` in the return type -// { -// /* ... Previous response */ -// transactions: TransactionResponse[]; -// } -const blockWithRewardsAndTransactionsResponse = await rpc - .getBlock(0n, { - rewards: true, - transactionDetails: 'full', - }) - .send(); -``` - -### Catching Compile-Time Bugs with TypeScript - -As previously mentioned, the type coverage in version 2.0 allows developers to catch common bugs at compile time, rather than runtime. - -In the example below, a transaction message is created and then attempted to be signed without setting the fee payer. This would result in a runtime error from the RPC, but instead you will see a type error from TypeScript as you type: - -```ts -const transactionMessage = pipe(createTransactionMessage({ version: 0 }), tx => - setTransactionMessageLifetimeUsingBlockhash(recentBlockhash, tx), -); -const signedTransaction = await signTransaction([keyPair], transactionMessage); // ERROR: Property 'feePayer' is missing in type -``` - -Consider another example where a developer is attempting to send a transaction that has not been fully signed. Again, the TypeScript compiler will throw a type error: - -```ts -const transactionMessage = pipe( - createTransactionMessage({ version: 0 }), - tx => setTransactionMessageFeePayer(feePayerAddress, tx), - tx => setTransactionMessageLifetimeUsingBlockhash(recentBlockhash, tx), -); - -const signedTransaction = await signTransaction([], transactionMessage); - -// Asserts the transaction is a `FullySignedTransaction` -// Throws an error if any signatures are missing! -assertTransactionIsFullySigned(signedTransaction); - -await sendAndConfirmTransaction(signedTransaction); -``` - -Are you building a nonce transaction and forgot to make `AdvanceNonce` the first instruction? That’s a type error: - -```ts -const feePayer = await generateKeyPair(); -const feePayerAddress = await getAddressFromPublicKey(feePayer.publicKey); - -const notNonceTransactionMessage = pipe(createTransactionMessage({ version: 0 }), tx => - setTransactionMessageFeePayer(feePayerAddress, tx), -); - -notNonceTransactionMessage satisfies TransactionMessageWithDurableNonceLifetime; -// => Property 'lifetimeConstraint' is missing in type - -const nonceConfig = { - nonce: 'nonce' as Nonce, - nonceAccountAddress: address('5tLU66bxQ35so2bReGcyf3GfMMAAauZdNA1N4uRnKQu4'), - nonceAuthorityAddress: address('GDhj8paPg8woUzp9n8fj7eAMocN5P7Ej3A7T9F5gotTX'), -}; - -const stillNotNonceTransactionMessage = { - lifetimeConstraint: nonceConfig, - ...notNonceTransactionMessage, -}; - -stillNotNonceTransactionMessage satisfies TransactionMessageWithDurableNonceLifetime; -// => 'readonly IInstruction[]' is not assignable to type 'readonly [AdvanceNonceAccountInstruction, ...IInstruction[]]' - -const validNonceTransactionMessage = pipe( - createTransactionMessage({ version: 0 }), - tx => setTransactionMessageFeePayer(feePayerAddress, tx), - tx => setTransactionMessageLifetimeUsingDurableNonce(nonceConfig, tx), // Adds the instruction! -); - -validNonceTransactionMessage satisfies TransactionMessageWithDurableNonceLifetime; // OK -``` - -The library’s type-checking can even catch you using lamports instead of SOL for a value: - -```ts -const airdropAmount = 1n; // SOL -const signature = rpc.requestAirdrop(myAddress, airdropAmount).send(); -``` - -It will force you to cast the numerical value for your airdrop (or transfer, etc.) amount using `lamports()`, which should be a good reminder! - -```ts -const airdropAmount = lamports(1000000000n); -const signature = rpc.requestAirdrop(myAddress, airdropAmount).send(); -``` - -## Compatibility Layer - -You will have noticed by now that web3.js is a complete and total breaking change from the 1.x line. We want to provide you with a strategy for interacting with 1.x APIs while building your application using 2.0. You need a tool for commuting between 1.x and 2.0 data types. - -The `@solana/compat` library allows for interoperability between functions and class objects from the legacy library - such as `VersionedTransaction`, `PublicKey`, and `Keypair` - and functions and types of the new library - such as `Address`, `Transaction`, and `CryptoKeyPair`. - -Here’s how you can use `@solana/compat` to convert from a legacy `PublicKey` to an `Address`: - -```ts -import { fromLegacyPublicKey } from '@solana/compat'; - -const publicKey = new PublicKey('B3piXWBQLLRuk56XG5VihxR4oe2PSsDM8nTF6s1DeVF5'); -const address: Address = fromLegacyPublicKey(publicKey); -``` - -Here’s how to convert from a legacy `Keypair` to a `CryptoKeyPair`: - -```ts -import { fromLegacyKeypair } from '@solana/compat'; - -const keypairLegacy = Keypair.generate(); -const cryptoKeyPair: CryptoKeyPair = fromLegacyKeypair(keypair); -``` - -Here’s how to convert legacy transaction objects to the new library’s transaction types: - -```ts -// Note that you can only convert `VersionedTransaction` objects -const modernTransaction = fromVersionedTransaction(classicTransaction); -``` - -To see more conversions supported by `@solana/compat`, you can check out the package’s [README on GitHub](https://github.com/solana-labs/solana-web3.js/blob/master/packages/compat/README.md). - -## Program Clients - -Writing JavaScript clients for on-chain programs has been done manually up until now. Without an IDL for some of the native programs, this process has been necessarily manual and has resulted in clients that lag behind the actual capabilities of the programs themselves. - -We think that program clients should be _generated_ rather than written. Developers should be able to write Rust programs, compile the program code, and generate all of the JavaScript client-side code to interact with the program. - -We use [Kinobi](https://github.com/metaplex-foundation/kinobi) to represent Solana programs and generate clients for them. This includes a JavaScript client compatible with this library. For instance, here is how you’d construct a transaction message composed of instructions from three different core programs. - -```ts -import { appendTransactionMessageInstructions, createTransactionMessage, pipe } from '@solana/web3.js'; -import { getAddMemoInstruction } from '@solana-program/memo'; -import { getSetComputeUnitLimitInstruction } from '@solana-program/compute-budget'; -import { getTransferSolInstruction } from '@solana-program/system'; - -const instructions = [ - getSetComputeUnitLimitInstruction({ units: 600_000 }), - getTransferSolInstruction({ source, destination, amount: 1_000_000_000 }), - getAddMemoInstruction({ memo: "I'm transferring some SOL!" }), -]; - -// Creates a V0 transaction message with 3 instructions inside. -const transactionMessage = pipe(createTransactionMessage({ version: 0 }), tx => - appendTransactionMessageInstructions(instructions, tx), -); -``` - -As you can see, each program now generates its own library allowing you to cherry-pick your dependencies. - -Note that asynchronous versions may be available for some instructions which allows them to resolve more inputs on your behalf — such as PDA derivation. For instance, the `CreateLookupTable` instruction offers an asynchronous builder that derives the `address` account and the `bump` argument for us. - -```ts -const rpc = createSolanaRpc('http://127.0.0.1:8899'); -const [authority, recentSlot] = await Promise.all([ - generateKeyPairSigner(), - rpc.getSlot({ commitment: 'finalized' }).send(), -]); - -const instruction = await getCreateLookupTableInstructionAsync({ - authority, - recentSlot, -}); -``` - -Alternatively, you may use the synchronous builder if you already have all the required inputs at hand. - -```ts -const [address, bump] = await findAddressLookupTablePda({ - authority: authority.address, - recentSlot, -}); +const sendAndConfirmNonceTransaction = sendAndConfirmDurableNonceTransactionFactory({ rpc, rpcSubscriptions }); -const instruction = getCreateLookupTableInstruction({ - address, - authority, - bump, - recentSlot, -}); +try { + await sendAndConfirmNonceTransaction(transaction, { commitment: 'confirmed' }); +} catch (e) { + if (isSolanaError(e, SOLANA_ERROR__NONCE_ACCOUNT_NOT_FOUND)) { + console.error( + 'The lifetime specified by this transaction refers to a nonce account ' + + `\`${e.context.nonceAccountAddress}\` that does not exist`, + ); + } else if (isSolanaError(e, SOLANA_ERROR__INVALID_NONCE)) { + console.error('This transaction depends on a nonce that is no longer valid'); + } else { + throw e; + } +} ``` -On top of instruction builders, these clients offer a variety of utilities such as: +### `sendAndConfirmTransactionFactory({rpc, rpcSubscriptions})` -- Instruction codecs — e.g. `getTransferSolInstructionDataCodec`. -- Account types — e.g. `AddressLookupTable`. -- Account codecs — e.g. `getAddressLookupTableAccountDataCodec`. -- Account helpers — e.g. `fetchAddressLookupTable`. -- PDA helpers — e.g. `findAddressLookupTablePda`, `fetchAddressLookupTableFromSeeds`. -- Defined types and their codecs — e.g. `NonceState`, `getNonceStateCodec`. -- Program helpers — e.g. `SYSTEM_PROGRAM_ADDRESS`, `SystemAccount` enum, `SystemAccount` enum, `identifySystemInstruction`. -- And much more! - -Here’s another example that fetches an `AddressLookupTable` PDA from its seeds. +Returns a function that you can call to send a blockhash-based transaction to the network and to wait until it has been confirmed. ```ts -const account = await fetchAddressLookupTableFromSeeds(rpc, { - authority: authority.address, - recentSlot, -}); - -account.address; // Address -account.lamports; // LamportsUnsafeBeyond2Pow53Minus1 -account.data.addresses; // Address[] -account.data.authority; // Some
-account.data.deactivationSlot; // Slot -account.data.lastExtendedSlot; // Slot -account.data.lastExtendedSlotStartIndex; // number -``` +import { isSolanaError, sendAndConfirmTransactionFactory, SOLANA_ERROR__BLOCK_HEIGHT_EXCEEDED } from '@solana/web3.js'; -### How Does This Work? +const sendAndConfirmTransaction = sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions }); -All of this code is 100% auto-generated by Kinobi from a tree of standardized nodes that represent our programs. It contains obvious nodes such as `AccountNode` but also more specified nodes such as `ConditionalValueNode` that allows us to resolve account or argument default values conditionally. - -Kinobi allows us to hydrate our tree of nodes from IDLs which are typically generated by program frameworks such as [Anchor](https://github.com/coral-xyz/anchor) or [Shank](https://github.com/metaplex-foundation/shank). Additionally, visitors can be used on our nodes to expand the knowledge of our programs since the IDL itself doesn’t yet contain that level of information. Finally, special visitors called ‘renderers’ visit our tree to generate clients such as this JavaScript client. - -Currently, there is one other renderer that generates Rust clients but this is only the beginning. In the future, you can expect renderers for auto-generated Python clients, documentation, CLIs, etc. - -## Create Solana Program - -We believe the whole ecosystem could benefit from generated program clients. That’s why we introduced a new NPM binary that allows you to create your Solana program — and generate clients for it — in no time. Simply run the following and follow the prompts to get started. - -```sh -pnpm create solana-program -``` - -This [`create-solana-program`](https://github.com/solana-program/create-solana-program) installer will create a new repository including: - -- An example program using the framework of your choice (Anchor coming soon). -- Generated clients for any of the selected clients. -- A set of scripts that allows you to: - - Start a local validator including all programs and accounts you depend on. - - Build, lint and test your programs. - - Generate IDLs from your programs. - - Generate clients from the generated IDLs. - - Build and test each of your clients. -- GitHub Actions pipelines to test your program, test your clients, and even manually publish new packages or crates for your clients. (Coming soon). - -When selecting the JavaScript client, you will get a fully generated library compatible with the new web3.js much like the `@solana-program` packages showcased above. - -## GraphQL - -Though not directly related to web3.js, we wanted to hijack your attention to show you something else that we’re working on, of particular interest to frontend developers. It’s a new API for interacting with the RPC: a GraphQL API. - -The `@solana/rpc-graphql` package can be used to make GraphQL queries to Solana RPC endpoints, using the same transports described above (including any customizations). - -Here’s an example of retrieving account data with GraphQL: - -```ts -const source = ` - query myQuery($address: String!) { - account(address: $address) { - dataBase58: data(encoding: BASE_58) - dataBase64: data(encoding: BASE_64) - lamports - } +try { + await sendAndConfirmTransaction(transaction, { commitment: 'confirmed' }); +} catch (e) { + if (isSolanaError(e, SOLANA_ERROR__BLOCK_HEIGHT_EXCEEDED)) { + console.error('This transaction depends on a blockhash that has expired'); + } else { + throw e; } -`; - -const variableValues = { - address: 'AyGCwnwxQMCqaU4ixReHt8h5W4dwmxU7eM3BEQBdWVca', -}; - -const result = await rpcGraphQL.query(source, variableValues); - -expect(result).toMatchObject({ - data: { - account: { - dataBase58: '2Uw1bpnsXxu3e', - dataBase64: 'dGVzdCBkYXRh', - lamports: 10290815n, - }, - }, -}); +} ``` -Using GraphQL allows developers to only specify which fields they _actually_ need, and do away with the rest of the response. +### `sendTransactionWithoutConfirmingFactory({rpc, rpcSubscriptions})` -However, GraphQL is also extremely powerful for **nesting queries**, which can be particularly useful if you want to, say, get the **sum** of every lamports balance of every **owner of the owner** of each token account, while discarding any mint accounts. +Returns a function that you can call to send a transaction with any kind of lifetime to the network without waiting for it to be confirmed. ```ts -const source = ` - query getLamportsOfOwnersOfOwnersOfTokenAccounts { - programAccounts(programAddress: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA") { - ... on TokenAccount { - owner { - ownerProgram { - lamports - } - } - } - } - } -`; - -const result = await rpcGraphQL.query(source); - -const sumOfAllLamportsOfOwnersOfOwnersOfTokenAccounts = result - .map(o => o.account.owner.ownerProgram.lamports) - .reduce((acc, lamports) => acc + lamports, 0); -``` +import { + sendTransactionWithoutConfirmingFactory, + SOLANA_ERROR__JSON_RPC__SERVER_ERROR_SEND_TRANSACTION_PREFLIGHT_FAILURE, +} from '@solana/web3.js'; -The new GraphQL package supports this same style of nested querying on transactions and blocks. +const sendTransaction = sendTransactionWithoutConfirmingFactory({ rpc }); -```ts -const source = ` - query myQuery($signature: String!, $commitment: Commitment) { - transaction(signature: $signature, commitment: $commitment) { - message { - instructions { - ... on CreateAccountInstruction { - lamports - programId - space - } - } - } - } +try { + await sendTransaction(transaction, { commitment: 'confirmed' }); +} catch (e) { + if (isSolanaError(e, SOLANA_ERROR__JSON_RPC__SERVER_ERROR_SEND_TRANSACTION_PREFLIGHT_FAILURE)) { + console.error('The transaction failed in simulation', e.cause); + } else { + throw e; } -`; - -const variableValues = { - signature: '63zkpxATgAwXRGFQZPDESTw2m4uZQ99sX338ibgKtTcgG6v34E3MSS3zckCwJHrimS71cvei6h1Bn1K1De53BNWC', - commitment: 'confirmed', -}; - -const result = await rpcGraphQL.query(source, variableValues); - -expect(result).toMatchObject({ - data: { - transaction: { - message: { - instructions: expect.arrayContaining([ - { - lamports: expect.any(BigInt), - programId: '11111111111111111111111111111111', - space: expect.any(BigInt), - }, - ]), - }, - }, - }, -}); +} ``` - -See more in the package’s [README on GitHub](https://github.com/solana-labs/solana-web3.js/tree/master/packages/rpc-graphql). - -## Development - -You can see all development of this library and associated GraphQL tooling in the web3.js repository on GitHub. - -- https://github.com/solana-labs/solana-web3.js - -You can follow along with program client generator development in the `@solana-program` org and the `@kinobi-so/kinobi` repository. - -- https://github.com/solana-program/ -- https://github.com/kinobi-so/kinobi - -Solana Labs develops these tools in public, as open source. We encourage any and all developers who would like to work on these tools to contribute to the codebase. - -## Thank you - -We’re grateful that you have read this far. If you are interested in migrating an existing application to the new web3.js to take advantage of some of the benefits we’ve demonstrated, we want to give you some direct support. Reach out to [@steveluscher](https://t.me/steveluscher/) on Telegram to start a conversation. diff --git a/packages/library/package.json b/packages/library/package.json index af033f772629..31df7087c909 100644 --- a/packages/library/package.json +++ b/packages/library/package.json @@ -1,5 +1,5 @@ { - "name": "@solana/web3.js-experimental", + "name": "@solana/web3.js", "version": "2.0.0-preview.4", "description": "Solana Javascript API", "exports": { @@ -40,8 +40,8 @@ "compile:typedefs": "tsc -p ./tsconfig.declarations.json", "dev": "jest -c ../../node_modules/@solana/test-config/jest-dev.config.ts --rootDir . --watch", "prepublishOnly": "pnpm pkg delete devDependencies", - "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-preview} --access public --no-git-checks", - "publish-packages": "sed -i 's/@solana\\/web3\\.js-experimental/@solana\\/web3\\.js/g' package.json && sed -i 's/@solana\\/web3\\.js/@solana\\/web3\\.js-bak/g' ../library-legacy/package.json && pnpm prepublishOnly && pnpm publish-impl && git reset --hard", + "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-canary} --access public --no-git-checks", + "publish-packages": "pnpm prepublishOnly && pnpm publish-impl", "style:fix": "pnpm eslint --fix src/* && pnpm prettier --log-level warn --ignore-unknown --write ./*", "test:lint": "TERM_OVERRIDE=\"${TURBO_HASH:+dumb}\" TERM=${TERM_OVERRIDE:-$TERM} jest -c ../../node_modules/@solana/test-config/jest-lint.config.ts --rootDir . --silent", "test:prettier": "TERM_OVERRIDE=\"${TURBO_HASH:+dumb}\" TERM=${TERM_OVERRIDE:-$TERM} jest -c ../../node_modules/@solana/test-config/jest-prettier.config.ts --rootDir . --silent", diff --git a/packages/library/tsconfig.json b/packages/library/tsconfig.json index 65139f0a7cdf..323b6d30ed91 100644 --- a/packages/library/tsconfig.json +++ b/packages/library/tsconfig.json @@ -3,7 +3,7 @@ "compilerOptions": { "lib": ["DOM", "ES2020", "ES2022.Error"] }, - "display": "@solana/web3.js-experimental", + "display": "@solana/web3.js", "extends": "../tsconfig/base.json", - "include": ["internal", "src"] + "include": ["src"] } diff --git a/packages/options/package.json b/packages/options/package.json index 43d4c209d0c5..147d74905c7a 100644 --- a/packages/options/package.json +++ b/packages/options/package.json @@ -37,7 +37,7 @@ "compile:typedefs": "tsc -p ./tsconfig.declarations.json", "dev": "jest -c ../../node_modules/@solana/test-config/jest-dev.config.ts --rootDir . --watch", "prepublishOnly": "pnpm pkg delete devDependencies", - "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-preview} --access public --no-git-checks", + "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-canary} --access public --no-git-checks", "publish-packages": "pnpm prepublishOnly && pnpm publish-impl", "style:fix": "pnpm eslint --fix src/* && pnpm prettier --log-level warn --ignore-unknown --write ./*", "test:lint": "TERM_OVERRIDE=\"${TURBO_HASH:+dumb}\" TERM=${TERM_OVERRIDE:-$TERM} jest -c ../../node_modules/@solana/test-config/jest-lint.config.ts --rootDir . --silent", diff --git a/packages/programs/package.json b/packages/programs/package.json index 83c052481c3f..a29556480d4d 100644 --- a/packages/programs/package.json +++ b/packages/programs/package.json @@ -37,7 +37,7 @@ "compile:typedefs": "tsc -p ./tsconfig.declarations.json", "dev": "jest -c ../../node_modules/@solana/test-config/jest-dev.config.ts --rootDir . --watch", "prepublishOnly": "pnpm pkg delete devDependencies", - "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-preview} --access public --no-git-checks", + "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-canary} --access public --no-git-checks", "publish-packages": "pnpm prepublishOnly && pnpm publish-impl", "style:fix": "pnpm eslint --fix src/* && pnpm prettier --log-level warn --ignore-unknown --write ./*", "test:lint": "TERM_OVERRIDE=\"${TURBO_HASH:+dumb}\" TERM=${TERM_OVERRIDE:-$TERM} jest -c ../../node_modules/@solana/test-config/jest-lint.config.ts --rootDir . --silent", diff --git a/packages/react/package.json b/packages/react/package.json index 85b35ba431bd..7ff760f6bf7e 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -37,7 +37,7 @@ "compile:typedefs": "tsc -p ./tsconfig.declarations.json", "dev": "jest -c ../../node_modules/@solana/test-config/jest-dev.config.ts --rootDir . --watch", "prepublishOnly": "pnpm pkg delete devDependencies", - "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-preview} --access public --no-git-checks", + "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-canary} --access public --no-git-checks", "publish-packages": "pnpm prepublishOnly && pnpm publish-impl", "style:fix": "pnpm eslint --fix src/* && pnpm prettier --log-level warn --ignore-unknown --write ./*", "test:lint": "TERM_OVERRIDE=\"${TURBO_HASH:+dumb}\" TERM=${TERM_OVERRIDE:-$TERM} jest -c ../../node_modules/@solana/test-config/jest-lint.config.ts --rootDir . --silent", diff --git a/packages/rpc-api/package.json b/packages/rpc-api/package.json index db48e1b94e5b..f749146fdfec 100644 --- a/packages/rpc-api/package.json +++ b/packages/rpc-api/package.json @@ -37,7 +37,7 @@ "compile:typedefs": "tsc -p ./tsconfig.declarations.json", "dev": "jest -c ../../node_modules/@solana/test-config/jest-dev.config.ts --globalSetup @solana/test-config/test-validator-setup.js --globalTeardown @solana/test-config/test-validator-teardown.js --rootDir . --watch", "prepublishOnly": "pnpm pkg delete devDependencies", - "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-preview} --access public --no-git-checks", + "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-canary} --access public --no-git-checks", "publish-packages": "pnpm prepublishOnly && pnpm publish-impl", "style:fix": "pnpm eslint --fix src/* && pnpm prettier --log-level warn --ignore-unknown --write ./*", "test:lint": "TERM_OVERRIDE=\"${TURBO_HASH:+dumb}\" TERM=${TERM_OVERRIDE:-$TERM} jest -c ../../node_modules/@solana/test-config/jest-lint.config.ts --rootDir . --silent", diff --git a/packages/rpc-graphql/package.json b/packages/rpc-graphql/package.json index a54baae60603..f8037aefc86b 100644 --- a/packages/rpc-graphql/package.json +++ b/packages/rpc-graphql/package.json @@ -37,7 +37,7 @@ "compile:typedefs": "tsc -p ./tsconfig.declarations.json", "dev": "jest -c ../../node_modules/@solana/test-config/jest-dev.config.ts --globalSetup @solana/test-config/test-validator-setup.js --globalTeardown @solana/test-config/test-validator-teardown.js --rootDir . --watch", "prepublishOnly": "pnpm pkg delete devDependencies", - "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-preview} --access public --no-git-checks", + "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-canary} --access public --no-git-checks", "publish-packages": "pnpm prepublishOnly && pnpm publish-impl", "style:fix": "pnpm eslint --fix src/* && pnpm prettier --log-level warn --ignore-unknown --write ./*", "test:lint": "TERM_OVERRIDE=\"${TURBO_HASH:+dumb}\" TERM=${TERM_OVERRIDE:-$TERM} jest -c ../../node_modules/@solana/test-config/jest-lint.config.ts --rootDir . --silent", diff --git a/packages/rpc-parsed-types/package.json b/packages/rpc-parsed-types/package.json index c564fee9dd8c..59b2bf013651 100644 --- a/packages/rpc-parsed-types/package.json +++ b/packages/rpc-parsed-types/package.json @@ -37,7 +37,7 @@ "compile:typedefs": "tsc -p ./tsconfig.declarations.json", "dev": "jest -c ../../node_modules/@solana/test-config/jest-dev.config.ts --globalSetup @solana/test-config/test-validator-setup.js --globalTeardown @solana/test-config/test-validator-teardown.js --rootDir . --watch", "prepublishOnly": "pnpm pkg delete devDependencies", - "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-preview} --access public --no-git-checks", + "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-canary} --access public --no-git-checks", "publish-packages": "pnpm prepublishOnly && pnpm publish-impl", "style:fix": "pnpm eslint --fix src/* && pnpm prettier --log-level warn --ignore-unknown --write ./*", "test:lint": "TERM_OVERRIDE=\"${TURBO_HASH:+dumb}\" TERM=${TERM_OVERRIDE:-$TERM} jest -c ../../node_modules/@solana/test-config/jest-lint.config.ts --rootDir . --silent", diff --git a/packages/rpc-spec-types/package.json b/packages/rpc-spec-types/package.json index c0dae2a5dd63..08857c8f3348 100644 --- a/packages/rpc-spec-types/package.json +++ b/packages/rpc-spec-types/package.json @@ -37,7 +37,7 @@ "compile:typedefs": "tsc -p ./tsconfig.declarations.json", "dev": "jest -c ../../node_modules/@solana/test-config/jest-dev.config.ts --rootDir . --watch", "prepublishOnly": "pnpm pkg delete devDependencies", - "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-preview} --access public --no-git-checks", + "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-canary} --access public --no-git-checks", "publish-packages": "pnpm prepublishOnly && pnpm publish-impl", "style:fix": "pnpm eslint --fix src/* && pnpm prettier --log-level warn --ignore-unknown --write ./*", "test:lint": "TERM_OVERRIDE=\"${TURBO_HASH:+dumb}\" TERM=${TERM_OVERRIDE:-$TERM} jest -c ../../node_modules/@solana/test-config/jest-lint.config.ts --rootDir . --silent", diff --git a/packages/rpc-spec/package.json b/packages/rpc-spec/package.json index 33d76024ef53..724fd3cf26f4 100644 --- a/packages/rpc-spec/package.json +++ b/packages/rpc-spec/package.json @@ -37,7 +37,7 @@ "compile:typedefs": "tsc -p ./tsconfig.declarations.json", "dev": "jest -c ../../node_modules/@solana/test-config/jest-dev.config.ts --rootDir . --watch", "prepublishOnly": "pnpm pkg delete devDependencies", - "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-preview} --access public --no-git-checks", + "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-canary} --access public --no-git-checks", "publish-packages": "pnpm prepublishOnly && pnpm publish-impl", "style:fix": "pnpm eslint --fix src/* && pnpm prettier --log-level warn --ignore-unknown --write ./*", "test:lint": "TERM_OVERRIDE=\"${TURBO_HASH:+dumb}\" TERM=${TERM_OVERRIDE:-$TERM} jest -c ../../node_modules/@solana/test-config/jest-lint.config.ts --rootDir . --silent", diff --git a/packages/rpc-subscriptions-api/package.json b/packages/rpc-subscriptions-api/package.json index d0a6623347ce..0010698f89ef 100644 --- a/packages/rpc-subscriptions-api/package.json +++ b/packages/rpc-subscriptions-api/package.json @@ -37,7 +37,7 @@ "compile:typedefs": "tsc -p ./tsconfig.declarations.json", "dev": "jest -c ../../node_modules/@solana/test-config/jest-dev.config.ts --globalSetup @solana/test-config/test-validator-setup.js --globalTeardown @solana/test-config/test-validator-teardown.js --rootDir . --watch", "prepublishOnly": "pnpm pkg delete devDependencies", - "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-preview} --access public --no-git-checks", + "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-canary} --access public --no-git-checks", "publish-packages": "pnpm prepublishOnly && pnpm publish-impl", "style:fix": "pnpm eslint --fix src/* && pnpm prettier --log-level warn --ignore-unknown --write ./*", "test:lint": "TERM_OVERRIDE=\"${TURBO_HASH:+dumb}\" TERM=${TERM_OVERRIDE:-$TERM} jest -c ../../node_modules/@solana/test-config/jest-lint.config.ts --rootDir . --silent", diff --git a/packages/rpc-subscriptions-spec/package.json b/packages/rpc-subscriptions-spec/package.json index 6ce311771f0d..efb174e6264e 100644 --- a/packages/rpc-subscriptions-spec/package.json +++ b/packages/rpc-subscriptions-spec/package.json @@ -37,7 +37,7 @@ "compile:typedefs": "tsc -p ./tsconfig.declarations.json", "dev": "jest -c ../../node_modules/@solana/test-config/jest-dev.config.ts --rootDir . --watch", "prepublishOnly": "pnpm pkg delete devDependencies", - "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-preview} --access public --no-git-checks", + "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-canary} --access public --no-git-checks", "publish-packages": "pnpm prepublishOnly && pnpm publish-impl", "style:fix": "pnpm eslint --fix src/* && pnpm prettier --log-level warn --ignore-unknown --write ./*", "test:lint": "TERM_OVERRIDE=\"${TURBO_HASH:+dumb}\" TERM=${TERM_OVERRIDE:-$TERM} jest -c ../../node_modules/@solana/test-config/jest-lint.config.ts --rootDir . --silent", diff --git a/packages/rpc-subscriptions-transport-websocket/package.json b/packages/rpc-subscriptions-transport-websocket/package.json index 87ee9e172813..268682fefa5a 100644 --- a/packages/rpc-subscriptions-transport-websocket/package.json +++ b/packages/rpc-subscriptions-transport-websocket/package.json @@ -37,7 +37,7 @@ "compile:typedefs": "tsc -p ./tsconfig.declarations.json", "dev": "jest -c ../../node_modules/@solana/test-config/jest-dev.config.ts --rootDir . --watch", "prepublishOnly": "pnpm pkg delete devDependencies", - "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-preview} --access public --no-git-checks", + "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-canary} --access public --no-git-checks", "publish-packages": "pnpm prepublishOnly && pnpm publish-impl", "style:fix": "pnpm eslint --fix src/* && pnpm prettier --log-level warn --ignore-unknown --write ./*", "test:lint": "TERM_OVERRIDE=\"${TURBO_HASH:+dumb}\" TERM=${TERM_OVERRIDE:-$TERM} jest -c ../../node_modules/@solana/test-config/jest-lint.config.ts --rootDir . --silent", diff --git a/packages/rpc-subscriptions/package.json b/packages/rpc-subscriptions/package.json index 13743ad1c0e5..d9e88af2300d 100644 --- a/packages/rpc-subscriptions/package.json +++ b/packages/rpc-subscriptions/package.json @@ -37,7 +37,7 @@ "compile:typedefs": "tsc -p ./tsconfig.declarations.json", "dev": "jest -c ../../node_modules/@solana/test-config/jest-dev.config.ts --rootDir . --watch", "prepublishOnly": "pnpm pkg delete devDependencies", - "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-preview} --access public --no-git-checks", + "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-canary} --access public --no-git-checks", "publish-packages": "pnpm prepublishOnly && pnpm publish-impl", "style:fix": "pnpm eslint --fix src/* && pnpm prettier --log-level warn --ignore-unknown --write ./*", "test:lint": "TERM_OVERRIDE=\"${TURBO_HASH:+dumb}\" TERM=${TERM_OVERRIDE:-$TERM} jest -c ../../node_modules/@solana/test-config/jest-lint.config.ts --rootDir . --silent", diff --git a/packages/rpc-transformers/package.json b/packages/rpc-transformers/package.json index 34b1a9ac8be2..d8e523dd319c 100644 --- a/packages/rpc-transformers/package.json +++ b/packages/rpc-transformers/package.json @@ -37,7 +37,7 @@ "compile:typedefs": "tsc -p ./tsconfig.declarations.json", "dev": "jest -c ../../node_modules/@solana/test-config/jest-dev.config.ts --rootDir . --watch", "prepublishOnly": "pnpm pkg delete devDependencies", - "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-preview} --access public --no-git-checks", + "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-canary} --access public --no-git-checks", "publish-packages": "pnpm prepublishOnly && pnpm publish-impl", "style:fix": "pnpm eslint --fix src/* && pnpm prettier --log-level warn --ignore-unknown --write ./*", "test:lint": "TERM_OVERRIDE=\"${TURBO_HASH:+dumb}\" TERM=${TERM_OVERRIDE:-$TERM} jest -c ../../node_modules/@solana/test-config/jest-lint.config.ts --rootDir . --silent", diff --git a/packages/rpc-transport-http/package.json b/packages/rpc-transport-http/package.json index 2ce88c9b6142..b38bd1511851 100644 --- a/packages/rpc-transport-http/package.json +++ b/packages/rpc-transport-http/package.json @@ -38,7 +38,7 @@ "compile:typedefs": "tsc -p ./tsconfig.declarations.json", "dev": "jest -c ../../node_modules/@solana/test-config/jest-dev.config.ts --rootDir . --watch", "prepublishOnly": "pnpm pkg delete devDependencies", - "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-preview} --access public --no-git-checks", + "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-canary} --access public --no-git-checks", "publish-packages": "pnpm prepublishOnly && pnpm publish-impl", "style:fix": "pnpm eslint --fix src/* && pnpm prettier --log-level warn --ignore-unknown --write ./*", "test:lint": "TERM_OVERRIDE=\"${TURBO_HASH:+dumb}\" TERM=${TERM_OVERRIDE:-$TERM} jest -c ../../node_modules/@solana/test-config/jest-lint.config.ts --rootDir . --silent", diff --git a/packages/rpc-types/package.json b/packages/rpc-types/package.json index 4344f3759ef7..b8f4f06fa991 100644 --- a/packages/rpc-types/package.json +++ b/packages/rpc-types/package.json @@ -37,7 +37,7 @@ "compile:typedefs": "tsc -p ./tsconfig.declarations.json", "dev": "jest -c ../../node_modules/@solana/test-config/jest-dev.config.ts --globalSetup @solana/test-config/test-validator-setup.js --globalTeardown @solana/test-config/test-validator-teardown.js --rootDir . --watch", "prepublishOnly": "pnpm pkg delete devDependencies", - "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-preview} --access public --no-git-checks", + "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-canary} --access public --no-git-checks", "publish-packages": "pnpm prepublishOnly && pnpm publish-impl", "style:fix": "pnpm eslint --fix src/* && pnpm prettier --log-level warn --ignore-unknown --write ./*", "test:lint": "TERM_OVERRIDE=\"${TURBO_HASH:+dumb}\" TERM=${TERM_OVERRIDE:-$TERM} jest -c ../../node_modules/@solana/test-config/jest-lint.config.ts --rootDir . --silent", diff --git a/packages/rpc/package.json b/packages/rpc/package.json index 7a2976d51670..dcb80c5d85ad 100644 --- a/packages/rpc/package.json +++ b/packages/rpc/package.json @@ -37,7 +37,7 @@ "compile:typedefs": "tsc -p ./tsconfig.declarations.json", "dev": "jest -c ../../node_modules/@solana/test-config/jest-dev.config.ts --rootDir . --watch", "prepublishOnly": "pnpm pkg delete devDependencies", - "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-preview} --access public --no-git-checks", + "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-canary} --access public --no-git-checks", "publish-packages": "pnpm prepublishOnly && pnpm publish-impl", "style:fix": "pnpm eslint --fix src/* && pnpm prettier --log-level warn --ignore-unknown --write ./*", "test:lint": "TERM_OVERRIDE=\"${TURBO_HASH:+dumb}\" TERM=${TERM_OVERRIDE:-$TERM} jest -c ../../node_modules/@solana/test-config/jest-lint.config.ts --rootDir . --silent", diff --git a/packages/signers/package.json b/packages/signers/package.json index 76b89b9ce759..205421e446c8 100644 --- a/packages/signers/package.json +++ b/packages/signers/package.json @@ -37,7 +37,7 @@ "compile:typedefs": "tsc -p ./tsconfig.declarations.json", "dev": "jest -c ../../node_modules/@solana/test-config/jest-dev.config.ts --rootDir . --watch", "prepublishOnly": "pnpm pkg delete devDependencies", - "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-preview} --access public --no-git-checks", + "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-canary} --access public --no-git-checks", "publish-packages": "pnpm prepublishOnly && pnpm publish-impl", "style:fix": "pnpm eslint --fix src/* && pnpm prettier --log-level warn --ignore-unknown --write ./*", "test:lint": "TERM_OVERRIDE=\"${TURBO_HASH:+dumb}\" TERM=${TERM_OVERRIDE:-$TERM} jest -c ../../node_modules/@solana/test-config/jest-lint.config.ts --rootDir . --silent", diff --git a/packages/sysvars/package.json b/packages/sysvars/package.json index 949213507eaf..e6e0b7a30e21 100644 --- a/packages/sysvars/package.json +++ b/packages/sysvars/package.json @@ -37,7 +37,7 @@ "compile:typedefs": "tsc -p ./tsconfig.declarations.json", "dev": "jest -c ../../node_modules/@solana/test-config/jest-dev.config.ts --rootDir . --watch", "prepublishOnly": "pnpm pkg delete devDependencies", - "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-preview} --access public --no-git-checks", + "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-canary} --access public --no-git-checks", "publish-packages": "pnpm prepublishOnly && pnpm publish-impl", "style:fix": "pnpm eslint --fix src/* && pnpm prettier --log-level warn --ignore-unknown --write ./*", "test:lint": "TERM_OVERRIDE=\"${TURBO_HASH:+dumb}\" TERM=${TERM_OVERRIDE:-$TERM} jest -c ../../node_modules/@solana/test-config/jest-lint.config.ts --rootDir . --silent", diff --git a/packages/transaction-confirmation/package.json b/packages/transaction-confirmation/package.json index 773f314816ae..ce93eae0d0bb 100644 --- a/packages/transaction-confirmation/package.json +++ b/packages/transaction-confirmation/package.json @@ -37,7 +37,7 @@ "compile:typedefs": "tsc -p ./tsconfig.declarations.json", "dev": "jest -c ../../node_modules/@solana/test-config/jest-dev.config.ts --rootDir . --watch", "prepublishOnly": "pnpm pkg delete devDependencies", - "publish-packages": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-preview} --access public --no-git-checks", + "publish-packages": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-canary} --access public --no-git-checks", "style:fix": "pnpm eslint --fix src/* && pnpm prettier --log-level warn --ignore-unknown --write ./*", "test:lint": "TERM_OVERRIDE=\"${TURBO_HASH:+dumb}\" TERM=${TERM_OVERRIDE:-$TERM} jest -c ../../node_modules/@solana/test-config/jest-lint.config.ts --rootDir . --silent", "test:prettier": "TERM_OVERRIDE=\"${TURBO_HASH:+dumb}\" TERM=${TERM_OVERRIDE:-$TERM} jest -c ../../node_modules/@solana/test-config/jest-prettier.config.ts --rootDir . --silent", diff --git a/packages/transaction-messages/package.json b/packages/transaction-messages/package.json index e74986cd625c..7e0df95bd655 100644 --- a/packages/transaction-messages/package.json +++ b/packages/transaction-messages/package.json @@ -37,7 +37,7 @@ "compile:typedefs": "tsc -p ./tsconfig.declarations.json", "dev": "jest -c ../../node_modules/@solana/test-config/jest-dev.config.ts --rootDir . --watch", "prepublishOnly": "pnpm pkg delete devDependencies", - "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-preview} --access public --no-git-checks", + "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-canary} --access public --no-git-checks", "publish-packages": "pnpm prepublishOnly && pnpm publish-impl", "style:fix": "pnpm eslint --fix src/* && pnpm prettier --log-level warn --ignore-unknown --write ./*", "test:lint": "TERM_OVERRIDE=\"${TURBO_HASH:+dumb}\" TERM=${TERM_OVERRIDE:-$TERM} jest -c ../../node_modules/@solana/test-config/jest-lint.config.ts --rootDir . --silent", diff --git a/packages/transactions/package.json b/packages/transactions/package.json index 11ba2663cf22..53adf5b54d45 100644 --- a/packages/transactions/package.json +++ b/packages/transactions/package.json @@ -37,7 +37,7 @@ "compile:typedefs": "tsc -p ./tsconfig.declarations.json", "dev": "jest -c ../../node_modules/@solana/test-config/jest-dev.config.ts --rootDir . --watch", "prepublishOnly": "pnpm pkg delete devDependencies", - "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-preview} --access public --no-git-checks", + "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-canary} --access public --no-git-checks", "publish-packages": "pnpm prepublishOnly && pnpm publish-impl", "style:fix": "pnpm eslint --fix src/* && pnpm prettier --log-level warn --ignore-unknown --write ./*", "test:lint": "TERM_OVERRIDE=\"${TURBO_HASH:+dumb}\" TERM=${TERM_OVERRIDE:-$TERM} jest -c ../../node_modules/@solana/test-config/jest-lint.config.ts --rootDir . --silent", diff --git a/packages/webcrypto-ed25519-polyfill/package.json b/packages/webcrypto-ed25519-polyfill/package.json index 7ea1ea96e070..3fea7adbd546 100644 --- a/packages/webcrypto-ed25519-polyfill/package.json +++ b/packages/webcrypto-ed25519-polyfill/package.json @@ -37,7 +37,7 @@ "compile:typedefs": "tsc -p ./tsconfig.declarations.json", "dev": "jest -c ../../node_modules/@solana/test-config/jest-dev.config.ts --rootDir . --watch", "prepublishOnly": "pnpm pkg delete devDependencies", - "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-preview} --access public --no-git-checks", + "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-canary} --access public --no-git-checks", "publish-packages": "pnpm prepublishOnly && pnpm publish-impl", "style:fix": "pnpm eslint --fix src/* && pnpm prettier --log-level warn --ignore-unknown --write ./*", "test:lint": "TERM_OVERRIDE=\"${TURBO_HASH:+dumb}\" TERM=${TERM_OVERRIDE:-$TERM} jest -c ../../node_modules/@solana/test-config/jest-lint.config.ts --rootDir . --silent", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cc69dde98aa0..1cb89ac01840 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -132,7 +132,7 @@ importers: specifier: workspace:* version: link:../utils '@solana/web3.js': - specifier: workspace:@solana/web3.js-experimental@* + specifier: workspace:* version: link:../../packages/library devDependencies: start-server-and-test: @@ -160,7 +160,7 @@ importers: specifier: workspace:* version: link:../../packages/react '@solana/web3.js': - specifier: workspace:@solana/web3.js-experimental@* + specifier: workspace:* version: link:../../packages/library '@wallet-standard/core': specifier: pre @@ -206,7 +206,7 @@ importers: specifier: workspace:* version: link:../utils '@solana/web3.js': - specifier: workspace:@solana/web3.js-experimental@* + specifier: workspace:* version: link:../../packages/library devDependencies: tsx: @@ -219,7 +219,7 @@ importers: specifier: workspace:* version: link:../utils '@solana/web3.js': - specifier: workspace:@solana/web3.js-experimental@* + specifier: workspace:* version: link:../../packages/library devDependencies: start-server-and-test: @@ -238,7 +238,7 @@ importers: specifier: workspace:* version: link:../utils '@solana/web3.js': - specifier: workspace:@solana/web3.js-experimental@* + specifier: workspace:* version: link:../../packages/library devDependencies: start-server-and-test: @@ -439,8 +439,8 @@ importers: version: 5.5.2 devDependencies: '@solana/web3.js': - specifier: workspace:../library-legacy - version: link:../library-legacy + specifier: ^1 + version: 1.95.2(bufferutil@4.0.8)(utf-8-validate@5.0.10) packages/crypto-impl: {} @@ -576,202 +576,6 @@ importers: specifier: '>=5' version: 5.5.2 - packages/library-legacy: - dependencies: - '@babel/runtime': - specifier: ^7.25.0 - version: 7.25.0 - '@noble/curves': - specifier: ^1.4.2 - version: 1.4.2 - '@noble/hashes': - specifier: ^1.4.0 - version: 1.4.0 - '@solana/buffer-layout': - specifier: ^4.0.1 - version: 4.0.1 - agentkeepalive: - specifier: ^4.5.0 - version: 4.5.0 - bigint-buffer: - specifier: ^1.1.5 - version: 1.1.5 - bn.js: - specifier: ^5.2.1 - version: 5.2.1 - borsh: - specifier: ^0.7.0 - version: 0.7.0 - bs58: - specifier: ^4.0.1 - version: 4.0.1 - buffer: - specifier: 6.0.3 - version: 6.0.3 - fast-stable-stringify: - specifier: ^1.0.0 - version: 1.0.0 - jayson: - specifier: ^4.1.1 - version: 4.1.1(bufferutil@4.0.8)(utf-8-validate@5.0.10) - node-fetch: - specifier: ^2.7.0 - version: 2.7.0 - rpc-websockets: - specifier: ^9.0.2 - version: 9.0.2 - superstruct: - specifier: ^2.0.2 - version: 2.0.2 - devDependencies: - '@babel/core': - specifier: ^7.24.9 - version: 7.24.9 - '@babel/plugin-transform-class-properties': - specifier: ^7.24.7 - version: 7.24.7(@babel/core@7.24.9) - '@babel/plugin-transform-private-methods': - specifier: ^7.24.7 - version: 7.24.7(@babel/core@7.24.9) - '@babel/plugin-transform-private-property-in-object': - specifier: ^7.24.7 - version: 7.24.7(@babel/core@7.24.9) - '@babel/plugin-transform-runtime': - specifier: ^7.24.7 - version: 7.24.7(@babel/core@7.24.9) - '@babel/preset-env': - specifier: ^7.25.0 - version: 7.25.0(@babel/core@7.24.9) - '@babel/preset-typescript': - specifier: ^7.24.7 - version: 7.24.7(@babel/core@7.24.9) - '@commitlint/config-conventional': - specifier: ^19.2.2 - version: 19.2.2 - '@rollup/plugin-alias': - specifier: ^5.1.0 - version: 5.1.0(rollup@4.19.0) - '@rollup/plugin-babel': - specifier: ^6.0.4 - version: 6.0.4(@babel/core@7.24.9)(@types/babel__core@7.20.1)(rollup@4.19.0) - '@rollup/plugin-commonjs': - specifier: ^26.0.1 - version: 26.0.1(rollup@4.19.0) - '@rollup/plugin-json': - specifier: ^6.1.0 - version: 6.1.0(rollup@4.19.0) - '@rollup/plugin-node-resolve': - specifier: ^15.2.3 - version: 15.2.3(rollup@4.19.0) - '@rollup/plugin-replace': - specifier: ^5.0.7 - version: 5.0.7(rollup@4.19.0) - '@rollup/plugin-terser': - specifier: ^0.4.4 - version: 0.4.4(rollup@4.19.0) - '@types/bn.js': - specifier: ^5.1.5 - version: 5.1.5 - '@types/bs58': - specifier: ^4.0.1 - version: 4.0.1 - '@types/chai-as-promised': - specifier: ^7.1.8 - version: 7.1.8 - '@types/express-serve-static-core': - specifier: ^4.19.5 - version: 4.19.5 - '@types/mocha': - specifier: ^10.0.6 - version: 10.0.6 - '@types/mz': - specifier: ^2.7.4 - version: 2.7.4 - '@types/node-fetch': - specifier: '2' - version: 2.1.0 - '@types/sinon': - specifier: ^17.0.3 - version: 17.0.3 - '@types/sinon-chai': - specifier: ^3.2.12 - version: 3.2.12 - chai: - specifier: ^5.1.1 - version: 5.1.1 - chai-as-promised: - specifier: ^8.0.0 - version: 8.0.0(chai@5.1.1) - commitlint: - specifier: ^19.3.0 - version: 19.3.0(@types/node@22.0.0)(typescript@5.5.4) - cross-env: - specifier: 7.0.3 - version: 7.0.3 - eslint-config-prettier: - specifier: ^9.1.0 - version: 9.1.0(eslint@8.57.0) - eslint-plugin-import: - specifier: ^2.29.0 - version: 2.29.0(@typescript-eslint/parser@7.17.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0) - eslint-plugin-mocha: - specifier: ^10.4.3 - version: 10.4.3(eslint@8.57.0) - eslint-plugin-prettier: - specifier: ^5.2.1 - version: 5.2.1(eslint-config-prettier@9.1.0(eslint@8.57.0))(eslint@8.57.0)(prettier@3.3.1) - esm: - specifier: ^3.2.25 - version: 3.2.25 - mocha: - specifier: ^10.4.0 - version: 10.4.0 - mockttp: - specifier: ^3.15.0 - version: 3.15.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) - mz: - specifier: ^2.7.0 - version: 2.7.0 - node-abort-controller: - specifier: ^3.0.1 - version: 3.0.1 - prettier: - specifier: ^3.3 - version: 3.3.1 - rimraf: - specifier: 6.0.1 - version: 6.0.1 - rollup: - specifier: ^4.19.0 - version: 4.19.0 - rollup-plugin-dts: - specifier: ^6.1.1 - version: 6.1.1(rollup@4.19.0)(typescript@5.5.4) - rollup-plugin-node-polyfills: - specifier: ^0.2.1 - version: 0.2.1 - semantic-release: - specifier: ^24.0.0 - version: 24.0.0(typescript@5.5.4) - sinon: - specifier: ^18.0.0 - version: 18.0.0 - sinon-chai: - specifier: ^4.0.0 - version: 4.0.0(chai@5.1.1)(sinon@18.0.0) - start-server-and-test: - specifier: ^2.0.4 - version: 2.0.4 - tslib: - specifier: ^2.6.3 - version: 2.6.3 - tsx: - specifier: ^4.16.2 - version: 4.16.2 - typedoc: - specifier: ^0.26.5 - version: 0.26.5(typescript@5.5.4) - packages/options: dependencies: '@solana/codecs-core': @@ -1411,10 +1215,6 @@ packages: resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==} engines: {node: '>=6.0.0'} - '@babel/code-frame@7.24.6': - resolution: {integrity: sha512-ZJhac6FkEd1yhG2AHOmfcXG4ceoLltoCVJjN5XsWN9BifBQr+cHJbWi0h68HZuSORq+3WtJ2z0hwF2NG1b5kcA==} - engines: {node: '>=6.9.0'} - '@babel/code-frame@7.24.7': resolution: {integrity: sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==} engines: {node: '>=6.9.0'} @@ -1492,10 +1292,6 @@ packages: resolution: {integrity: sha512-LABppdt+Lp/RlBxqrh4qgf1oEH/WxdzQNDJIu5gC/W1GyvPVrOBiItmmM8wan2fm4oYqFuFfkXmlGpLQhPY8CA==} engines: {node: '>=6.9.0'} - '@babel/helper-module-imports@7.22.15': - resolution: {integrity: sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==} - engines: {node: '>=6.9.0'} - '@babel/helper-module-imports@7.24.7': resolution: {integrity: sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==} engines: {node: '>=6.9.0'} @@ -1584,10 +1380,6 @@ packages: resolution: {integrity: sha512-gV2265Nkcz7weJJfvDoAEVzC1e2OTDpkGbEsebse8koXUJUXPsCMi7sRo/+SPMuMZ9MtUPnGwITTnQnU5YjyaQ==} engines: {node: '>=6.9.0'} - '@babel/highlight@7.24.6': - resolution: {integrity: sha512-2YnuOp4HAk2BsBrJJvYCbItHx0zWscI1C3zgWkz+wDyD9I7GIVrfnLyrR4Y1VR+7p+chAEcrgRQYZAGIKMV7vQ==} - engines: {node: '>=6.9.0'} - '@babel/highlight@7.24.7': resolution: {integrity: sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==} engines: {node: '>=6.9.0'} @@ -2020,12 +1812,6 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-runtime@7.24.7': - resolution: {integrity: sha512-YqXjrk4C+a1kZjewqt+Mmu2UuV1s07y8kqcUf4qYLnoqemhR4gRQikhdAhSVJioMjVTu6Mo6pAbaypEA3jY6fw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-shorthand-properties@7.24.7': resolution: {integrity: sha512-KsDsevZMDsigzbA09+vacnLpmPH4aWjcZjXdyFKGzpplxhbeB4wYtury3vglQkg6KM/xEPKt73eCjPPf1PgXBA==} engines: {node: '>=6.9.0'} @@ -2218,79 +2004,6 @@ packages: '@changesets/write@0.3.1': resolution: {integrity: sha512-SyGtMXzH3qFqlHKcvFY2eX+6b0NGiFcNav8AFsYwy5l8hejOeoeTDemu5Yjmke2V5jpzY+pBvM0vCCQ3gdZpfw==} - '@colors/colors@1.5.0': - resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} - engines: {node: '>=0.1.90'} - - '@commitlint/cli@19.3.0': - resolution: {integrity: sha512-LgYWOwuDR7BSTQ9OLZ12m7F/qhNY+NpAyPBgo4YNMkACE7lGuUnuQq1yi9hz1KA4+3VqpOYl8H1rY/LYK43v7g==} - engines: {node: '>=v18'} - hasBin: true - - '@commitlint/config-conventional@19.2.2': - resolution: {integrity: sha512-mLXjsxUVLYEGgzbxbxicGPggDuyWNkf25Ht23owXIH+zV2pv1eJuzLK3t1gDY5Gp6pxdE60jZnWUY5cvgL3ufw==} - engines: {node: '>=v18'} - - '@commitlint/config-validator@19.0.3': - resolution: {integrity: sha512-2D3r4PKjoo59zBc2auodrSCaUnCSALCx54yveOFwwP/i2kfEAQrygwOleFWswLqK0UL/F9r07MFi5ev2ohyM4Q==} - engines: {node: '>=v18'} - - '@commitlint/ensure@19.0.3': - resolution: {integrity: sha512-SZEpa/VvBLoT+EFZVb91YWbmaZ/9rPH3ESrINOl0HD2kMYsjvl0tF7nMHh0EpTcv4+gTtZBAe1y/SS6/OhfZzQ==} - engines: {node: '>=v18'} - - '@commitlint/execute-rule@19.0.0': - resolution: {integrity: sha512-mtsdpY1qyWgAO/iOK0L6gSGeR7GFcdW7tIjcNFxcWkfLDF5qVbPHKuGATFqRMsxcO8OUKNj0+3WOHB7EHm4Jdw==} - engines: {node: '>=v18'} - - '@commitlint/format@19.3.0': - resolution: {integrity: sha512-luguk5/aF68HiF4H23ACAfk8qS8AHxl4LLN5oxPc24H+2+JRPsNr1OS3Gaea0CrH7PKhArBMKBz5RX9sA5NtTg==} - engines: {node: '>=v18'} - - '@commitlint/is-ignored@19.2.2': - resolution: {integrity: sha512-eNX54oXMVxncORywF4ZPFtJoBm3Tvp111tg1xf4zWXGfhBPKpfKG6R+G3G4v5CPlRROXpAOpQ3HMhA9n1Tck1g==} - engines: {node: '>=v18'} - - '@commitlint/lint@19.2.2': - resolution: {integrity: sha512-xrzMmz4JqwGyKQKTpFzlN0dx0TAiT7Ran1fqEBgEmEj+PU98crOFtysJgY+QdeSagx6EDRigQIXJVnfrI0ratA==} - engines: {node: '>=v18'} - - '@commitlint/load@19.2.0': - resolution: {integrity: sha512-XvxxLJTKqZojCxaBQ7u92qQLFMMZc4+p9qrIq/9kJDy8DOrEa7P1yx7Tjdc2u2JxIalqT4KOGraVgCE7eCYJyQ==} - engines: {node: '>=v18'} - - '@commitlint/message@19.0.0': - resolution: {integrity: sha512-c9czf6lU+9oF9gVVa2lmKaOARJvt4soRsVmbR7Njwp9FpbBgste5i7l/2l5o8MmbwGh4yE1snfnsy2qyA2r/Fw==} - engines: {node: '>=v18'} - - '@commitlint/parse@19.0.3': - resolution: {integrity: sha512-Il+tNyOb8VDxN3P6XoBBwWJtKKGzHlitEuXA5BP6ir/3loWlsSqDr5aecl6hZcC/spjq4pHqNh0qPlfeWu38QA==} - engines: {node: '>=v18'} - - '@commitlint/read@19.2.1': - resolution: {integrity: sha512-qETc4+PL0EUv7Q36lJbPG+NJiBOGg7SSC7B5BsPWOmei+Dyif80ErfWQ0qXoW9oCh7GTpTNRoaVhiI8RbhuaNw==} - engines: {node: '>=v18'} - - '@commitlint/resolve-extends@19.1.0': - resolution: {integrity: sha512-z2riI+8G3CET5CPgXJPlzftH+RiWYLMYv4C9tSLdLXdr6pBNimSKukYP9MS27ejmscqCTVA4almdLh0ODD2KYg==} - engines: {node: '>=v18'} - - '@commitlint/rules@19.0.3': - resolution: {integrity: sha512-TspKb9VB6svklxNCKKwxhELn7qhtY1rFF8ls58DcFd0F97XoG07xugPjjbVnLqmMkRjZDbDIwBKt9bddOfLaPw==} - engines: {node: '>=v18'} - - '@commitlint/to-lines@19.0.0': - resolution: {integrity: sha512-vkxWo+VQU5wFhiP9Ub9Sre0FYe019JxFikrALVoD5UGa8/t3yOJEpEhxC5xKiENKKhUkTpEItMTRAjHw2SCpZw==} - engines: {node: '>=v18'} - - '@commitlint/top-level@19.0.0': - resolution: {integrity: sha512-KKjShd6u1aMGNkCkaX4aG1jOGdn7f8ZI8TR1VEuNqUOjWTOdcDSsmglinglJ18JTjuBX5I1PtjrhQCRcixRVFQ==} - engines: {node: '>=v18'} - - '@commitlint/types@19.0.3': - resolution: {integrity: sha512-tpyc+7i6bPG9mvaBbtKUeghfyZSDgWquIDfMgqYtTbmZ9Y9VzEm2je9EYcQ0aoz5o7NvGS+rcDec93yO08MHYA==} - engines: {node: '>=v18'} - '@cspotcode/source-map-support@0.8.1': resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} @@ -2614,11 +2327,6 @@ packages: '@floating-ui/utils@0.2.3': resolution: {integrity: sha512-XGndio0l5/Gvd6CLIABvsav9HHezgDFFhDfHk1bvLfr9ni8dojqLSvBbotJEjmIwNHL7vK4QzBJTdBRoB+c1ww==} - '@graphql-tools/merge@8.3.1': - resolution: {integrity: sha512-BMm99mqdNZbEYeTPK3it9r9S6rsZsQKtlqJsSBknAclXq2pGEfOxjcIZi+kBSkHZKPKCRrYDd5vY0+rUmIHVLg==} - peerDependencies: - graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 - '@graphql-tools/merge@9.0.3': resolution: {integrity: sha512-FeKv9lKLMwqDu0pQjPpF59GY3HReUkWXKsMIuMuJQOKh9BETu7zPEFUELvcw8w+lwZkl4ileJsHXC9+AnsT2Lw==} engines: {node: '>=16.0.0'} @@ -2631,27 +2339,12 @@ packages: peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 - '@graphql-tools/schema@8.5.1': - resolution: {integrity: sha512-0Esilsh0P/qYcB5DKQpiKeQs/jevzIadNTaT0jeWklPMwNbT7yMX4EqZany7mbeRRlSRwMzNzL5olyFdffHBZg==} - peerDependencies: - graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 - '@graphql-tools/utils@10.2.1': resolution: {integrity: sha512-U8OMdkkEt3Vp3uYHU2pMc6mwId7axVAcSSmcqJcUmWNPqY2pfee5O655ybTI2kNPWAe58Zu6gLu4Oi4QT4BgWA==} engines: {node: '>=16.0.0'} peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 - '@graphql-tools/utils@8.13.1': - resolution: {integrity: sha512-qIh9yYpdUFmctVqovwMdheVNJqFh+DQNWIhX87FJStfXYnmweBUDATok9fWPleKeFwxnW8IapKmY8m8toJEkAw==} - peerDependencies: - graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 - - '@graphql-tools/utils@8.9.0': - resolution: {integrity: sha512-pjJIWH0XOVnYGXCqej8g/u/tsfV4LvLlj0eATKQu5zwnxd/TiTHq7Cg313qUPTFFHZ3PP5wJ15chYVtLDwaymg==} - peerDependencies: - graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 - '@graphql-typed-document-node/core@3.2.0': resolution: {integrity: sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==} peerDependencies: @@ -2663,18 +2356,6 @@ packages: '@hapi/topo@5.1.0': resolution: {integrity: sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==} - '@httptoolkit/httpolyglot@2.2.1': - resolution: {integrity: sha512-HOS/0zWc3yn7NM0RQFgBeepeTE8eAKtyOkcGL/TV6if5MAfr+3bH9rwCyAhbXbjlLVR3afeBRt8JYKEerDcygA==} - engines: {node: '>=12.0.0'} - - '@httptoolkit/subscriptions-transport-ws@0.11.2': - resolution: {integrity: sha512-YB+gYYVjgYUeJrGkfS91ABeNWCFU7EVcn9Cflf2UXjsIiPJEI6yPxujPcjKv9wIJpM+33KQW/qVEmc+BdIDK2w==} - peerDependencies: - graphql: ^15.7.2 || ^16.0.0 - - '@httptoolkit/websocket-stream@6.0.1': - resolution: {integrity: sha512-A0NOZI+Glp3Xgcz6Na7i7o09+/+xm2m0UCU8gdtM2nIv6/cjLmhMZMqehSpTlgbx9omtLmV8LVqOskPEyWnmZQ==} - '@humanwhocodes/config-array@0.11.14': resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} engines: {node: '>=10.10.0'} @@ -2904,54 +2585,6 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} - '@octokit/auth-token@5.1.1': - resolution: {integrity: sha512-rh3G3wDO8J9wSjfI436JUKzHIxq8NaiL0tVeB2aXmG6p/9859aUOAjA9pmSPNGGZxfwmaJ9ozOJImuNVJdpvbA==} - engines: {node: '>= 18'} - - '@octokit/core@6.1.2': - resolution: {integrity: sha512-hEb7Ma4cGJGEUNOAVmyfdB/3WirWMg5hDuNFVejGEDFqupeOysLc2sG6HJxY2etBp5YQu5Wtxwi020jS9xlUwg==} - engines: {node: '>= 18'} - - '@octokit/endpoint@10.1.1': - resolution: {integrity: sha512-JYjh5rMOwXMJyUpj028cu0Gbp7qe/ihxfJMLc8VZBMMqSwLgOxDI1911gV4Enl1QSavAQNJcwmwBF9M0VvLh6Q==} - engines: {node: '>= 18'} - - '@octokit/graphql@8.1.1': - resolution: {integrity: sha512-ukiRmuHTi6ebQx/HFRCXKbDlOh/7xEV6QUXaE7MJEKGNAncGI/STSbOkl12qVXZrfZdpXctx5O9X1AIaebiDBg==} - engines: {node: '>= 18'} - - '@octokit/openapi-types@22.1.0': - resolution: {integrity: sha512-pGUdSP+eEPfZiQHNkZI0U01HLipxncisdJQB4G//OAmfeO8sqTQ9KRa0KF03TUPCziNsoXUrTg4B2Q1EX++T0Q==} - - '@octokit/plugin-paginate-rest@11.1.1': - resolution: {integrity: sha512-joUIZu9TupD4pRXLmWShD1Ur/oxYf/bJjYcnaopmGTReNrmWwcW7DUGSrWOjoTeihnlDig+a79m8koiafc4XQw==} - engines: {node: '>= 18'} - peerDependencies: - '@octokit/core': '>=6' - - '@octokit/plugin-retry@7.1.0': - resolution: {integrity: sha512-6mc4xNtT6eoDBGrJJn0sFALUmIba2f7Wx+G8XV9GkBLcyX5PogBdx2mDMW5yPPqSD/y23tYagkjOLX9sT7O6jA==} - engines: {node: '>= 18'} - peerDependencies: - '@octokit/core': '>=6' - - '@octokit/plugin-throttling@9.2.0': - resolution: {integrity: sha512-zHZSZCC7wk3HbK3ZCuvc3iPrnFGoYIVJsJAY4l8ilsVu4fqPfe7BP7QLZ1A641yttLWqgy2oID3ETD3Z1036Gw==} - engines: {node: '>= 18'} - peerDependencies: - '@octokit/core': ^6.0.0 - - '@octokit/request-error@6.1.1': - resolution: {integrity: sha512-1mw1gqT3fR/WFvnoVpY/zUM2o/XkMs/2AszUUG9I69xn0JFLv6PGkPhNk5lbfvROs79wiS0bqiJNxfCZcRJJdg==} - engines: {node: '>= 18'} - - '@octokit/request@9.1.1': - resolution: {integrity: sha512-pyAguc0p+f+GbQho0uNetNQMmLG1e80WjkIaqqgUkihqUp0boRU6nKItXO4VWnr+nbZiLGEyy4TeKRwqaLvYgw==} - engines: {node: '>= 18'} - - '@octokit/types@13.4.1': - resolution: {integrity: sha512-Y73oOAzRBAUzR/iRAbGULzpNkX8vaxKCqEtg6K74Ff3w9f5apFnWtE/2nade7dMWWW3bS5Kkd6DJS4HF04xreg==} - '@pkgjs/parseargs@0.11.0': resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} @@ -2960,18 +2593,6 @@ packages: resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} - '@pnpm/config.env-replace@1.1.0': - resolution: {integrity: sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==} - engines: {node: '>=12.22.0'} - - '@pnpm/network.ca-file@1.0.2': - resolution: {integrity: sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==} - engines: {node: '>=12.22.0'} - - '@pnpm/npm-conf@2.2.2': - resolution: {integrity: sha512-UA91GwWPhFExt3IizW6bOeY/pQ0BkuNwKjk9iQW9KqxluGCrg4VenZ0/L+2Y0+ZOtme72EVvg6v0zo3AMQRCeA==} - engines: {node: '>=12'} - '@radix-ui/colors@3.0.0': resolution: {integrity: sha512-FUOsGBkHrYJwCSEtWRCIfQbZG7q1e6DgxCIOe1SUQzDe/7rXXeA47s8yCn6fuTNQAj1Zq4oTFi9Yjp3wzElcxg==} @@ -3561,73 +3182,6 @@ packages: '@types/react-dom': optional: true - '@rollup/plugin-alias@5.1.0': - resolution: {integrity: sha512-lpA3RZ9PdIG7qqhEfv79tBffNaoDuukFDrmhLqg9ifv99u/ehn+lOg30x2zmhf8AQqQUZaMk/B9fZraQ6/acDQ==} - engines: {node: '>=14.0.0'} - peerDependencies: - rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 - peerDependenciesMeta: - rollup: - optional: true - - '@rollup/plugin-babel@6.0.4': - resolution: {integrity: sha512-YF7Y52kFdFT/xVSuVdjkV5ZdX/3YtmX0QulG+x0taQOtJdHYzVU61aSSkAgVJ7NOv6qPkIYiJSgSWWN/DM5sGw==} - engines: {node: '>=14.0.0'} - peerDependencies: - '@babel/core': ^7.0.0 - '@types/babel__core': ^7.1.9 - rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 - peerDependenciesMeta: - '@types/babel__core': - optional: true - rollup: - optional: true - - '@rollup/plugin-commonjs@26.0.1': - resolution: {integrity: sha512-UnsKoZK6/aGIH6AdkptXhNvhaqftcjq3zZdT+LY5Ftms6JR06nADcDsYp5hTU9E2lbJUEOhdlY5J4DNTneM+jQ==} - engines: {node: '>=16.0.0 || 14 >= 14.17'} - peerDependencies: - rollup: ^2.68.0||^3.0.0||^4.0.0 - peerDependenciesMeta: - rollup: - optional: true - - '@rollup/plugin-json@6.1.0': - resolution: {integrity: sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA==} - engines: {node: '>=14.0.0'} - peerDependencies: - rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 - peerDependenciesMeta: - rollup: - optional: true - - '@rollup/plugin-node-resolve@15.2.3': - resolution: {integrity: sha512-j/lym8nf5E21LwBT4Df1VD6hRO2L2iwUeUmP7litikRsVp1H6NWx20NEp0Y7su+7XGc476GnXXc4kFeZNGmaSQ==} - engines: {node: '>=14.0.0'} - peerDependencies: - rollup: ^2.78.0||^3.0.0||^4.0.0 - peerDependenciesMeta: - rollup: - optional: true - - '@rollup/plugin-replace@5.0.7': - resolution: {integrity: sha512-PqxSfuorkHz/SPpyngLyg5GCEkOcee9M1bkxiVDr41Pd61mqP1PLOoDPbpl44SB2mQGKwV/In74gqQmGITOhEQ==} - engines: {node: '>=14.0.0'} - peerDependencies: - rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 - peerDependenciesMeta: - rollup: - optional: true - - '@rollup/plugin-terser@0.4.4': - resolution: {integrity: sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==} - engines: {node: '>=14.0.0'} - peerDependencies: - rollup: ^2.0.0||^3.0.0||^4.0.0 - peerDependenciesMeta: - rollup: - optional: true - '@rollup/plugin-virtual@3.0.1': resolution: {integrity: sha512-fK8O0IL5+q+GrsMLuACVNk2x21g3yaw+sG2qn16SnUd3IlBsQyvWxLMGHmCmXRMecPjGRSZ/1LmZB4rjQm68og==} engines: {node: '>=14.0.0'} @@ -3637,24 +3191,6 @@ packages: rollup: optional: true - '@rollup/pluginutils@5.0.2': - resolution: {integrity: sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA==} - engines: {node: '>=14.0.0'} - peerDependencies: - rollup: ^1.20.0||^2.0.0||^3.0.0 - peerDependenciesMeta: - rollup: - optional: true - - '@rollup/pluginutils@5.1.0': - resolution: {integrity: sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==} - engines: {node: '>=14.0.0'} - peerDependencies: - rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 - peerDependenciesMeta: - rollup: - optional: true - '@rollup/rollup-android-arm-eabi@4.19.0': resolution: {integrity: sha512-JlPfZ/C7yn5S5p0yKk7uhHTTnFlvTgLetl2VxqE518QgyM7C9bSfFTYvB/Q/ftkq0RIPY4ySxTz+/wKJ/dXC0w==} cpu: [arm] @@ -3735,40 +3271,6 @@ packages: cpu: [x64] os: [win32] - '@sec-ant/readable-stream@0.4.1': - resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==} - - '@semantic-release/commit-analyzer@13.0.0': - resolution: {integrity: sha512-KtXWczvTAB1ZFZ6B4O+w8HkfYm/OgQb1dUGNFZtDgQ0csggrmkq8sTxhd+lwGF8kMb59/RnG9o4Tn7M/I8dQ9Q==} - engines: {node: '>=20.8.1'} - peerDependencies: - semantic-release: '>=20.1.0' - - '@semantic-release/error@4.0.0': - resolution: {integrity: sha512-mgdxrHTLOjOddRVYIYDo0fR3/v61GNN1YGkfbrjuIKg/uMgCd+Qzo3UAXJ+woLQQpos4pl5Esuw5A7AoNlzjUQ==} - engines: {node: '>=18'} - - '@semantic-release/github@10.0.5': - resolution: {integrity: sha512-hmuCDkfru/Uc9+ZBNOSremAupu6BCslvOVDiG0wYcL8TQodCycp6uvwDyeym1H0M4l3ob9c0s0xMBiZjjXQ2yA==} - engines: {node: '>=20.8.1'} - peerDependencies: - semantic-release: '>=20.1.0' - - '@semantic-release/npm@12.0.1': - resolution: {integrity: sha512-/6nntGSUGK2aTOI0rHPwY3ZjgY9FkXmEHbW9Kr+62NVOsyqpKKeP0lrCH+tphv+EsNdJNmqqwijTEnVWUMQ2Nw==} - engines: {node: '>=20.8.1'} - peerDependencies: - semantic-release: '>=20.1.0' - - '@semantic-release/release-notes-generator@14.0.0': - resolution: {integrity: sha512-XRxwr4e46yUMaXT8KGFBlRJlp5+NOMaufdq8qaEWlcJ7cT4Pn/iRmDGglZ2TgDe6GVP+u1boXFEnSs7N8Yzhng==} - engines: {node: '>=20.8.1'} - peerDependencies: - semantic-release: '>=20.1.0' - - '@shikijs/core@1.9.1': - resolution: {integrity: sha512-EmUful2MQtY8KgCF1OkBtOuMcvaZEvmdubhW0UHCGXi21O9dRLeADVCj+k6ZS+de7Mz9d2qixOXJ+GLhcK3pXg==} - '@sideway/address@4.1.5': resolution: {integrity: sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==} @@ -3784,24 +3286,9 @@ packages: '@sinclair/typebox@0.32.18': resolution: {integrity: sha512-ioMK5TA5YOloYf/GcnF+1fT4eTvowJes2j7Pm0Ivlm9xq61keqQw/XtbQQnPG8O4uq2y2DDenU8OqNc93xn11Q==} - '@sindresorhus/is@4.6.0': - resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} - engines: {node: '>=10'} - - '@sindresorhus/merge-streams@2.3.0': - resolution: {integrity: sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==} - engines: {node: '>=18'} - - '@sindresorhus/merge-streams@4.0.0': - resolution: {integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==} - engines: {node: '>=18'} - '@sinonjs/commons@1.8.6': resolution: {integrity: sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==} - '@sinonjs/commons@2.0.0': - resolution: {integrity: sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==} - '@sinonjs/commons@3.0.1': resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} @@ -3811,12 +3298,6 @@ packages: '@sinonjs/fake-timers@8.1.0': resolution: {integrity: sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==} - '@sinonjs/samsam@8.0.0': - resolution: {integrity: sha512-Bp8KUVlLp8ibJZrnvq2foVhP0IVX2CIprMJPK0vqGqgrDa0OHVKeZyBykqskkrdxV6yKBPmGasO8LVjAKR3Gew==} - - '@sinonjs/text-encoding@0.7.2': - resolution: {integrity: sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==} - '@solana-program/memo@0.4.0': resolution: {integrity: sha512-jtad4YNC7PgIZJo6mVbdsOqZB69ND8QGjDVJWsYT6WnBFpOHVhQf/WBDkLkcbZqjxYAJV8RjVVj52AwR26G5Aw==} peerDependencies: @@ -3858,6 +3339,9 @@ packages: resolution: {integrity: sha512-tUd9srDLkRpe1BYg7we+c4UhRQkq+XQWswsr/L1xfGmoRDF47BPSXf4zE7ZU2GRBGvxtGt7lwJVAufQyQYhxTQ==} engines: {node: '>=16'} + '@solana/web3.js@1.95.2': + resolution: {integrity: sha512-SjlHp0G4qhuhkQQc+YXdGkI8EerCqwxvgytMgBpzMUQTafrkNant3e7pgilBGgjy/iM40ICvWBLgASTPMrQU7w==} + '@swc/core-darwin-arm64@1.6.5': resolution: {integrity: sha512-RGQhMdni2v1/ANQ/2K+F+QYdzaucekYBewZcX1ogqJ8G5sbPaBdYdDN1qQ4kHLCIkPtGP6qC7c71qPEqL2RidQ==} engines: {node: '>=10'} @@ -3946,9 +3430,6 @@ packages: resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} engines: {node: '>= 10'} - '@tootallnate/quickjs-emscripten@0.23.0': - resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==} - '@tsconfig/node10@1.0.11': resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} @@ -3973,33 +3454,12 @@ packages: '@types/babel__traverse@7.20.1': resolution: {integrity: sha512-MitHFXnhtgwsGZWtT68URpOvLN4EREih1u3QtQiN4VdAxWKRVvGCSvw/Qth0M0Qq3pJpnGOu5JaM/ydK7OGbqg==} - '@types/bn.js@5.1.5': - resolution: {integrity: sha512-V46N0zwKRF5Q00AZ6hWtN0T8gGmDUaUzLWQvHFo5yThtVwK/VCenFY3wXVbOvNfajEpsTfQM4IN9k/d6gUVX3A==} - - '@types/bs58@4.0.1': - resolution: {integrity: sha512-yfAgiWgVLjFCmRv8zAcOIHywYATEwiTVccTLnRp6UxTNavT55M9d/uhK3T03St/+8/z/wW+CRjGKUNmEqoHHCA==} - - '@types/chai-as-promised@7.1.8': - resolution: {integrity: sha512-ThlRVIJhr69FLlh6IctTXFkmhtP3NpMZ2QGq69StYLyKZFp/HOp1VdKZj7RvfNWYYcJ1xlbLGLLWj1UvP5u/Gw==} - - '@types/chai@4.3.14': - resolution: {integrity: sha512-Wj71sXE4Q4AkGdG9Tvq1u/fquNz9EdG4LIJMwVVII7ashjD/8cf8fyIfJAjRr6YcsXnSE8cOGQPq1gqeR8z+3w==} - '@types/connect@3.4.35': resolution: {integrity: sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==} - '@types/conventional-commits-parser@5.0.0': - resolution: {integrity: sha512-loB369iXNmAZglwWATL+WRe+CRMmmBPtpolYzIebFaX4YA3x+BEfLqhUAV9WanycKI3TG1IMr5bMJDajDKLlUQ==} - - '@types/cors@2.8.17': - resolution: {integrity: sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==} - '@types/estree@1.0.5': resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} - '@types/express-serve-static-core@4.19.5': - resolution: {integrity: sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg==} - '@types/fastestsmallesttextencoderdecoder@1.0.2': resolution: {integrity: sha512-0Md9qUxGnQ9uJ0NjsA70Y0NHIl3NwfBO1d8CGXK0zhczRL85CXJ3M0JZsmCNQ0WcAbt08FuT4U1G1mWQqgOsUg==} @@ -4036,27 +3496,12 @@ packages: '@types/json-stable-stringify@1.0.36': resolution: {integrity: sha512-b7bq23s4fgBB76n34m2b3RBf6M369B0Z9uRR8aHTMd8kZISRkmDEpPD8hhpYvDFzr3bJCPES96cm3Q6qRNDbQw==} - '@types/json5@0.0.29': - resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} - '@types/jsonfile@6.1.4': resolution: {integrity: sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==} - '@types/mime@1.3.2': - resolution: {integrity: sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==} - - '@types/mocha@10.0.6': - resolution: {integrity: sha512-dJvrYWxP/UcXm36Qn36fxhUKu8A/xMRXVT2cliFF1Z7UA9liG5Psj3ezNSZw+5puH2czDXRLcXQxf8JbJt0ejg==} - '@types/mute-stream@0.0.4': resolution: {integrity: sha512-CPM9nzrCPPJHQNA9keH9CVkVI+WR5kMa+7XEs5jcGQ0VoAGnLv242w8lIVgwAEfmE4oufJRaTc9PNLQl0ioAow==} - '@types/mz@2.7.4': - resolution: {integrity: sha512-Zs0imXxyWT20j3Z2NwKpr0IO2LmLactBblNyLua5Az4UHuqOQ02V3jPTgyKwDkuc33/ahw+C3O1PIZdrhFMuQA==} - - '@types/node-fetch@2.1.0': - resolution: {integrity: sha512-7qhZIMCvHDJMZtdirrb/SkmTs2Dg8oVCLpUCOxNKm36xBdUZhh2JDWO/BeOdI5UyStyaCmeRv5UskaiH7kAgdg==} - '@types/node@12.20.55': resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} @@ -4069,9 +3514,6 @@ packages: '@types/node@22.0.0': resolution: {integrity: sha512-VT7KSYudcPOzP5Q0wfbowyNLaVR8QWUdw+088uFWwfvpY6uCWaXpqV6ieLAu9WBcnTa7H4Z5RLK8I5t2FuOcqw==} - '@types/normalize-package-data@2.4.4': - resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} - '@types/parse-json@4.0.0': resolution: {integrity: sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==} @@ -4081,12 +3523,6 @@ packages: '@types/prop-types@15.7.12': resolution: {integrity: sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==} - '@types/qs@6.9.7': - resolution: {integrity: sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==} - - '@types/range-parser@1.2.4': - resolution: {integrity: sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==} - '@types/react-dom@18.3.0': resolution: {integrity: sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==} @@ -4096,24 +3532,9 @@ packages: '@types/react@18.3.3': resolution: {integrity: sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==} - '@types/resolve@1.20.2': - resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} - '@types/semver@7.5.8': resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} - '@types/send@0.17.1': - resolution: {integrity: sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q==} - - '@types/sinon-chai@3.2.12': - resolution: {integrity: sha512-9y0Gflk3b0+NhQZ/oxGtaAJDvRywCa5sIyaVnounqLvmf93yBF4EgIRspePtkMs3Tr844nCclYMlcCNmLCvjuQ==} - - '@types/sinon@17.0.3': - resolution: {integrity: sha512-j3uovdn8ewky9kRBG19bOwaZbexJu/XjtkHyjvUgt4xfPFz18dcORIMqnYh66Fx3Powhcr85NT5+er3+oViapw==} - - '@types/sinonjs__fake-timers@8.1.2': - resolution: {integrity: sha512-9GcLXF0/v3t80caGs5p2rRfkB+a8VBGLJZVih6CNFkx8IZ994wiKKLSRs9nuFwk1HevWs/1mnUmkApGrSGsShA==} - '@types/stack-utils@2.0.2': resolution: {integrity: sha512-g7CK9nHdwjK2n0ymT2CW698FuWJRIx+RP6embAzZ2Qi8/ilIrA1Imt2LVSeHUzKvpoi7BhmmQcXz95eS0f2JXw==} @@ -4132,9 +3553,6 @@ packages: '@types/ws@7.4.7': resolution: {integrity: sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==} - '@types/ws@8.5.11': - resolution: {integrity: sha512-4+q7P5h3SpJxaBft0Dzpbr6lmMaqh0Jr2tbhJZ/luAwvD7ohSCniYkwz/pLxuT2h0EOa6QADgJj1Ko+TzRfZ+w==} - '@types/ws@8.5.12': resolution: {integrity: sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ==} @@ -4369,10 +3787,6 @@ packages: resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} engines: {node: '>=6.5'} - accepts@1.3.8: - resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} - engines: {node: '>= 0.6'} - acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -4400,28 +3814,13 @@ packages: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} - agent-base@7.1.1: - resolution: {integrity: sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==} - engines: {node: '>= 14'} - agentkeepalive@4.5.0: resolution: {integrity: sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==} engines: {node: '>= 8.0.0'} - aggregate-error@5.0.0: - resolution: {integrity: sha512-gOsf2YwSlleG6IjRYG2A7k0HmBMEo6qVNk9Bp/EaLgAJT5ngH6PXbqa4ItvnEwCm/velL5jAnQgsHsWnjhGmvw==} - engines: {node: '>=18'} - ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} - ajv@8.12.0: - resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==} - - ansi-colors@4.1.1: - resolution: {integrity: sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==} - engines: {node: '>=6'} - ansi-colors@4.1.3: resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} engines: {node: '>=6'} @@ -4477,54 +3876,14 @@ packages: argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - argv-formatter@1.0.0: - resolution: {integrity: sha512-F2+Hkm9xFaRg+GkaNnbwXNDV5O6pnCFEmqyhvfC/Ic5LbgOWjJh3L+mN/s91rxVL3znE7DYVpW0GJFT+4YBgWw==} - aria-hidden@1.2.4: resolution: {integrity: sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==} engines: {node: '>=10'} - array-buffer-byte-length@1.0.0: - resolution: {integrity: sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==} - - array-flatten@1.1.1: - resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} - - array-ify@1.0.0: - resolution: {integrity: sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==} - - array-includes@3.1.7: - resolution: {integrity: sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==} - engines: {node: '>= 0.4'} - array-union@2.1.0: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} engines: {node: '>=8'} - array.prototype.findlastindex@1.2.3: - resolution: {integrity: sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA==} - engines: {node: '>= 0.4'} - - array.prototype.flat@1.3.2: - resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==} - engines: {node: '>= 0.4'} - - array.prototype.flatmap@1.3.2: - resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==} - engines: {node: '>= 0.4'} - - arraybuffer.prototype.slice@1.0.2: - resolution: {integrity: sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==} - engines: {node: '>= 0.4'} - - assertion-error@2.0.1: - resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} - engines: {node: '>=12'} - - ast-types@0.13.4: - resolution: {integrity: sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==} - engines: {node: '>=4'} - ast-types@0.14.2: resolution: {integrity: sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA==} engines: {node: '>=4'} @@ -4533,12 +3892,6 @@ packages: resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==} engines: {node: '>=4'} - async-mutex@0.5.0: - resolution: {integrity: sha512-1A94B18jkJ3DYq284ohPxoXbfTA5HsQ7/Mf4DEhcyLx3Bz27Rh59iScbB6EPiP+B+joue6YCxcMXSbFC1tZKwA==} - - async@2.6.4: - resolution: {integrity: sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==} - asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} @@ -4546,10 +3899,6 @@ packages: resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} engines: {node: '>=8.0.0'} - available-typed-arrays@1.0.5: - resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==} - engines: {node: '>= 0.4'} - axios@1.6.8: resolution: {integrity: sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==} @@ -4593,29 +3942,15 @@ packages: peerDependencies: '@babel/core': ^7.11.0 - backo2@1.0.2: - resolution: {integrity: sha512-zj6Z6M7Eq+PBZ7PQxl5NT665MvJdAkzp0f60nAJ+sLaSCBPMwVak5ZegFbgVCzFcCJTKFoMizvM5Ld7+JrRJHA==} - balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} base-x@3.0.9: resolution: {integrity: sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==} - base64-arraybuffer@0.1.5: - resolution: {integrity: sha512-437oANT9tP582zZMwSvZGy2nmSeAb8DW2me3y+Uv1Wp2Rulr8Mqlyrv3E7MLxmsiaPSMMDmiDVzgE+e8zlMx9g==} - engines: {node: '>= 0.6.0'} - base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - basic-ftp@5.0.5: - resolution: {integrity: sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==} - engines: {node: '>=10.0.0'} - - before-after-hook@3.0.2: - resolution: {integrity: sha512-Nik3Sc0ncrMK4UUdXQmAnRtzmNQTAAXmXIopizwZ1W1t8QmfJj+zL4OA2I7XPTPW5z5TDqv4hRo/JzouDJnX3A==} - better-path-resolve@1.0.0: resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} engines: {node: '>=4'} @@ -4637,16 +3972,9 @@ packages: bn.js@5.2.1: resolution: {integrity: sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==} - body-parser@1.20.2: - resolution: {integrity: sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==} - engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} - borsh@0.7.0: resolution: {integrity: sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA==} - bottleneck@2.19.5: - resolution: {integrity: sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==} - brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} @@ -4657,12 +3985,6 @@ packages: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} - brotli-wasm@1.3.1: - resolution: {integrity: sha512-Vp+v3QXddvy39Ycbmvd3/Y1kUvKhwtnprzeABcKWN4jmyg6W3W5MhGPCfXBMHeSQnizgpV59iWmkSRp7ykOnDQ==} - - browser-stdout@1.3.1: - resolution: {integrity: sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==} - browserslist-to-esbuild@2.1.1: resolution: {integrity: sha512-KN+mty6C3e9AN8Z5dI1xeN15ExcRNeISoC3g7V0Kax/MMF9MSoYA2G7lkTTcVUFntiEjkpI0HNgqJC1NjdyNUw==} engines: {node: '>=18'} @@ -4691,28 +4013,16 @@ packages: resolution: {integrity: sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==} engines: {node: '>=6.14.2'} - builtin-modules@3.3.0: - resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} - engines: {node: '>=6'} - bundle-require@5.0.0: resolution: {integrity: sha512-GuziW3fSSmopcx4KRymQEJVbZUfqlCqcq7dvs6TYwKRZiegK/2buMxQTPs6MGlNv50wms1699qYO54R8XfRX4w==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} peerDependencies: esbuild: '>=0.18' - bytes@3.1.2: - resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} - engines: {node: '>= 0.8'} - cac@6.7.14: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} - cacheable-lookup@6.1.0: - resolution: {integrity: sha512-KJ/Dmo1lDDhmW2XDPMo+9oiy/CeqosPguPCrgcVzKyZrL6pM1gU2GmPY/xo6OQPTUaA/c0kwHuywB4E6nmT9ww==} - engines: {node: '>=10.6.0'} - call-bind@1.0.5: resolution: {integrity: sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==} @@ -4731,15 +4041,6 @@ packages: caniuse-lite@1.0.30001641: resolution: {integrity: sha512-Phv5thgl67bHYo1TtMY/MurjkHhV4EDaCosezRXgZ8jzA/Ub+wjxAvbGvjoFENStinwi5kCyOYV3mi5tOGykwA==} - chai-as-promised@8.0.0: - resolution: {integrity: sha512-sMsGXTrS3FunP/wbqh/KxM8Kj/aLPXQGkNtvE5wPfSToq8wkkvBpTZo1LIiEVmC4BwkKpag+l5h/20lBMk6nUg==} - peerDependencies: - chai: '>= 2.1.2 < 6' - - chai@5.1.1: - resolution: {integrity: sha512-pT1ZgP8rPNqUgieVaEY+ryQr6Q4HXNg8Ei9UnLUrjN4IA7dvQC5JB+/kxVcPNDHyBcc/26CXPkbNzq3qwrOEKA==} - engines: {node: '>=12'} - chalk@2.4.2: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} engines: {node: '>=4'} @@ -4767,18 +4068,10 @@ packages: chardet@0.7.0: resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} - check-error@2.1.1: - resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} - engines: {node: '>= 16'} - check-more-types@2.24.0: resolution: {integrity: sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA==} engines: {node: '>= 0.8.0'} - chokidar@3.5.3: - resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} - engines: {node: '>= 8.10.0'} - chokidar@3.6.0: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} @@ -4797,23 +4090,10 @@ packages: classnames@2.3.2: resolution: {integrity: sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==} - clean-stack@5.2.0: - resolution: {integrity: sha512-TyUIUJgdFnCISzG5zu3291TAsE77ddchd0bepon1VVQrKLGKFED4iXFEDQ24mIPdPBbyE16PK3F8MYE1CmcBEQ==} - engines: {node: '>=14.16'} - - cli-highlight@2.1.11: - resolution: {integrity: sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==} - engines: {node: '>=8.0.0', npm: '>=5.0.0'} - hasBin: true - cli-spinners@2.9.2: resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} engines: {node: '>=6'} - cli-table3@0.6.3: - resolution: {integrity: sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==} - engines: {node: 10.* || >= 12.*} - cli-width@4.1.0: resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} engines: {node: '>= 12'} @@ -4821,9 +4101,6 @@ packages: client-only@0.0.1: resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} - cliui@7.0.4: - resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} - cliui@8.0.1: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} @@ -4874,125 +4151,29 @@ packages: resolution: {integrity: sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==} engines: {node: '>= 6'} - commitlint@19.3.0: - resolution: {integrity: sha512-B8eUVQCjz+1ZAjR3LC3+vzKg7c4/qN4QhSxkjp0u0v7Pi79t9CsnGAluvveKmFh56e885zgToPL5ax+l8BHTPg==} - engines: {node: '>=v18'} - hasBin: true - - common-tags@1.8.2: - resolution: {integrity: sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==} - engines: {node: '>=4.0.0'} - commondir@1.0.1: resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} - compare-func@2.0.0: - resolution: {integrity: sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==} - concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - config-chain@1.1.13: - resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==} - - connect@3.7.0: - resolution: {integrity: sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==} - engines: {node: '>= 0.10.0'} - consola@3.2.3: resolution: {integrity: sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==} engines: {node: ^14.18.0 || >=16.10.0} - content-disposition@0.5.4: - resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} - engines: {node: '>= 0.6'} - - content-type@1.0.5: - resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} - engines: {node: '>= 0.6'} - - conventional-changelog-angular@7.0.0: - resolution: {integrity: sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ==} - engines: {node: '>=16'} - - conventional-changelog-angular@8.0.0: - resolution: {integrity: sha512-CLf+zr6St0wIxos4bmaKHRXWAcsCXrJU6F4VdNDrGRK3B8LDLKoX3zuMV5GhtbGkVR/LohZ6MT6im43vZLSjmA==} - engines: {node: '>=18'} - - conventional-changelog-conventionalcommits@8.0.0: - resolution: {integrity: sha512-eOvlTO6OcySPyyyk8pKz2dP4jjElYunj9hn9/s0OB+gapTO8zwS9UQWrZ1pmF2hFs3vw1xhonOLGcGjy/zgsuA==} - engines: {node: '>=18'} - - conventional-changelog-writer@8.0.0: - resolution: {integrity: sha512-TQcoYGRatlAnT2qEWDON/XSfnVG38JzA7E0wcGScu7RElQBkg9WWgZd1peCWFcWDh1xfb2CfsrcvOn1bbSzztA==} - engines: {node: '>=18'} - hasBin: true - - conventional-commits-filter@5.0.0: - resolution: {integrity: sha512-tQMagCOC59EVgNZcC5zl7XqO30Wki9i9J3acbUvkaosCT6JX3EeFwJD7Qqp4MCikRnzS18WXV3BLIQ66ytu6+Q==} - engines: {node: '>=18'} - - conventional-commits-parser@5.0.0: - resolution: {integrity: sha512-ZPMl0ZJbw74iS9LuX9YIAiW8pfM5p3yh2o/NbXHbkFuZzY5jvdi5jFycEOkmBW5H5I7nA+D6f3UcsCLP2vvSEA==} - engines: {node: '>=16'} - hasBin: true - - conventional-commits-parser@6.0.0: - resolution: {integrity: sha512-TbsINLp48XeMXR8EvGjTnKGsZqBemisPoyWESlpRyR8lif0lcwzqz+NMtYSj1ooF/WYjSuu7wX0CtdeeMEQAmA==} - engines: {node: '>=18'} - hasBin: true - - convert-hrtime@5.0.0: - resolution: {integrity: sha512-lOETlkIeYSJWcbbcvjRKGxVMXJR+8+OQb/mTPbA4ObPMytYIsUbuOE0Jzy60hjARYszq1id0j8KgVhC+WGZVTg==} - engines: {node: '>=12'} - convert-source-map@1.9.0: resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - cookie-signature@1.0.6: - resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} - - cookie@0.6.0: - resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} - engines: {node: '>= 0.6'} - core-js-compat@3.37.1: resolution: {integrity: sha512-9TNiImhKvQqSUkOvk/mMRZzOANTiEVC7WaBNhHcKM7x+/5E1l5NvsysR19zuDQScE8k+kfQXWRN3AtS/eOSHpg==} - core-util-is@1.0.3: - resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} - - cors-gate@1.1.3: - resolution: {integrity: sha512-RFqvbbpj02lqKDhqasBEkgzmT3RseCH3DKy5sT2W9S1mhctABKQP3ktKcnKN0h8t4pJ2SneI3hPl3TGNi/VmZA==} - - cors@2.8.5: - resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} - engines: {node: '>= 0.10'} - - cosmiconfig-typescript-loader@5.0.0: - resolution: {integrity: sha512-+8cK7jRAReYkMwMiG+bxhcNKiHJDM6bR9FD/nGBXOWdMLuYawjF5cGrtLilJ+LGd3ZjCXnJjR5DkfWPoIVlqJA==} - engines: {node: '>=v16'} - peerDependencies: - '@types/node': '*' - cosmiconfig: '>=8.2' - typescript: '>=4' - cosmiconfig@7.1.0: resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==} engines: {node: '>=10'} - cosmiconfig@9.0.0: - resolution: {integrity: sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==} - engines: {node: '>=14'} - peerDependencies: - typescript: '>=4.9.5' - peerDependenciesMeta: - typescript: - optional: true - create-jest-runner@0.11.2: resolution: {integrity: sha512-6lwspphs4M1PLKV9baBNxHQtWVBPZuDU8kAP4MyrVWa6aEpEcpi2HZeeA6WncwaqgsGNXpP0N2STS7XNM/nHKQ==} hasBin: true @@ -5012,14 +4193,6 @@ packages: create-require@1.1.1: resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} - cross-env@7.0.3: - resolution: {integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==} - engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'} - hasBin: true - - cross-fetch@3.1.8: - resolution: {integrity: sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==} - cross-inspect@1.0.0: resolution: {integrity: sha512-4PFfn4b5ZN6FMNGSZlyb7wUhuN8wvj8t/VQHZdM4JsDcruGJ8L2kf9zao98QIrBPFCpdk27qst/AGTl7pL3ypQ==} engines: {node: '>=16.0.0'} @@ -5031,10 +4204,6 @@ packages: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} engines: {node: '>= 8'} - crypto-random-string@4.0.0: - resolution: {integrity: sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==} - engines: {node: '>=12'} - cssstyle@3.0.0: resolution: {integrity: sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg==} engines: {node: '>=14'} @@ -5046,14 +4215,6 @@ packages: resolution: {integrity: sha512-YGZxdTTL9lmLkCUTpg4j0zQ7IhRB5ZmqNBbGCl3Tg6MP/d5/6sY7L5mmTjzbc6JKgVZYiqTQTNhPFsbXNGlRaA==} engines: {node: '>=0.8'} - dargs@8.1.0: - resolution: {integrity: sha512-wAV9QHOsNbwnWdNW2FYvE1P56wtgSbM+3SZcdGiWQILwVjACCXDCI3Ai8QlCjMDB8YK5zySiXZYBiwGmNY3lnw==} - engines: {node: '>=12'} - - data-uri-to-buffer@6.0.2: - resolution: {integrity: sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==} - engines: {node: '>= 14'} - data-urls@4.0.0: resolution: {integrity: sha512-/mMTei/JXPqvFqQtfyTowxmJVwr2PVAeCcDxyFf6LhoOu/09TX2OX3kb2wzi4DMXcfj4OItwDOnhl5oziPnT6g==} engines: {node: '>=14'} @@ -5067,22 +4228,6 @@ packages: dateformat@4.6.3: resolution: {integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==} - debug@2.6.9: - resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - debug@3.2.7: - resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - debug@4.3.4: resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} engines: {node: '>=6.0'} @@ -5101,10 +4246,6 @@ packages: supports-color: optional: true - decamelize@4.0.0: - resolution: {integrity: sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==} - engines: {node: '>=10'} - decimal.js@10.4.3: resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==} @@ -5116,14 +4257,6 @@ packages: babel-plugin-macros: optional: true - deep-eql@5.0.1: - resolution: {integrity: sha512-nwQCf6ne2gez3o1MxWifqkciwt0zhl0LO1/UwVu4uMBuPmflWM4oQ70XMqHqnBJA+nhzncaqL9HVL6KkHJ28lw==} - engines: {node: '>=6'} - - deep-extend@0.6.0: - resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} - engines: {node: '>=4.0.0'} - deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} @@ -5135,14 +4268,6 @@ packages: resolution: {integrity: sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==} engines: {node: '>= 0.4'} - define-properties@1.2.0: - resolution: {integrity: sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==} - engines: {node: '>= 0.4'} - - degenerator@5.0.1: - resolution: {integrity: sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==} - engines: {node: '>= 14'} - delay@5.0.0: resolution: {integrity: sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==} engines: {node: '>=10'} @@ -5151,18 +4276,6 @@ packages: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} - depd@2.0.0: - resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} - engines: {node: '>= 0.8'} - - destroy@1.2.0: - resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} - engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} - - destroyable-server@1.0.2: - resolution: {integrity: sha512-Ln7ZKRq+7kr/3e4FCI8+jAjRbqbdaET8/ZBoUVvn+sDSAD7zDZA5mykkPRcrjBcaGy+LOM4ntMlIp1NMj1kMxw==} - engines: {node: '>=12.0.0'} - detect-indent@6.1.0: resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} engines: {node: '>=8'} @@ -5190,22 +4303,10 @@ packages: resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} engines: {node: '>=0.3.1'} - diff@5.0.0: - resolution: {integrity: sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==} - engines: {node: '>=0.3.1'} - - diff@5.2.0: - resolution: {integrity: sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==} - engines: {node: '>=0.3.1'} - dir-glob@3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} - doctrine@2.1.0: - resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} - engines: {node: '>=0.10.0'} - doctrine@3.0.0: resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} engines: {node: '>=6.0.0'} @@ -5215,10 +4316,6 @@ packages: engines: {node: '>=12'} deprecated: Use your platform's native DOMException instead - dot-prop@5.3.0: - resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==} - engines: {node: '>=8'} - dot-prop@6.0.1: resolution: {integrity: sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==} engines: {node: '>=10'} @@ -5235,21 +4332,12 @@ packages: resolution: {integrity: sha512-20TuZZHCEZ2O71q9/+8BwKwZ0QtD9D8ObhrihJPr+vLLYlSuAU3/zL4cSlgbfeoGHTjCSJBa7NGcrF9/Bx/WJQ==} engines: {node: '>=4'} - duplexer2@0.1.4: - resolution: {integrity: sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==} - duplexer@0.1.2: resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} - duplexify@3.7.1: - resolution: {integrity: sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==} - eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - ee-first@1.1.1: - resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - electron-to-chromium@1.4.827: resolution: {integrity: sha512-VY+J0e4SFcNfQy19MEoMdaIcZLmDCprqvBtkii1WTCTQHpRvf5N8+3kTYCgL/PcntvwQvmMJWTuDPsq+IlhWKQ==} @@ -5267,16 +4355,9 @@ packages: emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - emojilib@2.4.0: - resolution: {integrity: sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw==} - emphasize@5.0.0: resolution: {integrity: sha512-wRMiBsXijTTIOcXAhNzrMEwhSo246B1Dw8Qtx1QThNNeqN4edg85YvREhhZClwk23dQ3Kz1IM+TsmZ2hVVLeoQ==} - encodeurl@1.0.2: - resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} - engines: {node: '>= 0.8'} - end-of-stream@1.4.4: resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} @@ -5288,32 +4369,9 @@ packages: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} - env-ci@11.0.0: - resolution: {integrity: sha512-apikxMgkipkgTvMdRT9MNqWx5VLOci79F4VBd7Op/7OPjjoanjdAvn6fglMCCEf/1bAh8eOiuEVCUs4V3qP3nQ==} - engines: {node: ^18.17 || >=20.6.1} - - env-paths@2.2.1: - resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} - engines: {node: '>=6'} - error-ex@1.3.2: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} - es-abstract@1.22.3: - resolution: {integrity: sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==} - engines: {node: '>= 0.4'} - - es-set-tostringtag@2.0.1: - resolution: {integrity: sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==} - engines: {node: '>= 0.4'} - - es-shim-unscopables@1.0.0: - resolution: {integrity: sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==} - - es-to-primitive@1.2.1: - resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} - engines: {node: '>= 0.4'} - es6-promise@4.2.8: resolution: {integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==} @@ -5338,9 +4396,6 @@ packages: resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} engines: {node: '>=6'} - escape-html@1.0.3: - resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} - escape-string-regexp@1.0.5: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} engines: {node: '>=0.8.0'} @@ -5353,60 +4408,11 @@ packages: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} - escape-string-regexp@5.0.0: - resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} - engines: {node: '>=12'} - - escodegen@2.1.0: - resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==} - engines: {node: '>=6.0'} - hasBin: true - - eslint-config-prettier@9.1.0: - resolution: {integrity: sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==} - hasBin: true - peerDependencies: - eslint: '>=7.0.0' - eslint-config-turbo@2.0.9: resolution: {integrity: sha512-FoIMElI8md/dR5DxjB5Om52KJfi7Qf7RInXeE+PGU6lN388rumppwyqEJsZ7vnR5GhGa9cLPt0vNZwEK9iXtKg==} peerDependencies: eslint: '>6.6.0' - eslint-import-resolver-node@0.3.9: - resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} - - eslint-module-utils@2.8.0: - resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: '*' - eslint-import-resolver-node: '*' - eslint-import-resolver-typescript: '*' - eslint-import-resolver-webpack: '*' - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - eslint: - optional: true - eslint-import-resolver-node: - optional: true - eslint-import-resolver-typescript: - optional: true - eslint-import-resolver-webpack: - optional: true - - eslint-plugin-import@2.29.0: - resolution: {integrity: sha512-QPOO5NO6Odv5lpoTkddtutccQjysJuFxoPS7fAHO+9m9udNHvTCPSAMW9zGAYj8lAIdr40I8yPCdUYrncXtrwg==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - eslint-plugin-jest@27.9.0: resolution: {integrity: sha512-QIT7FH7fNmd9n4se7FFKHbsLKGQiw885Ds6Y/sxKgCZ6natwCsXdgPOADnYVxN2QrRweF0FZWbJ6S7Rsn7llug==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -5420,26 +4426,6 @@ packages: jest: optional: true - eslint-plugin-mocha@10.4.3: - resolution: {integrity: sha512-emc4TVjq5Ht0/upR+psftuz6IBG5q279p+1dSRDeHf+NS9aaerBi3lXKo1SEzwC29hFIW21gO89CEWSvRsi8IQ==} - engines: {node: '>=14.0.0'} - peerDependencies: - eslint: '>=7.0.0' - - eslint-plugin-prettier@5.2.1: - resolution: {integrity: sha512-gH3iR3g4JfF+yYPaJYkN7jEl9QbweL/YfkoRlNnuIEHEz1vHVlCmWOS+eGGiRuzHQXdJFCOTxRgvju9b8VUmrw==} - engines: {node: ^14.18.0 || >=16.0.0} - peerDependencies: - '@types/eslint': '>=8.0.0' - eslint: '>=8.0.0' - eslint-config-prettier: '*' - prettier: '>=3.0.0' - peerDependenciesMeta: - '@types/eslint': - optional: true - eslint-config-prettier: - optional: true - eslint-plugin-react-hooks@4.6.2: resolution: {integrity: sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==} engines: {node: '>=10'} @@ -5481,20 +4467,10 @@ packages: resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - eslint-utils@3.0.0: - resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} - engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} - peerDependencies: - eslint: '>=5' - eslint-visitor-keys@1.3.0: resolution: {integrity: sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==} engines: {node: '>=4'} - eslint-visitor-keys@2.1.0: - resolution: {integrity: sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==} - engines: {node: '>=10'} - eslint-visitor-keys@3.4.3: resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -5504,10 +4480,6 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} hasBin: true - esm@3.2.25: - resolution: {integrity: sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==} - engines: {node: '>=6'} - espree@6.2.1: resolution: {integrity: sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==} engines: {node: '>=6.0.0'} @@ -5537,20 +4509,10 @@ packages: resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} engines: {node: '>=4.0'} - estree-walker@0.6.1: - resolution: {integrity: sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==} - - estree-walker@2.0.2: - resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} - esutils@2.0.3: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} - etag@1.8.1: - resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} - engines: {node: '>= 0.6'} - event-stream@3.3.4: resolution: {integrity: sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g==} @@ -5558,9 +4520,6 @@ packages: resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} engines: {node: '>=6'} - eventemitter3@3.1.2: - resolution: {integrity: sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==} - eventemitter3@5.0.1: resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} @@ -5572,14 +4531,6 @@ packages: resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} engines: {node: '>=10'} - execa@8.0.1: - resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} - engines: {node: '>=16.17'} - - execa@9.1.0: - resolution: {integrity: sha512-lSgHc4Elo2m6bUDhc3Hl/VxvUDJdQWI40RZ4KMY9bKRc+hgMOT7II/JjbNDhI8VnMtrCb7U/fhpJIkLORZozWw==} - engines: {node: '>=18'} - exit@0.1.2: resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==} engines: {node: '>= 0.8.0'} @@ -5600,10 +4551,6 @@ packages: resolution: {integrity: sha512-8hBXtSCQuJnZFOUAAiih2GYDRg93h2Ui6XL9BPu6QgSvlSozTLCtCyDsNPq7aL0D43H5uYHwqXiVfWW6MIlJhw==} engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} - express@4.19.2: - resolution: {integrity: sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==} - engines: {node: '>= 0.10.0'} - extendable-error@0.1.7: resolution: {integrity: sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==} @@ -5621,16 +4568,10 @@ packages: fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - fast-diff@1.3.0: - resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} - fast-glob@3.3.2: resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} engines: {node: '>=8.6.0'} - fast-json-patch@3.1.1: - resolution: {integrity: sha512-vf6IHUX2SBcA+5/+4883dsIjpBTqmfBjmYiWK1savxQmFk4JfBMLa7ynTYOs1Rolp/T1betJxHiGD3g1Mn8lUQ==} - fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} @@ -5659,14 +4600,6 @@ packages: fb-watchman@2.0.2: resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} - figures@2.0.0: - resolution: {integrity: sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==} - engines: {node: '>=4'} - - figures@6.1.0: - resolution: {integrity: sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==} - engines: {node: '>=18'} - file-entry-cache@6.0.1: resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} engines: {node: ^10.12.0 || >=12.0.0} @@ -5678,14 +4611,6 @@ packages: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} - finalhandler@1.1.2: - resolution: {integrity: sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==} - engines: {node: '>= 0.8'} - - finalhandler@1.2.0: - resolution: {integrity: sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==} - engines: {node: '>= 0.8'} - find-cache-dir@2.1.0: resolution: {integrity: sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==} engines: {node: '>=6'} @@ -5702,14 +4627,6 @@ packages: resolution: {integrity: sha512-/U4CYp1214Xrp3u3Fqr9yNynUrr5Le4y0SsJh2lMDDSbpwYSz3M2SMWQC+wqcx79cN8PQtHQIL8KnuY9M66fdg==} hasBin: true - find-up-simple@1.0.0: - resolution: {integrity: sha512-q7Us7kcjj2VMePAa02hDAF6d+MzsdsAWEwYyOpwUtlerRBkOEPBCRZrAV4XfcSN8fHAgaD0hP7miwoay6DCprw==} - engines: {node: '>=18'} - - find-up@2.1.0: - resolution: {integrity: sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==} - engines: {node: '>=4'} - find-up@3.0.0: resolution: {integrity: sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==} engines: {node: '>=6'} @@ -5722,14 +4639,6 @@ packages: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} - find-up@7.0.0: - resolution: {integrity: sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g==} - engines: {node: '>=18'} - - find-versions@6.0.0: - resolution: {integrity: sha512-2kCCtc+JvcZ86IGAz3Z2Y0A1baIz9fL31pH/0S1IqZr9Iwnjq8izfPtrCyQKO6TLMPELLsQMre7VDqeIKCsHkA==} - engines: {node: '>=18'} - find-yarn-workspace-root2@1.2.16: resolution: {integrity: sha512-hr6hb1w8ePMpPVUK39S4RlwJzi+xPLuVuG8XlwXU3KD5Yn3qgBWVfy3AzNlDhWvE1EORCE65/Qm26rFQt3VLVA==} @@ -5737,10 +4646,6 @@ packages: resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==} engines: {node: ^10.12.0 || >=12.0.0} - flat@5.0.2: - resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} - hasBin: true - flatted@3.2.7: resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} @@ -5757,9 +4662,6 @@ packages: debug: optional: true - for-each@0.3.3: - resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} - foreground-child@3.1.1: resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==} engines: {node: '>=14'} @@ -5772,17 +4674,6 @@ packages: resolution: {integrity: sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==} engines: {node: '>=0.4.x'} - forwarded@0.2.0: - resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} - engines: {node: '>= 0.6'} - - fresh@0.5.2: - resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} - engines: {node: '>= 0.6'} - - from2@2.3.0: - resolution: {integrity: sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==} - from@0.1.7: resolution: {integrity: sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==} @@ -5790,10 +4681,6 @@ packages: resolution: {integrity: sha512-cR/vflFyPZtrN6b38ZyWxpWdhlXrzZEBawlpBQMq7033xVY7/kg0GDMBK5jg8lDYQckdJ5x/YC88lM3C7VMsLg==} engines: {node: '>=0.10.0'} - fs-extra@11.2.0: - resolution: {integrity: sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==} - engines: {node: '>=14.14'} - fs-extra@7.0.1: resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} engines: {node: '>=6 <7 || >=8'} @@ -5813,17 +4700,6 @@ packages: function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - function-timeout@1.0.1: - resolution: {integrity: sha512-6yPMImFFuaMPNaTMTBuolA8EanHJWF5Vju0NHpObRURT105J6x1Mf2a7J4P7Sqk2xDxv24N5L0RatEhTBhNmdA==} - engines: {node: '>=18'} - - function.prototype.name@1.1.6: - resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} - engines: {node: '>= 0.4'} - - functions-have-names@1.2.3: - resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} - gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} @@ -5832,9 +4708,6 @@ packages: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} - get-func-name@2.0.2: - resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} - get-intrinsic@1.2.2: resolution: {integrity: sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==} @@ -5850,37 +4723,9 @@ packages: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} - get-stream@7.0.1: - resolution: {integrity: sha512-3M8C1EOFN6r8AMUhwUAACIoXZJEOufDU5+0gFFN5uNs6XYOralD2Pqkl7m046va6x77FwposWXbAhPPIOus7mQ==} - engines: {node: '>=16'} - - get-stream@8.0.1: - resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} - engines: {node: '>=16'} - - get-stream@9.0.1: - resolution: {integrity: sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==} - engines: {node: '>=18'} - - get-symbol-description@1.0.0: - resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==} - engines: {node: '>= 0.4'} - get-tsconfig@4.7.5: resolution: {integrity: sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw==} - get-uri@6.0.3: - resolution: {integrity: sha512-BzUrJBS9EcUb4cFol8r4W3v1cPsSyajLSthNkz5BxbpDcHN5tIrM10E2eNvfnvBn3DaT3DUgx0OpsBKkaOpanw==} - engines: {node: '>= 14'} - - git-log-parser@1.2.0: - resolution: {integrity: sha512-rnCVNfkTL8tdNryFuaY0fYiBWEBcgF748O6ZI61rslBvr2o7U65c2/6npCRqH40vuAhtgtDiqLTJjBVdrejCzA==} - - git-raw-commits@4.0.0: - resolution: {integrity: sha512-ICsMM1Wk8xSGMowkOmPrzo2Fgmfo4bMHLNX6ytHjajRJUqvHOw/TFapQ+QG75c3X/tTDDhOSRPGC52dDbNM8FQ==} - engines: {node: '>=16'} - hasBin: true - glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -5894,24 +4739,10 @@ packages: engines: {node: '>=16 || 14 >=14.18'} hasBin: true - glob@11.0.0: - resolution: {integrity: sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g==} - engines: {node: 20 || >=22} - hasBin: true - glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} deprecated: Glob versions prior to v9 are no longer supported - glob@8.1.0: - resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} - engines: {node: '>=12'} - deprecated: Glob versions prior to v9 are no longer supported - - global-directory@4.0.1: - resolution: {integrity: sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==} - engines: {node: '>=18'} - global-modules@0.2.3: resolution: {integrity: sha512-JeXuCbvYzYXcwE6acL9V2bAOeSIGl4dD+iwLY9iUx2VBJJ80R18HCn+JCwHM9Oegdfya3lEkGCdaRkSyc10hDA==} engines: {node: '>=0.10.0'} @@ -5932,63 +4763,23 @@ packages: resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} engines: {node: '>=8'} - globalthis@1.0.3: - resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==} - engines: {node: '>= 0.4'} - globby@11.1.0: resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} engines: {node: '>=10'} - globby@14.0.1: - resolution: {integrity: sha512-jOMLD2Z7MAhyG8aJpNOpmziMOP4rPLcc95oQPKXBazW82z+CEgPFBQvEpRUa1KeIMUJo4Wsm+q6uzO/Q/4BksQ==} - engines: {node: '>=18'} - gopd@1.0.1: resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} - graceful-fs@4.2.10: - resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==} - graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} - graphql-http@1.22.0: - resolution: {integrity: sha512-9RBUlGJWBFqz9LwfpmAbjJL/8j/HCNkZwPBU5+Bfmwez+1Ay43DocMNQYpIWsWqH0Ftv6PTNAh2aRnnMCBJgLw==} - engines: {node: '>=12'} - peerDependencies: - graphql: '>=0.11 <=16' - - graphql-subscriptions@1.2.1: - resolution: {integrity: sha512-95yD/tKi24q8xYa7Q9rhQN16AYj5wPbrb8tmHGM3WRc9EBmWrG/0kkMl+tQG8wcEuE9ibR4zyOM31p5Sdr2v4g==} - peerDependencies: - graphql: ^0.10.5 || ^0.11.3 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 - - graphql-tag@2.12.6: - resolution: {integrity: sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg==} - engines: {node: '>=10'} - peerDependencies: - graphql: ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 - - graphql@15.8.0: - resolution: {integrity: sha512-5gghUc24tP9HRznNpV2+FIoq3xKkj5dTQqf4v0CpdPbFVwFkWoxOM+o+2OC9ZSvjEMTjfmG9QT+gcvggTwW1zw==} - engines: {node: '>= 10.x'} - graphql@16.9.0: resolution: {integrity: sha512-GGTKBX4SD7Wdb8mqeDLni2oaRGYQWjWHGKPQ24ZMnUtKfcsVoiv4uX8+LJr1K6U5VW2Lu1BwJnj7uiori0YtRw==} engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} - handlebars@4.7.7: - resolution: {integrity: sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==} - engines: {node: '>=0.4.7'} - hasBin: true - - has-bigints@1.0.2: - resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} - has-flag@3.0.0: resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} engines: {node: '>=4'} @@ -6008,28 +4799,13 @@ packages: resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} engines: {node: '>= 0.4'} - has-tostringtag@1.0.0: - resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==} - engines: {node: '>= 0.4'} - - has@1.0.3: - resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} - engines: {node: '>= 0.4.0'} - hasown@2.0.0: resolution: {integrity: sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==} engines: {node: '>= 0.4'} - he@1.2.0: - resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} - hasBin: true - help-me@5.0.0: resolution: {integrity: sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==} - highlight.js@10.7.3: - resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==} - highlight.js@11.0.1: resolution: {integrity: sha512-EqYpWyTF2s8nMfttfBA2yLKPNoZCO33pLS4MnbXQ4hECf1TKujCt1Kq7QAdrio7roL4+CqsfjqwYj4tYgq0pJQ==} engines: {node: '>=12.0.0'} @@ -6038,14 +4814,6 @@ packages: resolution: {integrity: sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==} engines: {node: '>=0.10.0'} - hook-std@3.0.0: - resolution: {integrity: sha512-jHRQzjSDzMtFy34AGj1DN+vq54WVuhSvKgrHf0OMiFQTwDD4L/qqofVEWjLOBMTn5+lCD3fPg32W9yOfnEJTTw==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - hosted-git-info@7.0.1: - resolution: {integrity: sha512-+K84LB1DYwMHoHSgaOY/Jfhw3ucPmSET5v98Ke/HdNSw4a0UktWzyW1mjhjpuxxTqOOsfWT/7iVshHmVZ4IpOA==} - engines: {node: ^16.14.0 || >=18.0.0} - html-encoding-sniffer@3.0.0: resolution: {integrity: sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==} engines: {node: '>=12'} @@ -6053,33 +4821,14 @@ packages: html-escaper@2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} - http-encoding@1.5.1: - resolution: {integrity: sha512-2m4JnG1Z5RX5pRMdccyp6rX1jVo4LO+ussQzWdwR4AmrWhtX0KP1NyslVAFAspQwMxt2P00CCWXIBKj7ILZLpQ==} - - http-errors@2.0.0: - resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} - engines: {node: '>= 0.8'} - http-proxy-agent@5.0.0: resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==} engines: {node: '>= 6'} - http-proxy-agent@7.0.0: - resolution: {integrity: sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==} - engines: {node: '>= 14'} - - http2-wrapper@2.2.1: - resolution: {integrity: sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==} - engines: {node: '>=10.19.0'} - https-proxy-agent@5.0.1: resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} engines: {node: '>= 6'} - https-proxy-agent@7.0.4: - resolution: {integrity: sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==} - engines: {node: '>= 14'} - human-id@1.0.2: resolution: {integrity: sha512-UNopramDEhHJD+VR+ehk8rOslwSfByxPIZyJRfV739NDhN5LF1fa1MqnzKm2lGTQRjNrjK19Q5fhkgIfjlVUKw==} @@ -6087,14 +4836,6 @@ packages: resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} engines: {node: '>=10.17.0'} - human-signals@5.0.0: - resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} - engines: {node: '>=16.17.0'} - - human-signals@7.0.0: - resolution: {integrity: sha512-74kytxOUSvNbjrT9KisAbaTZ/eJwD/LrbM/kh5j0IhPuJzwuA19dWvniFGwBzN9rVjg+O/e+F310PjObDXS+9Q==} - engines: {node: '>=18.18.0'} - humanize-ms@1.2.1: resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} @@ -6121,30 +4862,15 @@ packages: resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} engines: {node: '>=6'} - import-from-esm@1.3.4: - resolution: {integrity: sha512-7EyUlPFC0HOlBDpUFGfYstsU7XHxZJKAAMzCT8wZ0hMW7b+hG51LIKTDcsgtz8Pu6YC0HqRVbX+rVUtsGMUKvg==} - engines: {node: '>=16.20'} - import-local@3.1.0: resolution: {integrity: sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==} engines: {node: '>=8'} hasBin: true - import-meta-resolve@4.0.0: - resolution: {integrity: sha512-okYUR7ZQPH+efeuMJGlq4f8ubUgO50kByRPyt/Cy1Io4PSRsPjxME+YlVaCOx+NIToW7hCsZNFJyTPFFKepRSA==} - imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} - indent-string@5.0.0: - resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==} - engines: {node: '>=12'} - - index-to-position@0.1.2: - resolution: {integrity: sha512-MWDKS3AS1bGCHLBA2VLImJz42f7bJh8wQsTGCzI3j519/CASStoDONUBVz2I/VID0MpiX3SGSnbOD2xUalbE5g==} - engines: {node: '>=18'} - inflight@1.0.6: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. @@ -6155,61 +4881,19 @@ packages: ini@1.3.8: resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} - ini@4.1.1: - resolution: {integrity: sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - - internal-slot@1.0.5: - resolution: {integrity: sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==} - engines: {node: '>= 0.4'} - - into-stream@7.0.0: - resolution: {integrity: sha512-2dYz766i9HprMBasCMvHMuazJ7u4WzhJwo5kb3iPSiW/iRYV6uPari3zHoqZlnuaR7V1bEiNMxikhp37rdBXbw==} - engines: {node: '>=12'} - invariant@2.2.4: resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} - ip-address@9.0.5: - resolution: {integrity: sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==} - engines: {node: '>= 12'} - - ipaddr.js@1.9.1: - resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} - engines: {node: '>= 0.10'} - - is-array-buffer@3.0.2: - resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==} - is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} - is-bigint@1.0.4: - resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} - is-binary-path@2.1.0: resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} engines: {node: '>=8'} - is-boolean-object@1.1.2: - resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} - engines: {node: '>= 0.4'} - - is-builtin-module@3.2.1: - resolution: {integrity: sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==} - engines: {node: '>=6'} - - is-callable@1.2.7: - resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} - engines: {node: '>= 0.4'} - is-core-module@2.13.1: resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} - is-date-object@1.0.5: - resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} - engines: {node: '>= 0.4'} - is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} @@ -6226,17 +4910,6 @@ packages: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} - is-module@1.0.0: - resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==} - - is-negative-zero@2.0.2: - resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==} - engines: {node: '>= 0.4'} - - is-number-object@1.0.7: - resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} - engines: {node: '>= 0.4'} - is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} @@ -6249,14 +4922,6 @@ packages: resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} engines: {node: '>=8'} - is-plain-obj@2.1.0: - resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==} - engines: {node: '>=8'} - - is-plain-obj@4.1.0: - resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} - engines: {node: '>=12'} - is-plain-object@2.0.4: resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==} engines: {node: '>=0.10.0'} @@ -6264,62 +4929,17 @@ packages: is-potential-custom-element-name@1.0.1: resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} - is-reference@1.2.1: - resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==} - - is-regex@1.1.4: - resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} - engines: {node: '>= 0.4'} - - is-shared-array-buffer@1.0.2: - resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==} - is-stream@2.0.1: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} - is-stream@3.0.0: - resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - is-stream@4.0.1: - resolution: {integrity: sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==} - engines: {node: '>=18'} - - is-string@1.0.7: - resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} - engines: {node: '>= 0.4'} - is-subdir@1.2.0: resolution: {integrity: sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw==} engines: {node: '>=4'} - is-symbol@1.0.4: - resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} - engines: {node: '>= 0.4'} - - is-text-path@2.0.0: - resolution: {integrity: sha512-+oDTluR6WEjdXEJMnC2z6A4FRwFoYuvShVVEGsS7ewc0UTi2QtAKMDJuL4BDEVt+5T7MjFo12RP8ghOM75oKJw==} - engines: {node: '>=8'} - - is-typed-array@1.1.12: - resolution: {integrity: sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==} - engines: {node: '>= 0.4'} - is-typedarray@1.0.0: resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} - is-unicode-supported@0.1.0: - resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} - engines: {node: '>=10'} - - is-unicode-supported@2.0.0: - resolution: {integrity: sha512-FRdAyx5lusK1iHG0TWpVtk9+1i+GjrzRffhDg4ovQ7mcidMQ6mj+MhKPmvh7Xwyv5gIS06ns49CA7Sqg7lC22Q==} - engines: {node: '>=18'} - - is-weakref@1.0.2: - resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} - is-windows@0.2.0: resolution: {integrity: sha512-n67eJYmXbniZB7RF4I/FTjK1s6RPOCTxhYrVYLRaCt3lF0mpWZPKr3T2LSZAqyjQsxR2qMmGYXXzK0YWwcPM1Q==} engines: {node: '>=0.10.0'} @@ -6328,9 +4948,6 @@ packages: resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} engines: {node: '>=0.10.0'} - isarray@1.0.0: - resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} - isarray@2.0.5: resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} @@ -6346,10 +4963,6 @@ packages: peerDependencies: ws: '*' - issue-parser@7.0.0: - resolution: {integrity: sha512-jgAw78HO3gs9UrKqJNQvfDj9Ouy8Mhu40fbEJ8yXff4MW8+/Fcn9iFjyWUQ6SKbX8ipPk3X5A3AyfYHRu6uVLw==} - engines: {node: ^18.17 || >=20.6.1} - istanbul-lib-coverage@3.2.0: resolution: {integrity: sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==} engines: {node: '>=8'} @@ -6374,21 +4987,10 @@ packages: resolution: {integrity: sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==} engines: {node: '>=8'} - iterall@1.3.0: - resolution: {integrity: sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg==} - jackspeak@3.4.0: resolution: {integrity: sha512-JVYhQnN59LVPFCEcVa2C3CrEKYacvjRfqIQl+h8oi91aLYQVWRYbxjPcv1bUiUy/kLmQaANrYfNMCO3kuEDHfw==} engines: {node: '>=14'} - jackspeak@4.0.1: - resolution: {integrity: sha512-cub8rahkh0Q/bw1+GxP7aeSe29hHHn2V4m29nnDlvCdlgU+3UGxkZp7Z53jLUdpX3jdTO0nJZUDl3xvbWc2Xog==} - engines: {node: 20 || >=22} - - java-properties@1.0.2: - resolution: {integrity: sha512-qjdpeo2yKlYTH7nFdK0vbZWuTCesk4o63v5iVOlhMQPfuIZQfW/HI35SjfhA+4qpg36rnFSvUK5b1m+ckIblQQ==} - engines: {node: '>= 0.6.0'} - jayson@4.1.1: resolution: {integrity: sha512-5ZWm4Q/0DHPyeMfAsrwViwUS2DMVsQgWh8bEEIVTkfb3DzHZ2L3G5WUnF+AKmGjjM9r1uAv73SaqC1/U4RL45w==} engines: {node: '>=8'} @@ -6698,9 +5300,6 @@ packages: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} hasBin: true - jsbn@1.1.0: - resolution: {integrity: sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==} - jscodeshift@0.16.1: resolution: {integrity: sha512-oMQXySazy63awNBzMpXbbVv73u3irdxTeX2L5ueRyFRxi32qb9uzdZdOY5fTBYADBG19l5M/wnGknZSV1dzCdA==} hasBin: true @@ -6728,18 +5327,12 @@ packages: engines: {node: '>=4'} hasBin: true - json-parse-better-errors@1.0.2: - resolution: {integrity: sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==} - json-parse-even-better-errors@2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - json-schema-traverse@1.0.0: - resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} - json-schema@0.4.0: resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} @@ -6753,10 +5346,6 @@ packages: json-stringify-safe@5.0.1: resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} - json5@1.0.2: - resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} - hasBin: true - json5@2.2.3: resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} engines: {node: '>=6'} @@ -6768,9 +5357,6 @@ packages: jsonfile@4.0.0: resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} - jsonfile@6.1.0: - resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} - jsonify@0.0.1: resolution: {integrity: sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==} @@ -6778,9 +5364,6 @@ packages: resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==} engines: {'0': node >= 0.2.0} - just-extend@6.2.0: - resolution: {integrity: sha512-cYofQu2Xpom82S6qD778jBDpwvvy39s1l/hrYij2u9AMdQcGRpaBu6kY4mVhuno5kJVi1DAz4aiphA2WI1/OAw==} - kind-of@6.0.3: resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} engines: {node: '>=0.10.0'} @@ -6808,13 +5391,6 @@ packages: lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - linkify-it@5.0.0: - resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==} - - load-json-file@4.0.0: - resolution: {integrity: sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==} - engines: {node: '>=4'} - load-tsconfig@0.2.5: resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -6823,10 +5399,6 @@ packages: resolution: {integrity: sha512-OfCBkGEw4nN6JLtgRidPX6QxjBQGQf72q3si2uvqyFEMbycSFFHwAZeXx6cJgFM9wmLrf9zBwCP3Ivqa+LLZPw==} engines: {node: '>=6'} - locate-path@2.0.0: - resolution: {integrity: sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==} - engines: {node: '>=4'} - locate-path@3.0.0: resolution: {integrity: sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==} engines: {node: '>=6'} @@ -6839,75 +5411,25 @@ packages: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} - locate-path@7.2.0: - resolution: {integrity: sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - lodash-es@4.17.21: - resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} - - lodash.camelcase@4.3.0: - resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} - - lodash.capitalize@4.2.1: - resolution: {integrity: sha512-kZzYOKspf8XVX5AvmQF94gQW0lejFVgb80G85bU4ZWzoJ6C03PQg3coYAUpSTpQWelrZELd3XWgHzw4Ck5kaIw==} - lodash.debounce@4.0.8: resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} - lodash.escaperegexp@4.1.2: - resolution: {integrity: sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==} - - lodash.get@4.4.2: - resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==} - - lodash.isplainobject@4.0.6: - resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} - - lodash.isstring@4.0.1: - resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==} - - lodash.kebabcase@4.1.1: - resolution: {integrity: sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==} - lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - lodash.mergewith@4.6.2: - resolution: {integrity: sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==} - - lodash.snakecase@4.1.1: - resolution: {integrity: sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==} - lodash.sortby@4.7.0: resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} lodash.startcase@4.4.0: resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==} - lodash.uniq@4.5.0: - resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==} - - lodash.uniqby@4.7.0: - resolution: {integrity: sha512-e/zcLx6CSbmaEgFHCA7BnoQKyCtKMxnuWrJygbwPs/AIn+IMKl66L8/s+wBUn5LRw2pZx3bUHibiV1b6aTWIww==} - - lodash.upperfirst@4.3.1: - resolution: {integrity: sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg==} - lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} - log-symbols@4.1.0: - resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} - engines: {node: '>=10'} - loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true - loupe@3.1.0: - resolution: {integrity: sha512-qKl+FrLXUhFuHUoDJG7f8P8gEMHq9NFS0c6ghXG1J0rldmZFQZoNVv/vyirE9qwCIhWZDsvEFd1sbFu3GvRQFg==} - lowlight@2.0.1: resolution: {integrity: sha512-HB2PZDjmI3NlcSukkKHTwhXIiVhKMq8NZVcIMo8qXUJundfbes8JpE3jtqW/InByhOVd4X0XitTTzgiNoavAzQ==} @@ -6915,10 +5437,6 @@ packages: resolution: {integrity: sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==} engines: {node: 14 || >=16.14} - lru-cache@11.0.0: - resolution: {integrity: sha512-Qv32eSV1RSCfhY3fpPE2GNZ8jgM9X7rdAfemLWqTUxwiyIC4jJ6Sy0fZ8H+oLWevO6i4/bizg7c8d8i6bxrzbA==} - engines: {node: 20 || >=22} - lru-cache@4.1.5: resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==} @@ -6929,19 +5447,6 @@ packages: resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} engines: {node: '>=10'} - lru-cache@7.18.3: - resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} - engines: {node: '>=12'} - - lunr@2.3.9: - resolution: {integrity: sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==} - - magic-string@0.25.9: - resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==} - - magic-string@0.30.10: - resolution: {integrity: sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==} - make-dir@2.1.0: resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==} engines: {node: '>=6'} @@ -6959,39 +5464,10 @@ packages: map-stream@0.1.0: resolution: {integrity: sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g==} - markdown-it@14.1.0: - resolution: {integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==} - hasBin: true - - marked-terminal@7.0.0: - resolution: {integrity: sha512-sNEx8nn9Ktcm6pL0TnRz8tnXq/mSS0Q1FRSwJOAqw4lAB4l49UeDf85Gm1n9RPFm5qurCPjwi1StAQT2XExhZw==} - engines: {node: '>=16.0.0'} - peerDependencies: - marked: '>=1 <13' - - marked@12.0.1: - resolution: {integrity: sha512-Y1/V2yafOcOdWQCX0XpAKXzDakPOpn6U0YLxTJs3cww6VxOzZV1BTOOYWLvH3gX38cq+iLwljHHTnMtlDfg01Q==} - engines: {node: '>= 18'} - hasBin: true - - mdurl@2.0.0: - resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} - - media-typer@0.3.0: - resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} - engines: {node: '>= 0.6'} - - meow@12.1.1: - resolution: {integrity: sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==} - engines: {node: '>=16.10'} - meow@13.2.0: resolution: {integrity: sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==} engines: {node: '>=18'} - merge-descriptors@1.0.1: - resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==} - merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} @@ -6999,10 +5475,6 @@ packages: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} - methods@1.1.2: - resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} - engines: {node: '>= 0.6'} - micromatch@4.0.7: resolution: {integrity: sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==} engines: {node: '>=8.6'} @@ -7015,39 +5487,13 @@ packages: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} - mime@1.6.0: - resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} - engines: {node: '>=4'} - hasBin: true - - mime@4.0.1: - resolution: {integrity: sha512-5lZ5tyrIfliMXzFtkYyekWbtRXObT9OWa8IwQ5uxTBDHucNNwniRqo0yInflj+iYi5CBa6qxadGzGarDfuEOxA==} - engines: {node: '>=16'} - hasBin: true - mimic-fn@2.1.0: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} - mimic-fn@4.0.0: - resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} - engines: {node: '>=12'} - - minimatch@10.0.1: - resolution: {integrity: sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==} - engines: {node: 20 || >=22} - minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} - minimatch@5.0.1: - resolution: {integrity: sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==} - engines: {node: '>=10'} - - minimatch@5.1.6: - resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} - engines: {node: '>=10'} - minimatch@9.0.5: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} @@ -7063,27 +5509,14 @@ packages: resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} hasBin: true - mocha@10.4.0: - resolution: {integrity: sha512-eqhGB8JKapEYcC4ytX/xrzKforgEc3j1pGlAXVy3eRwrtAy5/nIfT1SvgGzfN0XZZxeLq0aQWkOUAmqIJiv+bA==} - engines: {node: '>= 14.0.0'} - hasBin: true - mock-socket@9.3.1: resolution: {integrity: sha512-qxBgB7Qa2sEQgHFjj0dSigq7fX4k6Saisd5Nelwp2q8mlbAFh5dHV9JTTlF8viYJLSSWgMCZFUom8PJcMNBoJw==} engines: {node: '>= 8'} - mockttp@3.15.0: - resolution: {integrity: sha512-+LqA7ayl3KQv0FRMnvz/ot5dq+47NTntX4ASO822n+k4LaeaPZnfJW3wKedHe5MFmm8HXC9emn7+R+b1giNvjg==} - engines: {node: '>=14.14.0'} - hasBin: true - mri@1.2.0: resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} engines: {node: '>=4'} - ms@2.0.0: - resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} - ms@2.1.2: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} @@ -7102,43 +5535,19 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - native-duplexpair@1.0.0: - resolution: {integrity: sha512-E7QQoM+3jvNtlmyfqRZ0/U75VFgCls+fSkbml2MpgWkWyz3ox8Y58gNhfuziuQYGNNQAbFZJQck55LHCnCK6CA==} - natural-compare-lite@1.4.0: resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==} natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - negotiator@0.6.3: - resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} - engines: {node: '>= 0.6'} - neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} - nerf-dart@1.0.0: - resolution: {integrity: sha512-EZSPZB70jiVsivaBLYDCyntd5eH8NTSMOn3rB+HxwdmKThGELLdYv8qVIMWvZEFy9w8ZZpW9h9OB32l1rGtj7g==} - - netmask@2.0.2: - resolution: {integrity: sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==} - engines: {node: '>= 0.4.0'} - - nise@6.0.0: - resolution: {integrity: sha512-K8ePqo9BFvN31HXwEtTNGzgrPpmvgciDsFz8aztFjt4LqKO/JeFD8tBOeuDiCMXrIl/m1YvfH8auSpxfaD09wg==} - - node-abort-controller@3.0.1: - resolution: {integrity: sha512-/ujIVxthRs+7q6hsdjHMaj8hRG9NuWmwrz+JdRwZ14jdFoKSkm+vDsCbF9PLpnSqjaWQJuTmVtcWHNLr+vrOFw==} - node-dir@0.1.17: resolution: {integrity: sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg==} engines: {node: '>= 0.10.5'} - node-emoji@2.1.3: - resolution: {integrity: sha512-E2WEOVsgs7O16zsURJ/eH8BqhF029wGpEOnv7Urwdo2wmQanOACwJQh0devF9D9RhoZru0+9JXIS0dBXIAz+lA==} - engines: {node: '>=18'} - node-fetch@2.7.0: resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} engines: {node: 4.x || >=6.0.0} @@ -7148,10 +5557,6 @@ packages: encoding: optional: true - node-forge@1.3.1: - resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==} - engines: {node: '>= 6.13.0'} - node-gyp-build@4.6.0: resolution: {integrity: sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==} hasBin: true @@ -7162,103 +5567,14 @@ packages: node-releases@2.0.14: resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} - normalize-package-data@6.0.0: - resolution: {integrity: sha512-UL7ELRVxYBHBgYEtZCXjxuD5vPxnmvMGq0jp/dGPKKrN7tfsBh2IY7TlJ15WWwdjRWD3RJbnsygUurTK3xkPkg==} - engines: {node: ^16.14.0 || >=18.0.0} - normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} - normalize-url@8.0.0: - resolution: {integrity: sha512-uVFpKhj5MheNBJRTiMZ9pE/7hD1QTeEvugSJW/OmLzAp78PB5O6adfMNTvmfKhXBkvCzC+rqifWcVYpGFwTjnw==} - engines: {node: '>=14.16'} - npm-run-path@4.0.1: resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} engines: {node: '>=8'} - npm-run-path@5.3.0: - resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - npm@10.5.2: - resolution: {integrity: sha512-cHVG7QEJwJdZyOrK0dKX5uf3R5Fd0E8AcmSES1jLtO52UT1enUKZ96Onw/xwq4CbrTZEnDuu2Vf9kCQh/Sd12w==} - engines: {node: ^18.17.0 || >=20.5.0} - hasBin: true - bundledDependencies: - - '@isaacs/string-locale-compare' - - '@npmcli/arborist' - - '@npmcli/config' - - '@npmcli/fs' - - '@npmcli/map-workspaces' - - '@npmcli/package-json' - - '@npmcli/promise-spawn' - - '@npmcli/redact' - - '@npmcli/run-script' - - '@sigstore/tuf' - - abbrev - - archy - - cacache - - chalk - - ci-info - - cli-columns - - cli-table3 - - columnify - - fastest-levenshtein - - fs-minipass - - glob - - graceful-fs - - hosted-git-info - - ini - - init-package-json - - is-cidr - - json-parse-even-better-errors - - libnpmaccess - - libnpmdiff - - libnpmexec - - libnpmfund - - libnpmhook - - libnpmorg - - libnpmpack - - libnpmpublish - - libnpmsearch - - libnpmteam - - libnpmversion - - make-fetch-happen - - minimatch - - minipass - - minipass-pipeline - - ms - - node-gyp - - nopt - - normalize-package-data - - npm-audit-report - - npm-install-checks - - npm-package-arg - - npm-pick-manifest - - npm-profile - - npm-registry-fetch - - npm-user-validate - - npmlog - - p-map - - pacote - - parse-conflict-json - - proc-log - - qrcode-terminal - - read - - semver - - spdx-expression-parse - - ssri - - supports-color - - tar - - text-table - - tiny-relative-date - - treeverse - - validate-npm-package-name - - which - - write-file-atomic - nwsapi@2.2.5: resolution: {integrity: sha512-6xpotnECFy/og7tKSBVmUNft7J3jyXAka4XvG6AUhFWRz+Q/Ljus7znJAA3bxColfQLdS+XsjoodtJfCgeTEFQ==} @@ -7266,40 +5582,14 @@ packages: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} - object-inspect@1.13.1: - resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} - object-keys@1.1.1: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} engines: {node: '>= 0.4'} - object.assign@4.1.4: - resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==} - engines: {node: '>= 0.4'} - - object.fromentries@2.0.7: - resolution: {integrity: sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==} - engines: {node: '>= 0.4'} - - object.groupby@1.0.1: - resolution: {integrity: sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ==} - - object.values@1.1.7: - resolution: {integrity: sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==} - engines: {node: '>= 0.4'} - on-exit-leak-free@2.1.2: resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==} engines: {node: '>=14.0.0'} - on-finished@2.3.0: - resolution: {integrity: sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==} - engines: {node: '>= 0.8'} - - on-finished@2.4.1: - resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} - engines: {node: '>= 0.8'} - once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} @@ -7307,10 +5597,6 @@ packages: resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} engines: {node: '>=6'} - onetime@6.0.0: - resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} - engines: {node: '>=12'} - optionator@0.9.3: resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==} engines: {node: '>= 0.8.0'} @@ -7326,26 +5612,10 @@ packages: outdent@0.5.0: resolution: {integrity: sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==} - p-each-series@3.0.0: - resolution: {integrity: sha512-lastgtAdoH9YaLyDa5i5z64q+kzOcQHsQ5SsZJD3q0VEyI8mq872S3geuNbRUQLVAE9siMfgKrpj7MloKFHruw==} - engines: {node: '>=12'} - p-filter@2.1.0: resolution: {integrity: sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==} engines: {node: '>=8'} - p-filter@4.1.0: - resolution: {integrity: sha512-37/tPdZ3oJwHaS3gNJdenCDB3Tz26i9sjhnguBtvN0vYlRIiDNnvTWkuh+0hETV9rLPdJ3rlL3yVOYPIAnM8rw==} - engines: {node: '>=18'} - - p-is-promise@3.0.0: - resolution: {integrity: sha512-Wo8VsW4IRQSKVXsJCn7TomUaVtyfjVDn3nUP7kE967BQk0CwFpdbZs0X0uk5sW9mkBa9eNM7hCMaG93WUAwxYQ==} - engines: {node: '>=8'} - - p-limit@1.3.0: - resolution: {integrity: sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==} - engines: {node: '>=4'} - p-limit@2.3.0: resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} engines: {node: '>=6'} @@ -7358,10 +5628,6 @@ packages: resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - p-locate@2.0.0: - resolution: {integrity: sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==} - engines: {node: '>=4'} - p-locate@3.0.0: resolution: {integrity: sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==} engines: {node: '>=6'} @@ -7374,84 +5640,29 @@ packages: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} - p-locate@6.0.0: - resolution: {integrity: sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - p-map@2.1.0: resolution: {integrity: sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==} engines: {node: '>=6'} - p-map@7.0.2: - resolution: {integrity: sha512-z4cYYMMdKHzw4O5UkWJImbZynVIo0lSGTXc7bzB1e/rrDqkgGUNysK/o4bTr+0+xKvvLoTyGqYC4Fgljy9qe1Q==} - engines: {node: '>=18'} - - p-reduce@3.0.0: - resolution: {integrity: sha512-xsrIUgI0Kn6iyDYm9StOpOeK29XM1aboGji26+QEortiFST1hGZaUQOLhtEbqHErPpGW/aSz6allwK2qcptp0Q==} - engines: {node: '>=12'} - - p-try@1.0.0: - resolution: {integrity: sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==} - engines: {node: '>=4'} - p-try@2.2.0: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} - pac-proxy-agent@7.0.1: - resolution: {integrity: sha512-ASV8yU4LLKBAjqIPMbrgtaKIvxQri/yh2OpI+S6hVa9JRkUI3Y3NPFbfngDtY7oFtSMD3w31Xns89mDa3Feo5A==} - engines: {node: '>= 14'} - - pac-resolver@7.0.1: - 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==} - parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} - parse-json@4.0.0: - resolution: {integrity: sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==} - engines: {node: '>=4'} - parse-json@5.2.0: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} - parse-json@8.1.0: - resolution: {integrity: sha512-rum1bPifK5SSar35Z6EKZuYPJx85pkNaFrxBK3mwdfSJ1/WKbYrjoW/zTPSjRRamfmVX1ACBIdFAO0VRErW/EA==} - engines: {node: '>=18'} - - parse-ms@4.0.0: - resolution: {integrity: sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==} - engines: {node: '>=18'} - - parse-multipart-data@1.5.0: - resolution: {integrity: sha512-ck5zaMF0ydjGfejNMnlo5YU2oJ+pT+80Jb1y4ybanT27j+zbVP/jkYmCrUGsEln0Ox/hZmuvgy8Ra7AxbXP2Mw==} - parse-passwd@1.0.0: resolution: {integrity: sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==} engines: {node: '>=0.10.0'} - parse5-htmlparser2-tree-adapter@6.0.1: - resolution: {integrity: sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==} - - parse5@5.1.1: - resolution: {integrity: sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==} - - parse5@6.0.1: - resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==} - parse5@7.1.2: resolution: {integrity: sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==} - parseurl@1.3.3: - resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} - engines: {node: '>= 0.8'} - path-exists@3.0.0: resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==} engines: {node: '>=4'} @@ -7460,10 +5671,6 @@ packages: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} - path-exists@5.0.0: - resolution: {integrity: sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - path-is-absolute@1.0.1: resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} engines: {node: '>=0.10.0'} @@ -7472,10 +5679,6 @@ packages: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} - path-key@4.0.0: - resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} - engines: {node: '>=12'} - path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} @@ -7483,34 +5686,13 @@ packages: resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} engines: {node: '>=16 || 14 >=14.18'} - path-scurry@2.0.0: - resolution: {integrity: sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==} - engines: {node: 20 || >=22} - - path-to-regexp@0.1.7: - resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==} - - path-to-regexp@6.2.2: - resolution: {integrity: sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw==} - path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} - path-type@5.0.0: - resolution: {integrity: sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==} - engines: {node: '>=12'} - - pathval@2.0.0: - resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==} - engines: {node: '>= 14.16'} - pause-stream@0.0.11: resolution: {integrity: sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==} - performance-now@2.1.0: - resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==} - picocolors@1.0.1: resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==} @@ -7522,18 +5704,10 @@ packages: resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} engines: {node: '>=12'} - pify@3.0.0: - resolution: {integrity: sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==} - engines: {node: '>=4'} - pify@4.0.1: resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} engines: {node: '>=6'} - pify@5.0.0: - resolution: {integrity: sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==} - engines: {node: '>=10'} - pino-abstract-transport@1.2.0: resolution: {integrity: sha512-Guhh8EZfPCfH+PMXAb6rKOjGQEoy0xlAIn+irODG5kgfYV+BQ0rGYYWTIel3P5mmyXqkYkPmdIkywsn6QKUR1Q==} @@ -7552,10 +5726,6 @@ packages: resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} engines: {node: '>= 6'} - pkg-conf@2.1.0: - resolution: {integrity: sha512-C+VUP+8jis7EsQZIhDYmS5qlNtjv2yP4SNtjXK9AP1ZcTRlnSfuumaTnRfYZnYgUUYVIKqL0fRvmUGDV2fmp6g==} - engines: {node: '>=4'} - pkg-dir@3.0.0: resolution: {integrity: sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==} engines: {node: '>=6'} @@ -7564,10 +5734,6 @@ packages: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} engines: {node: '>=8'} - portfinder@1.0.32: - resolution: {integrity: sha512-on2ZJVVDXRADWE6jnQaX0ioEylzgBpQk8r55NE4wjXW1ZxO+BgDlY6DXwj20i0V8eB4SenDQ00WEaxfiIQPcxg==} - engines: {node: '>= 0.12.0'} - postcss-load-config@6.0.1: resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} engines: {node: '>= 18'} @@ -7598,20 +5764,11 @@ packages: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} - prettier-linter-helpers@1.0.0: - resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} - engines: {node: '>=6.0.0'} - prettier@2.8.8: resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} engines: {node: '>=10.13.0'} hasBin: true - prettier@3.3.1: - resolution: {integrity: sha512-7CAwy5dRsxs8PHXT3twixW9/OEll8MLE0VRPCJyl7CkS6VHGPSlsVaWTiASPTyGyYRyApxlaWTzwUxVNrhcwDg==} - engines: {node: '>=14'} - hasBin: true - prettier@3.3.3: resolution: {integrity: sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==} engines: {node: '>=14'} @@ -7629,13 +5786,6 @@ packages: resolution: {integrity: sha512-qRzqj0zWh2CRvL9UbWGksN9YSSuzzvNqexrDBwKiH48RVX00BQCxHwSfWF+sigp3IZGKxjG2nud42SQQU8q3Yg==} engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} - pretty-ms@9.0.0: - resolution: {integrity: sha512-E9e9HJ9R9NasGOgPaPE8VMeiPKAyWR5jcFpNnwIejslIhWqdqOrb2wShBsncMPUb+BcCd2OPYfh7p2W6oemTng==} - engines: {node: '>=18'} - - process-nextick-args@2.0.1: - resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} - process-warning@4.0.0: resolution: {integrity: sha512-/MyYDxttz7DfGMMHiysAsFE4qF+pQYAA8ziO/3NcRVrQ5fSk+Mns4QZA/oRPFzvcqNoVJXQNWNAsdwBXLUkQKw==} @@ -7647,13 +5797,6 @@ packages: resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} engines: {node: '>= 6'} - proto-list@1.2.4: - resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} - - proxy-addr@2.0.7: - resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} - engines: {node: '>= 0.10'} - proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} @@ -7671,10 +5814,6 @@ packages: pump@3.0.0: resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} - punycode.js@2.3.1: - resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} - engines: {node: '>=6'} - punycode@2.3.0: resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} engines: {node: '>=6'} @@ -7682,10 +5821,6 @@ packages: pure-rand@6.0.2: resolution: {integrity: sha512-6Yg0ekpKICSjPswYOuC5sku/TSWaRYlA0qsXqJgM/d/4pLPHPuTxK7Nbf7jFKzAeedUhR8C7K9Uv63FBsSo8xQ==} - qs@6.11.0: - resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==} - engines: {node: '>=0.6'} - querystringify@2.2.0: resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} @@ -7695,28 +5830,6 @@ packages: quick-format-unescaped@4.0.4: resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} - quick-lru@5.1.1: - resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} - engines: {node: '>=10'} - - rambda@7.5.0: - resolution: {integrity: sha512-y/M9weqWAH4iopRd7EHDEQQvpFPHj1AA3oHozE9tfITHUtTR7Z9PSlIRRG2l1GuW7sefC1cXFfIcF+cgnShdBA==} - - randombytes@2.1.0: - resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} - - range-parser@1.2.1: - resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} - engines: {node: '>= 0.6'} - - raw-body@2.5.2: - resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==} - engines: {node: '>= 0.8'} - - rc@1.2.8: - resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} - hasBin: true - react-dom@18.3.1: resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} peerDependencies: @@ -7790,30 +5903,10 @@ packages: resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} engines: {node: '>=0.10.0'} - read-package-up@11.0.0: - resolution: {integrity: sha512-MbgfoNPANMdb4oRBNg5eqLbB2t2r+o5Ua1pNt8BqGp4I0FJZhuVSOj3PaBPni4azWuSzEdNn2evevzVmEk1ohQ==} - engines: {node: '>=18'} - - read-pkg-up@11.0.0: - resolution: {integrity: sha512-LOVbvF1Q0SZdjClSefZ0Nz5z8u+tIE7mV5NibzmE9VYmDe9CaBbAVtz1veOSZbofrdsilxuDAYnFenukZVp8/Q==} - engines: {node: '>=18'} - deprecated: Renamed to read-package-up - - read-pkg@9.0.1: - resolution: {integrity: sha512-9viLL4/n1BJUCT1NXVTdS1jtm80yDEgR5T4yCelII49Mbj0v1rZdKqj7zCiYdbB0CuCgdrvHcNogAKTFPBocFA==} - engines: {node: '>=18'} - - read-tls-client-hello@1.0.1: - resolution: {integrity: sha512-OvSzfVv6Y656ekUxB7aDhWkLW7y1ck16ChfLFNJhKNADFNweH2fvyiEZkGmmdtXbOtlNuH2zVXZoFCW349M+GA==} - engines: {node: '>=12.0.0'} - read-yaml-file@1.1.0: resolution: {integrity: sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==} engines: {node: '>=6'} - readable-stream@2.3.8: - resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} - readable-stream@4.5.2: resolution: {integrity: sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -7847,18 +5940,10 @@ packages: regenerator-transform@0.15.2: resolution: {integrity: sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==} - regexp.prototype.flags@1.5.1: - resolution: {integrity: sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==} - engines: {node: '>= 0.4'} - regexpu-core@5.3.2: resolution: {integrity: sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==} engines: {node: '>=4'} - registry-auth-token@5.0.2: - resolution: {integrity: sha512-o/3ikDxtXaA59BmZuZrJZDJv8NMDGSj+6j6XaeBmHw8eY1i1qd9+6H+LjVvQXx3HN6aRCGa1cUdJ9RaJZUugnQ==} - engines: {node: '>=14'} - regjsparser@0.9.1: resolution: {integrity: sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==} hasBin: true @@ -7867,10 +5952,6 @@ packages: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} - require-from-string@2.0.2: - resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} - engines: {node: '>=0.10.0'} - requireindex@1.2.0: resolution: {integrity: sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==} engines: {node: '>=0.10.5'} @@ -7878,9 +5959,6 @@ packages: requires-port@1.0.0: resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} - resolve-alpn@1.2.1: - resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} - resolve-cwd@3.0.0: resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} engines: {node: '>=8'} @@ -7926,28 +6004,6 @@ packages: deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true - rimraf@6.0.1: - resolution: {integrity: sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A==} - engines: {node: 20 || >=22} - hasBin: true - - rollup-plugin-dts@6.1.1: - resolution: {integrity: sha512-aSHRcJ6KG2IHIioYlvAOcEq6U99sVtqDDKVhnwt70rW6tsz3tv5OSjEiWcgzfsHdLyGXZ/3b/7b/+Za3Y6r1XA==} - engines: {node: '>=16'} - peerDependencies: - rollup: ^3.29.4 || ^4 - typescript: ^4.5 || ^5.0 - - rollup-plugin-inject@3.0.2: - resolution: {integrity: sha512-ptg9PQwzs3orn4jkgXJ74bfs5vYz1NCZlSQMBUA0wKcGp5i5pA1AO3fOUEte8enhGUC+iapTCzEWw2jEFFUO/w==} - deprecated: This package has been deprecated and is no longer maintained. Please use @rollup/plugin-inject. - - rollup-plugin-node-polyfills@0.2.1: - resolution: {integrity: sha512-4kCrKPTJ6sK4/gLL/U5QzVT8cxJcofO0OU74tnB19F40cmuAKSzH5/siithxlofFEjwvw1YAhPmbvGNA6jEroA==} - - rollup-pluginutils@2.8.2: - resolution: {integrity: sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==} - rollup@3.27.2: resolution: {integrity: sha512-YGwmHf7h2oUHkVBT248x0yt6vZkYQ3/rvE5iQuVBh3WO8GcJ6BNeOkpoX1yMHIiBm18EMLjBPIoUDkhgnyxGOQ==} engines: {node: '>=14.18.0', npm: '>=8.0.0'} @@ -7970,19 +6026,9 @@ packages: rxjs@7.8.1: resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} - safe-array-concat@1.0.1: - resolution: {integrity: sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==} - engines: {node: '>=0.4'} - - safe-buffer@5.1.2: - resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} - safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - safe-regex-test@1.0.0: - resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==} - safe-stable-stringify@2.4.3: resolution: {integrity: sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==} engines: {node: '>=10'} @@ -8000,21 +6046,8 @@ packages: secure-json-parse@2.7.0: resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==} - semantic-release@24.0.0: - resolution: {integrity: sha512-v46CRPw+9eI3ZuYGF2oAjqPqsfbnfFTwLBgQsv/lch4goD09ytwOTESMN4QIrx/wPLxUGey60/NMx+ANQtWRsA==} - engines: {node: '>=20.8.1'} - hasBin: true - - semver-diff@4.0.0: - resolution: {integrity: sha512-0Ju4+6A8iOnpL/Thra7dZsSlOHYAHIeMxfhWQRI1/VLcT3WDBZKKtQt/QkBOsiIN9ZpuvHE6cGZ0x4glCMmfiA==} - engines: {node: '>=12'} - - semver-regex@4.0.5: - resolution: {integrity: sha512-hunMQrEy1T6Jr2uEVjrAIqjwWcQTgOAcIM52C8MY1EZSD3DDNft04XzvYKPqjED65bNVVko0YI38nYeEHCX3yw==} - engines: {node: '>=12'} - - semver@5.7.1: - resolution: {integrity: sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==} + semver@5.7.1: + resolution: {integrity: sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==} hasBin: true semver@6.3.1: @@ -8026,31 +6059,10 @@ packages: engines: {node: '>=10'} hasBin: true - send@0.18.0: - resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==} - engines: {node: '>= 0.8.0'} - - serialize-javascript@6.0.0: - resolution: {integrity: sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==} - - serialize-javascript@6.0.1: - resolution: {integrity: sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==} - - serve-static@1.15.0: - resolution: {integrity: sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==} - engines: {node: '>= 0.8.0'} - set-function-length@1.1.1: resolution: {integrity: sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==} engines: {node: '>= 0.4'} - set-function-name@2.0.1: - resolution: {integrity: sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==} - engines: {node: '>= 0.4'} - - setprototypeof@1.2.0: - resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - shallow-clone@3.0.1: resolution: {integrity: sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==} engines: {node: '>=8'} @@ -8071,12 +6083,6 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} - shiki@1.9.1: - resolution: {integrity: sha512-8PDkgb5ja3nfujTjvC4VytL6wGOGCtFAClUb2r3QROevYXxcq+/shVJK5s6gy0HZnjaJgFxd6BpPqpRfqne5rA==} - - side-channel@1.0.4: - resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} - signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} @@ -8084,57 +6090,17 @@ packages: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} - signale@1.4.0: - resolution: {integrity: sha512-iuh+gPf28RkltuJC7W5MRi6XAjTDCAPC/prJUpQoG4vIP3MJZ+GTydVnodXA7pwvTKb2cA0m9OFZW/cdWy/I/w==} - engines: {node: '>=6'} - - sinon-chai@4.0.0: - resolution: {integrity: sha512-cWqO7O2I4XfJDWyWElAQ9D/dtdh5Mo0RHndsfiiYyjWnlPzBJdIvjCVURO4EjyYaC3BjV+ISNXCfTXPXTEIEWA==} - peerDependencies: - chai: ^5.0.0 - sinon: '>=4.0.0' - - sinon@18.0.0: - resolution: {integrity: sha512-+dXDXzD1sBO6HlmZDd7mXZCR/y5ECiEiGCBSGuFD/kZ0bDTofPYc6JaeGmPSF+1j1MejGUWkORbYOLDyvqCWpA==} - sisteransi@1.0.5: resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} - skin-tone@2.0.0: - resolution: {integrity: sha512-kUMbT1oBJCpgrnKoSr0o6wPtvRWT9W9UKvGLwfJYO2WuahZRHOpEyL1ckyMGgMWh0UdpmaoFqKKD29WTomNEGA==} - engines: {node: '>=8'} - slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} - slash@4.0.0: - resolution: {integrity: sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==} - engines: {node: '>=12'} - slash@5.1.0: resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==} engines: {node: '>=14.16'} - smart-buffer@4.2.0: - resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} - engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} - - smob@1.4.0: - resolution: {integrity: sha512-MqR3fVulhjWuRNSMydnTlweu38UhQ0HXM4buStD/S3mc/BzX3CuM9OmhyQpmtYCvoYdl5ris6TI0ZqH355Ymqg==} - - socks-proxy-agent@7.0.0: - resolution: {integrity: sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==} - engines: {node: '>= 10'} - - socks-proxy-agent@8.0.3: - resolution: {integrity: sha512-VNegTZKhuGq5vSD6XNKlbqWhyt/40CgoEw8XxD6dhnm8Jq9IEa3nIa4HwnM8XOqU0CdB0BwWVXusqiFXfHB3+A==} - engines: {node: '>= 14'} - - socks@2.8.1: - resolution: {integrity: sha512-B6w7tkwNid7ToxjZ08rQMT8M9BJAf8DKx8Ft4NivzH0zBUfd6jldGcisJn/RLgxcX3FPNDdNQCUEMMT79b+oCQ==} - engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} - sonic-boom@4.0.1: resolution: {integrity: sha512-hTSD/6JMLyT4r9zeof6UtuBDpjJ9sO08/nmS5djaA9eozT9oOlNdpXSnzcgj4FTqpk3nkLrs61l4gip9r1HCrQ==} @@ -8156,13 +6122,6 @@ packages: resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} engines: {node: '>= 8'} - sourcemap-codec@1.4.8: - resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==} - deprecated: Please use @jridgewell/sourcemap-codec instead - - spawn-error-forwarder@1.0.0: - resolution: {integrity: sha512-gRjMgK5uFjbCvdibeGJuy3I5OYz6VLoVdsOJdA6wV0WlfQVLFueoqMxwwYD9RODdgb6oUIvlRlsyFSiQkMKu0g==} - spawnd@10.0.0: resolution: {integrity: sha512-6GKcakMTryb5b1SWCvdubCDHEsR2k+5VZUD5G19umZRarkvj1RyCGyizcqhjewI7cqZo8fTVD8HpnDZbVOLMtg==} engines: {node: '>=16'} @@ -8170,21 +6129,6 @@ packages: spawndamnit@2.0.0: resolution: {integrity: sha512-j4JKEcncSjFlqIwU5L/rp2N5SIPsdxaRsIv678+TZxZ0SRDJTm8JrxJMjE/XuiEZNEir3S8l0Fa3Ke339WI4qA==} - spdx-correct@3.2.0: - resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} - - spdx-exceptions@2.3.0: - resolution: {integrity: sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==} - - spdx-expression-parse@3.0.1: - resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} - - spdx-license-ids@3.0.13: - resolution: {integrity: sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==} - - split2@1.0.0: - resolution: {integrity: sha512-NKywug4u4pX/AZBB1FCPzZ6/7O+Xhz1qMVbzTvvKvikjO99oPN87SkK08mEY9P63/5lWjK+wgOOgApnTg5r6qg==} - split2@4.2.0: resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} engines: {node: '>= 10.x'} @@ -8195,9 +6139,6 @@ packages: sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} - sprintf-js@1.1.3: - resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} - stack-utils@2.0.6: resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} engines: {node: '>=10'} @@ -8207,23 +6148,9 @@ packages: engines: {node: '>=16'} hasBin: true - statuses@1.5.0: - resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==} - engines: {node: '>= 0.6'} - - statuses@2.0.1: - resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} - engines: {node: '>= 0.8'} - - stream-combiner2@1.1.1: - resolution: {integrity: sha512-3PnJbYgS56AeWgtKF5jtJRT6uFJe56Z0Hc5Ngg/6sI6rIt8iiMBTa9cvdyFfpMQjaVHr8dusbNeFGIIonxOvKw==} - stream-combiner@0.0.4: resolution: {integrity: sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw==} - stream-shift@1.0.3: - resolution: {integrity: sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==} - string-length@4.0.2: resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} engines: {node: '>=10'} @@ -8240,19 +6167,6 @@ packages: resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} engines: {node: '>=12'} - string.prototype.trim@1.2.8: - resolution: {integrity: sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==} - engines: {node: '>= 0.4'} - - string.prototype.trimend@1.0.7: - resolution: {integrity: sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==} - - string.prototype.trimstart@1.0.7: - resolution: {integrity: sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==} - - string_decoder@1.1.1: - resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} - string_decoder@1.3.0: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} @@ -8276,18 +6190,6 @@ packages: resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} engines: {node: '>=6'} - strip-final-newline@3.0.0: - resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} - engines: {node: '>=12'} - - strip-final-newline@4.0.0: - resolution: {integrity: sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==} - engines: {node: '>=18'} - - strip-json-comments@2.0.1: - resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} - engines: {node: '>=0.10.0'} - strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} @@ -8297,10 +6199,6 @@ packages: engines: {node: '>=16 || 14 >=14.17'} hasBin: true - super-regex@1.0.0: - resolution: {integrity: sha512-CY8u7DtbvucKuquCmOFEKhr9Besln7n9uN8eFbwcoGYWXOMW07u2o8njWaiXt11ylS3qoGF55pILjRmPlbodyg==} - engines: {node: '>=18'} - superstruct@2.0.2: resolution: {integrity: sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A==} engines: {node: '>=14.0.0'} @@ -8317,10 +6215,6 @@ packages: resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} engines: {node: '>=10'} - supports-hyperlinks@3.0.0: - resolution: {integrity: sha512-QBDPHyPQDRTy9ku4URNGY5Lah8PAaXs6tAAwp55sL5WCsSW7GIfdf6W5ixfziW+t7wh3GVvHyHHyQ1ESsoRvaA==} - engines: {node: '>=14.18'} - supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} @@ -8330,10 +6224,6 @@ packages: peerDependencies: react: ^16.11.0 || ^17.0.0 || ^18.0.0 - symbol-observable@1.2.0: - resolution: {integrity: sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==} - engines: {node: '>=0.10.0'} - symbol-tree@3.2.4: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} @@ -8341,18 +6231,10 @@ packages: resolution: {integrity: sha512-7gr8p9TQP6RAHusBOSLs46F4564ZrjV8xFmw5zCmgmhGUcw2hxsShhJ6CEiHQMgPDwAQ1fWHPM0ypc4RMAig4A==} engines: {node: ^14.18.0 || >=16.0.0} - temp-dir@3.0.0: - resolution: {integrity: sha512-nHc6S/bwIilKHNRgK/3jlhDoIHcp45YgyiwcAk46Tr0LfEqGBVpmiAyuiuxeVE44m3mXnEeVhaipLOEWmH+Njw==} - engines: {node: '>=14.16'} - temp@0.9.4: resolution: {integrity: sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==} engines: {node: '>=6.0.0'} - tempy@3.1.0: - resolution: {integrity: sha512-7jDLIdD2Zp0bDe5r3D2qtkd1QOCacylBuL7oa4udvN6v2pqr4+LcCr67C8DR1zkpaZ8XosF5m1yQSabKAW6f2g==} - engines: {node: '>=14.16'} - term-size@2.2.1: resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==} engines: {node: '>=8'} @@ -8369,10 +6251,6 @@ packages: text-encoding-utf-8@1.0.2: resolution: {integrity: sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg==} - text-extensions@2.4.0: - resolution: {integrity: sha512-te/NtwBwfiNRLf9Ijqx3T0nlqZiQ2XrrtBvu+cLL8ZRrGkO0NHTug8MYFKyoSrv/sHTaSKfilUkizV6XhxMJ3g==} - engines: {node: '>=8'} - text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} @@ -8389,16 +6267,9 @@ packages: throat@6.0.2: resolution: {integrity: sha512-WKexMoJj3vEuK0yFEapj8y64V0A6xcuPuK9Gt1d0R+dzCSJc0lHqQytAbSB4cDAK0dWh4T0E2ETkoLE2WZ41OQ==} - through2@2.0.5: - resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==} - through@2.3.8: resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} - time-span@5.1.0: - resolution: {integrity: sha512-75voc/9G4rDIJleOo4jPvN4/YC4GRZrY8yy1uU4lwrB3XEQbWve8zXoO5No4eFrGcTAMYyoY67p8jRQdtA1HbA==} - engines: {node: '>=12'} - tiny-invariant@1.3.3: resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} @@ -8420,10 +6291,6 @@ packages: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} - toidentifier@1.0.1: - resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} - engines: {node: '>=0.6'} - tough-cookie@4.1.3: resolution: {integrity: sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==} engines: {node: '>=6'} @@ -8438,9 +6305,6 @@ packages: resolution: {integrity: sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==} engines: {node: '>=14'} - traverse@0.6.7: - resolution: {integrity: sha512-/y956gpUo9ZNCb99YjxG7OaslxZWHfCHAUUfshwqOXmxUIvqLjVO581BT+gM59+QV9tFe6/CGG53tsA1Y7RSdg==} - tree-kill@1.2.2: resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} hasBin: true @@ -8468,9 +6332,6 @@ packages: '@swc/wasm': optional: true - tsconfig-paths@3.14.2: - resolution: {integrity: sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==} - tslib@1.14.1: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} @@ -8557,55 +6418,13 @@ packages: resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} engines: {node: '>=10'} - type-fest@1.4.0: - resolution: {integrity: sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==} - engines: {node: '>=10'} - - type-fest@2.19.0: - resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} - engines: {node: '>=12.20'} - type-fest@3.12.0: resolution: {integrity: sha512-qj9wWsnFvVEMUDbESiilKeXeHL7FwwiFcogfhfyjmvT968RXSvnl23f1JOClTHYItsi7o501C/7qVllscUP3oA==} engines: {node: '>=14.16'} - type-fest@4.15.0: - resolution: {integrity: sha512-tB9lu0pQpX5KJq54g+oHOLumOx+pMep4RaM6liXh2PKmVRFF+/vAtUP0ZaJ0kOySfVNjF6doBWPHhBhISKdlIA==} - engines: {node: '>=16'} - - type-is@1.6.18: - resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} - engines: {node: '>= 0.6'} - - typed-array-buffer@1.0.0: - resolution: {integrity: sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==} - engines: {node: '>= 0.4'} - - typed-array-byte-length@1.0.0: - resolution: {integrity: sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==} - engines: {node: '>= 0.4'} - - typed-array-byte-offset@1.0.0: - resolution: {integrity: sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==} - engines: {node: '>= 0.4'} - - typed-array-length@1.0.4: - resolution: {integrity: sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==} - - typed-error@3.2.2: - resolution: {integrity: sha512-Z48LU67/qJ+vyA7lh3ozELqpTp3pvQoY5RtLi5wQ/UGSrEidBhlVSqhjr8B3iqbGpjqAoJYrtSYXWMDtidWGkA==} - engines: {node: '>=6.0.0', npm: '>=3.0.0'} - typedarray-to-buffer@3.1.5: resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} - typedoc@0.26.5: - resolution: {integrity: sha512-Vn9YKdjKtDZqSk+by7beZ+xzkkr8T8CYoiasqyt4TTRFy5+UHzL/mF/o4wGBjRF+rlWQHDb0t6xCpA3JNL5phg==} - engines: {node: '>= 18'} - hasBin: true - peerDependencies: - typescript: 4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x - typescript@5.5.2: resolution: {integrity: sha512-NcRtPEOsPFFWjobJEtfihkLCZCXZt/os3zf8nTxjVH3RvTSxjrCamJpbExGvYOF+tFHc3pA65qpdwPbzjohhew==} engines: {node: '>=14.17'} @@ -8616,17 +6435,6 @@ packages: engines: {node: '>=14.17'} hasBin: true - uc.micro@2.1.0: - resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} - - uglify-js@3.17.4: - resolution: {integrity: sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==} - engines: {node: '>=0.8.0'} - hasBin: true - - unbox-primitive@1.0.2: - resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} - undici-types@5.26.5: resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} @@ -8644,10 +6452,6 @@ packages: resolution: {integrity: sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==} engines: {node: '>=4'} - unicode-emoji-modifier-base@1.0.0: - resolution: {integrity: sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g==} - engines: {node: '>=4'} - unicode-match-property-ecmascript@2.0.0: resolution: {integrity: sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==} engines: {node: '>=4'} @@ -8660,17 +6464,6 @@ packages: resolution: {integrity: sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==} engines: {node: '>=4'} - unicorn-magic@0.1.0: - resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==} - engines: {node: '>=18'} - - unique-string@3.0.0: - resolution: {integrity: sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==} - engines: {node: '>=12'} - - universal-user-agent@7.0.2: - resolution: {integrity: sha512-0JCqzSKnStlRRQfCdowvqy3cy0Dvtlb8xecj/H8JFZuCze4rwjPZQOgvFvn0Ws/usCHQFGpyr+pB9adaGwXn4Q==} - universalify@0.1.2: resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} engines: {node: '>= 4.0.0'} @@ -8679,14 +6472,6 @@ packages: resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} engines: {node: '>= 4.0.0'} - universalify@2.0.0: - resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==} - engines: {node: '>= 10.0.0'} - - unpipe@1.0.0: - resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} - engines: {node: '>= 0.8'} - update-browserslist-db@1.1.0: resolution: {integrity: sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==} hasBin: true @@ -8696,16 +6481,9 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - url-join@5.0.0: - resolution: {integrity: sha512-n2huDr9h9yzd6exQVnH/jU5mr+Pfx08LRXXZhkLLetAMESRj+anQsTAh940iMrIetKAmry9coFuZQ2jY8/p3WA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - url-parse@1.5.10: resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} - urlpattern-polyfill@8.0.2: - resolution: {integrity: sha512-Qp95D4TPJl1kC9SKigDcqgyM2VDVO4RiJc2d4qe5GrYm+zbIQCWWKAFaJNQ4BhdFeDGwBmAxqJBwWSJDb9T3BQ==} - use-callback-ref@1.3.2: resolution: {integrity: sha512-elOQwe6Q8gqZgDA8mrh44qRTQqpIHDcZ3hXTLjBe1i4ph8XpNJnO+aQf3NaG+lriLopI4HMx9VjQLfPQ6vhnoA==} engines: {node: '>=10'} @@ -8735,13 +6513,6 @@ packages: resolution: {integrity: sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==} engines: {node: '>=6.14.2'} - util-deprecate@1.0.2: - resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - - utils-merge@1.0.1: - resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} - engines: {node: '>= 0.4.0'} - uuid@8.3.2: resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} hasBin: true @@ -8753,21 +6524,10 @@ packages: resolution: {integrity: sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==} engines: {node: '>=10.12.0'} - validate-npm-package-license@3.0.4: - resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} - - value-or-promise@1.0.11: - resolution: {integrity: sha512-41BrgH+dIbCFXClcSapVs5M6GkENd3gQOJpEfPDNa71LsUGMXDL0jMWpI/Rh7WhX+Aalfz2TTS3Zt5pUsbnhLg==} - engines: {node: '>=12'} - value-or-promise@1.0.12: resolution: {integrity: sha512-Z6Uz+TYwEqE7ZN50gwn+1LCVo9ZVrpxRPOhOLnncYkY1ZzOYtrX8Fwf/rFktZ8R5mJms6EZf5TqNOMeZmnPq9Q==} engines: {node: '>=12'} - vary@1.1.2: - resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} - engines: {node: '>= 0.8'} - vite@5.3.5: resolution: {integrity: sha512-MdjglKR6AQXQb9JGiS7Rc2wC6uMjcm7Go/NHNO63EwiJXfuk9PgqiP/n5IDJCziMkfw9n4Ubp7lttNwz+8ZVKA==} engines: {node: ^18.0.0 || >=20.0.0} @@ -8839,17 +6599,10 @@ packages: whatwg-url@7.1.0: resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==} - which-boxed-primitive@1.0.2: - resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} - which-pm@2.0.0: resolution: {integrity: sha512-Lhs9Pmyph0p5n5Z3mVnN0yWcbQYUAD7rbQUiMsQxOJ3T57k7RFe35SUwWMf7dsbDZks1uOmw4AecB/JMDj3v/w==} engines: {node: '>=8.15'} - which-typed-array@1.1.13: - resolution: {integrity: sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==} - engines: {node: '>= 0.4'} - which@1.3.1: resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} hasBin: true @@ -8859,12 +6612,6 @@ packages: engines: {node: '>= 8'} hasBin: true - wordwrap@1.0.0: - resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} - - workerpool@6.2.1: - resolution: {integrity: sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==} - wrap-ansi@6.2.0: resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} engines: {node: '>=8'} @@ -8930,10 +6677,6 @@ packages: xmlchars@2.2.0: resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} - xtend@4.0.2: - resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} - engines: {node: '>=0.4'} - y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -8956,26 +6699,10 @@ packages: engines: {node: '>= 14'} hasBin: true - yargs-parser@20.2.4: - resolution: {integrity: sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==} - engines: {node: '>=10'} - - yargs-parser@20.2.9: - resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} - engines: {node: '>=10'} - yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} - yargs-unparser@2.0.0: - resolution: {integrity: sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==} - engines: {node: '>=10'} - - yargs@16.2.0: - resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} - engines: {node: '>=10'} - yargs@17.7.2: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} @@ -8996,17 +6723,10 @@ packages: resolution: {integrity: sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==} engines: {node: '>=18'} - yoctocolors@2.0.2: - resolution: {integrity: sha512-Ct97huExsu7cWeEjmrXlofevF8CvzUglJ4iGUet5B8xn1oumtAZBpHU4GzYuoE6PVqcZ5hghtBrSlhwHuR1Jmw==} - engines: {node: '>=18'} - yoctocolors@2.1.1: resolution: {integrity: sha512-GQHQqAopRhwU8Kt1DDM8NjibDXHC8eoh1erhGAJPEyveY9qqVeXvVikNKrDz69sHowPMorbPUrH/mx8c50eiBQ==} engines: {node: '>=18'} - zstd-codec@0.1.4: - resolution: {integrity: sha512-KYnWoFWgGtWyQEKNnUcb3u8ZtKO8dn5d8u+oGpxPlopqsPyv60U8suDyfk7Z7UtAO6Sk5i1aVcAs9RbaB1n36A==} - zx@8.1.4: resolution: {integrity: sha512-QFDYYpnzdpRiJ3dL2102Cw26FpXpWshW4QLTGxiYfIcwdAqg084jRCkK/kuP/NOSkxOjydRwNFG81qzA5r1a6w==} engines: {node: '>= 12.17.0'} @@ -9021,12 +6741,6 @@ snapshots: '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 - '@babel/code-frame@7.24.6': - dependencies: - '@babel/highlight': 7.24.6 - picocolors: 1.0.1 - optional: true - '@babel/code-frame@7.24.7': dependencies: '@babel/highlight': 7.24.7 @@ -9105,6 +6819,7 @@ snapshots: '@babel/types': 7.25.0 transitivePeerDependencies: - supports-color + optional: true '@babel/helper-compilation-targets@7.24.8': dependencies: @@ -9129,21 +6844,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/helper-create-class-features-plugin@7.24.7(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-annotate-as-pure': 7.24.7 - '@babel/helper-environment-visitor': 7.24.7 - '@babel/helper-function-name': 7.24.7 - '@babel/helper-member-expression-to-functions': 7.24.7 - '@babel/helper-optimise-call-expression': 7.24.7 - '@babel/helper-replace-supers': 7.24.7(@babel/core@7.24.9) - '@babel/helper-skip-transparent-expression-wrappers': 7.24.7 - '@babel/helper-split-export-declaration': 7.24.7 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - '@babel/helper-create-regexp-features-plugin@7.25.0(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 @@ -9152,13 +6852,6 @@ snapshots: semver: 6.3.1 optional: true - '@babel/helper-create-regexp-features-plugin@7.25.0(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-annotate-as-pure': 7.24.7 - regexpu-core: 5.3.2 - semver: 6.3.1 - '@babel/helper-define-polyfill-provider@0.6.1(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 @@ -9171,17 +6864,6 @@ snapshots: - supports-color optional: true - '@babel/helper-define-polyfill-provider@0.6.1(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-compilation-targets': 7.24.8 - '@babel/helper-plugin-utils': 7.24.8 - debug: 4.3.5 - lodash.debounce: 4.0.8 - resolve: 1.22.8 - transitivePeerDependencies: - - supports-color - '@babel/helper-environment-visitor@7.24.7': dependencies: '@babel/types': 7.24.9 @@ -9208,10 +6890,7 @@ snapshots: '@babel/types': 7.25.0 transitivePeerDependencies: - supports-color - - '@babel/helper-module-imports@7.22.15': - dependencies: - '@babel/types': 7.24.9 + optional: true '@babel/helper-module-imports@7.24.7': dependencies: @@ -9231,17 +6910,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/helper-module-transforms@7.24.8(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-environment-visitor': 7.24.7 - '@babel/helper-module-imports': 7.24.7 - '@babel/helper-simple-access': 7.24.7 - '@babel/helper-split-export-declaration': 7.24.7 - '@babel/helper-validator-identifier': 7.24.7 - transitivePeerDependencies: - - supports-color - '@babel/helper-module-transforms@7.24.9(@babel/core@7.24.9)': dependencies: '@babel/core': 7.24.9 @@ -9264,16 +6932,6 @@ snapshots: - supports-color optional: true - '@babel/helper-module-transforms@7.25.0(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-module-imports': 7.24.7 - '@babel/helper-simple-access': 7.24.7 - '@babel/helper-validator-identifier': 7.24.7 - '@babel/traverse': 7.25.1 - transitivePeerDependencies: - - supports-color - '@babel/helper-optimise-call-expression@7.24.7': dependencies: '@babel/types': 7.24.9 @@ -9292,15 +6950,6 @@ snapshots: - supports-color optional: true - '@babel/helper-remap-async-to-generator@7.25.0(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-annotate-as-pure': 7.24.7 - '@babel/helper-wrap-function': 7.25.0 - '@babel/traverse': 7.25.1 - transitivePeerDependencies: - - supports-color - '@babel/helper-replace-supers@7.24.7(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 @@ -9310,15 +6959,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/helper-replace-supers@7.24.7(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-environment-visitor': 7.24.7 - '@babel/helper-member-expression-to-functions': 7.24.7 - '@babel/helper-optimise-call-expression': 7.24.7 - transitivePeerDependencies: - - supports-color - '@babel/helper-replace-supers@7.25.0(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 @@ -9329,15 +6969,6 @@ snapshots: - supports-color optional: true - '@babel/helper-replace-supers@7.25.0(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-member-expression-to-functions': 7.24.8 - '@babel/helper-optimise-call-expression': 7.24.7 - '@babel/traverse': 7.25.1 - transitivePeerDependencies: - - supports-color - '@babel/helper-simple-access@7.24.7': dependencies: '@babel/traverse': 7.24.8 @@ -9371,20 +7002,13 @@ snapshots: '@babel/types': 7.25.0 transitivePeerDependencies: - supports-color + optional: true '@babel/helpers@7.24.8': dependencies: '@babel/template': 7.24.7 '@babel/types': 7.24.9 - '@babel/highlight@7.24.6': - dependencies: - '@babel/helper-validator-identifier': 7.24.7 - chalk: 2.4.2 - js-tokens: 4.0.0 - picocolors: 1.0.1 - optional: true - '@babel/highlight@7.24.7': dependencies: '@babel/helper-validator-identifier': 7.24.7 @@ -9413,36 +7037,18 @@ snapshots: - supports-color optional: true - '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.25.0(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/traverse': 7.25.1 - transitivePeerDependencies: - - supports-color - '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.25.0(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 '@babel/helper-plugin-utils': 7.24.8 optional: true - '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.25.0(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.25.0(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 '@babel/helper-plugin-utils': 7.24.8 optional: true - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.25.0(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.24.7(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 @@ -9453,15 +7059,6 @@ snapshots: - supports-color optional: true - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.24.7(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/helper-skip-transparent-expression-wrappers': 7.24.7 - '@babel/plugin-transform-optional-chaining': 7.24.8(@babel/core@7.24.9) - transitivePeerDependencies: - - supports-color - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.25.0(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 @@ -9471,23 +7068,11 @@ snapshots: - supports-color optional: true - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.25.0(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/traverse': 7.25.1 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.24.8)': + '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 optional: true - '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 @@ -9521,33 +7106,18 @@ snapshots: '@babel/helper-plugin-utils': 7.24.8 optional: true - '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 '@babel/helper-plugin-utils': 7.24.8 optional: true - '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 '@babel/helper-plugin-utils': 7.24.8 optional: true - '@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-flow@7.24.7(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 @@ -9559,22 +7129,12 @@ snapshots: '@babel/helper-plugin-utils': 7.24.8 optional: true - '@babel/plugin-syntax-import-assertions@7.24.7(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-import-attributes@7.24.7(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 '@babel/helper-plugin-utils': 7.24.8 optional: true - '@babel/plugin-syntax-import-attributes@7.24.7(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 @@ -9677,11 +7237,6 @@ snapshots: '@babel/helper-plugin-utils': 7.24.8 optional: true - '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 @@ -9710,23 +7265,12 @@ snapshots: '@babel/helper-plugin-utils': 7.24.8 optional: true - '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-create-regexp-features-plugin': 7.25.0(@babel/core@7.24.9) - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-arrow-functions@7.24.7(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 '@babel/helper-plugin-utils': 7.24.8 optional: true - '@babel/plugin-transform-arrow-functions@7.24.7(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-async-generator-functions@7.25.0(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 @@ -9738,16 +7282,6 @@ snapshots: - supports-color optional: true - '@babel/plugin-transform-async-generator-functions@7.25.0(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/helper-remap-async-to-generator': 7.25.0(@babel/core@7.24.9) - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.9) - '@babel/traverse': 7.25.1 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-async-to-generator@7.24.7(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 @@ -9758,37 +7292,18 @@ snapshots: - supports-color optional: true - '@babel/plugin-transform-async-to-generator@7.24.7(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-module-imports': 7.24.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/helper-remap-async-to-generator': 7.25.0(@babel/core@7.24.9) - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-block-scoped-functions@7.24.7(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 '@babel/helper-plugin-utils': 7.24.8 optional: true - '@babel/plugin-transform-block-scoped-functions@7.24.7(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-block-scoping@7.25.0(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 '@babel/helper-plugin-utils': 7.24.8 optional: true - '@babel/plugin-transform-block-scoping@7.25.0(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-class-properties@7.24.7(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 @@ -9797,14 +7312,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-class-properties@7.24.7(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-create-class-features-plugin': 7.24.7(@babel/core@7.24.9) - '@babel/helper-plugin-utils': 7.24.7 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-class-static-block@7.24.7(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 @@ -9815,15 +7322,6 @@ snapshots: - supports-color optional: true - '@babel/plugin-transform-class-static-block@7.24.7(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-create-class-features-plugin': 7.24.7(@babel/core@7.24.9) - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.24.9) - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-classes@7.25.0(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 @@ -9837,18 +7335,6 @@ snapshots: - supports-color optional: true - '@babel/plugin-transform-classes@7.25.0(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-annotate-as-pure': 7.24.7 - '@babel/helper-compilation-targets': 7.24.8 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/helper-replace-supers': 7.25.0(@babel/core@7.24.9) - '@babel/traverse': 7.25.1 - globals: 11.12.0 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-computed-properties@7.24.7(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 @@ -9856,23 +7342,12 @@ snapshots: '@babel/template': 7.25.0 optional: true - '@babel/plugin-transform-computed-properties@7.24.7(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/template': 7.25.0 - '@babel/plugin-transform-destructuring@7.24.8(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 '@babel/helper-plugin-utils': 7.24.8 optional: true - '@babel/plugin-transform-destructuring@7.24.8(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-dotall-regex@7.24.7(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 @@ -9880,23 +7355,12 @@ snapshots: '@babel/helper-plugin-utils': 7.24.8 optional: true - '@babel/plugin-transform-dotall-regex@7.24.7(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-create-regexp-features-plugin': 7.25.0(@babel/core@7.24.9) - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-duplicate-keys@7.24.7(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 '@babel/helper-plugin-utils': 7.24.8 optional: true - '@babel/plugin-transform-duplicate-keys@7.24.7(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.25.0(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 @@ -9904,12 +7368,6 @@ snapshots: '@babel/helper-plugin-utils': 7.24.8 optional: true - '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.25.0(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-create-regexp-features-plugin': 7.25.0(@babel/core@7.24.9) - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-dynamic-import@7.24.7(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 @@ -9917,12 +7375,6 @@ snapshots: '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.8) optional: true - '@babel/plugin-transform-dynamic-import@7.24.7(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.9) - '@babel/plugin-transform-exponentiation-operator@7.24.7(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 @@ -9932,14 +7384,6 @@ snapshots: - supports-color optional: true - '@babel/plugin-transform-exponentiation-operator@7.24.7(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-builder-binary-assignment-operator-visitor': 7.24.7 - '@babel/helper-plugin-utils': 7.24.8 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-export-namespace-from@7.24.7(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 @@ -9947,12 +7391,6 @@ snapshots: '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.24.8) optional: true - '@babel/plugin-transform-export-namespace-from@7.24.7(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.24.9) - '@babel/plugin-transform-flow-strip-types@7.24.7(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 @@ -9968,14 +7406,6 @@ snapshots: - supports-color optional: true - '@babel/plugin-transform-for-of@7.24.7(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/helper-skip-transparent-expression-wrappers': 7.24.7 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-function-name@7.25.1(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 @@ -9986,15 +7416,6 @@ snapshots: - supports-color optional: true - '@babel/plugin-transform-function-name@7.25.1(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-compilation-targets': 7.24.8 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/traverse': 7.25.1 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-json-strings@7.24.7(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 @@ -10002,23 +7423,12 @@ snapshots: '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.8) optional: true - '@babel/plugin-transform-json-strings@7.24.7(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.9) - '@babel/plugin-transform-literals@7.24.7(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 '@babel/helper-plugin-utils': 7.24.8 optional: true - '@babel/plugin-transform-literals@7.24.7(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-logical-assignment-operators@7.24.7(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 @@ -10026,23 +7436,12 @@ snapshots: '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.8) optional: true - '@babel/plugin-transform-logical-assignment-operators@7.24.7(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.9) - '@babel/plugin-transform-member-expression-literals@7.24.7(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 '@babel/helper-plugin-utils': 7.24.8 optional: true - '@babel/plugin-transform-member-expression-literals@7.24.7(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-modules-amd@7.24.7(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 @@ -10052,14 +7451,6 @@ snapshots: - supports-color optional: true - '@babel/plugin-transform-modules-amd@7.24.7(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-module-transforms': 7.25.0(@babel/core@7.24.9) - '@babel/helper-plugin-utils': 7.24.8 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-modules-commonjs@7.24.7(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 @@ -10069,15 +7460,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-commonjs@7.24.7(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-module-transforms': 7.24.8(@babel/core@7.24.9) - '@babel/helper-plugin-utils': 7.24.8 - '@babel/helper-simple-access': 7.24.7 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-modules-commonjs@7.24.8(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 @@ -10088,15 +7470,6 @@ snapshots: - supports-color optional: true - '@babel/plugin-transform-modules-commonjs@7.24.8(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-module-transforms': 7.25.0(@babel/core@7.24.9) - '@babel/helper-plugin-utils': 7.24.8 - '@babel/helper-simple-access': 7.24.7 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-modules-systemjs@7.25.0(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 @@ -10108,16 +7481,6 @@ snapshots: - supports-color optional: true - '@babel/plugin-transform-modules-systemjs@7.25.0(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-module-transforms': 7.25.0(@babel/core@7.24.9) - '@babel/helper-plugin-utils': 7.24.8 - '@babel/helper-validator-identifier': 7.24.7 - '@babel/traverse': 7.25.1 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-modules-umd@7.24.7(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 @@ -10127,14 +7490,6 @@ snapshots: - supports-color optional: true - '@babel/plugin-transform-modules-umd@7.24.7(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-module-transforms': 7.25.0(@babel/core@7.24.9) - '@babel/helper-plugin-utils': 7.24.8 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-named-capturing-groups-regex@7.24.7(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 @@ -10142,35 +7497,18 @@ snapshots: '@babel/helper-plugin-utils': 7.24.8 optional: true - '@babel/plugin-transform-named-capturing-groups-regex@7.24.7(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-create-regexp-features-plugin': 7.25.0(@babel/core@7.24.9) - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-new-target@7.24.7(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 '@babel/helper-plugin-utils': 7.24.8 optional: true - '@babel/plugin-transform-new-target@7.24.7(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-nullish-coalescing-operator@7.24.7(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.8) - '@babel/plugin-transform-nullish-coalescing-operator@7.24.7(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.9) - '@babel/plugin-transform-numeric-separator@7.24.7(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 @@ -10178,12 +7516,6 @@ snapshots: '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.8) optional: true - '@babel/plugin-transform-numeric-separator@7.24.7(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.9) - '@babel/plugin-transform-object-rest-spread@7.24.7(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 @@ -10193,14 +7525,6 @@ snapshots: '@babel/plugin-transform-parameters': 7.24.7(@babel/core@7.24.8) optional: true - '@babel/plugin-transform-object-rest-spread@7.24.7(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-compilation-targets': 7.24.8 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.9) - '@babel/plugin-transform-parameters': 7.24.7(@babel/core@7.24.9) - '@babel/plugin-transform-object-super@7.24.7(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 @@ -10210,14 +7534,6 @@ snapshots: - supports-color optional: true - '@babel/plugin-transform-object-super@7.24.7(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/helper-replace-supers': 7.25.0(@babel/core@7.24.9) - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-optional-catch-binding@7.24.7(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 @@ -10225,12 +7541,6 @@ snapshots: '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.8) optional: true - '@babel/plugin-transform-optional-catch-binding@7.24.7(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.9) - '@babel/plugin-transform-optional-chaining@7.24.7(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 @@ -10250,26 +7560,12 @@ snapshots: - supports-color optional: true - '@babel/plugin-transform-optional-chaining@7.24.8(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/helper-skip-transparent-expression-wrappers': 7.24.7 - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.9) - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-parameters@7.24.7(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 '@babel/helper-plugin-utils': 7.24.8 optional: true - '@babel/plugin-transform-parameters@7.24.7(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-private-methods@7.24.7(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 @@ -10278,46 +7574,23 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-private-methods@7.24.7(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-create-class-features-plugin': 7.24.7(@babel/core@7.24.9) - '@babel/helper-plugin-utils': 7.24.7 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-private-property-in-object@7.24.7(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 '@babel/helper-annotate-as-pure': 7.24.7 '@babel/helper-create-class-features-plugin': 7.24.7(@babel/core@7.24.8) - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.24.8) transitivePeerDependencies: - supports-color optional: true - '@babel/plugin-transform-private-property-in-object@7.24.7(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-annotate-as-pure': 7.24.7 - '@babel/helper-create-class-features-plugin': 7.24.7(@babel/core@7.24.9) - '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.24.9) - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-property-literals@7.24.7(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 '@babel/helper-plugin-utils': 7.24.8 optional: true - '@babel/plugin-transform-property-literals@7.24.7(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-regenerator@7.24.7(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 @@ -10325,46 +7598,18 @@ snapshots: regenerator-transform: 0.15.2 optional: true - '@babel/plugin-transform-regenerator@7.24.7(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-plugin-utils': 7.24.8 - regenerator-transform: 0.15.2 - '@babel/plugin-transform-reserved-words@7.24.7(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 '@babel/helper-plugin-utils': 7.24.8 optional: true - '@babel/plugin-transform-reserved-words@7.24.7(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-plugin-utils': 7.24.8 - - '@babel/plugin-transform-runtime@7.24.7(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-module-imports': 7.24.7 - '@babel/helper-plugin-utils': 7.24.7 - babel-plugin-polyfill-corejs2: 0.4.10(@babel/core@7.24.9) - babel-plugin-polyfill-corejs3: 0.10.4(@babel/core@7.24.9) - babel-plugin-polyfill-regenerator: 0.6.1(@babel/core@7.24.9) - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-shorthand-properties@7.24.7(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 '@babel/helper-plugin-utils': 7.24.8 optional: true - '@babel/plugin-transform-shorthand-properties@7.24.7(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-spread@7.24.7(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 @@ -10374,47 +7619,24 @@ snapshots: - supports-color optional: true - '@babel/plugin-transform-spread@7.24.7(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/helper-skip-transparent-expression-wrappers': 7.24.7 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-sticky-regex@7.24.7(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 '@babel/helper-plugin-utils': 7.24.8 optional: true - '@babel/plugin-transform-sticky-regex@7.24.7(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-template-literals@7.24.7(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 '@babel/helper-plugin-utils': 7.24.8 optional: true - '@babel/plugin-transform-template-literals@7.24.7(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-typeof-symbol@7.24.8(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 '@babel/helper-plugin-utils': 7.24.8 optional: true - '@babel/plugin-transform-typeof-symbol@7.24.8(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-typescript@7.24.7(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 @@ -10425,27 +7647,12 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-typescript@7.24.7(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-annotate-as-pure': 7.24.7 - '@babel/helper-create-class-features-plugin': 7.24.7(@babel/core@7.24.9) - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-typescript': 7.24.7(@babel/core@7.24.9) - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-unicode-escapes@7.24.7(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 '@babel/helper-plugin-utils': 7.24.8 optional: true - '@babel/plugin-transform-unicode-escapes@7.24.7(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-unicode-property-regex@7.24.7(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 @@ -10453,12 +7660,6 @@ snapshots: '@babel/helper-plugin-utils': 7.24.8 optional: true - '@babel/plugin-transform-unicode-property-regex@7.24.7(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-create-regexp-features-plugin': 7.25.0(@babel/core@7.24.9) - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-unicode-regex@7.24.7(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 @@ -10466,12 +7667,6 @@ snapshots: '@babel/helper-plugin-utils': 7.24.8 optional: true - '@babel/plugin-transform-unicode-regex@7.24.7(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-create-regexp-features-plugin': 7.25.0(@babel/core@7.24.9) - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-unicode-sets-regex@7.24.7(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 @@ -10479,12 +7674,6 @@ snapshots: '@babel/helper-plugin-utils': 7.24.8 optional: true - '@babel/plugin-transform-unicode-sets-regex@7.24.7(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-create-regexp-features-plugin': 7.25.0(@babel/core@7.24.9) - '@babel/helper-plugin-utils': 7.24.8 - '@babel/preset-env@7.25.0(@babel/core@7.24.8)': dependencies: '@babel/compat-data': 7.25.0 @@ -10575,116 +7764,20 @@ snapshots: - supports-color optional: true - '@babel/preset-env@7.25.0(@babel/core@7.24.9)': - dependencies: - '@babel/compat-data': 7.25.0 - '@babel/core': 7.24.9 - '@babel/helper-compilation-targets': 7.24.8 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/helper-validator-option': 7.24.8 - '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.25.0(@babel/core@7.24.9) - '@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.25.0(@babel/core@7.24.9) - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.25.0(@babel/core@7.24.9) - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.24.7(@babel/core@7.24.9) - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.25.0(@babel/core@7.24.9) - '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.24.9) - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.9) - '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.24.9) - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.24.9) - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.9) - '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.24.9) - '@babel/plugin-syntax-import-assertions': 7.24.7(@babel/core@7.24.9) - '@babel/plugin-syntax-import-attributes': 7.24.7(@babel/core@7.24.9) - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.24.9) - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.9) - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.9) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.9) - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.9) - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.9) - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.9) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.9) - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.24.9) - '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.24.9) - '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.24.9) - '@babel/plugin-transform-arrow-functions': 7.24.7(@babel/core@7.24.9) - '@babel/plugin-transform-async-generator-functions': 7.25.0(@babel/core@7.24.9) - '@babel/plugin-transform-async-to-generator': 7.24.7(@babel/core@7.24.9) - '@babel/plugin-transform-block-scoped-functions': 7.24.7(@babel/core@7.24.9) - '@babel/plugin-transform-block-scoping': 7.25.0(@babel/core@7.24.9) - '@babel/plugin-transform-class-properties': 7.24.7(@babel/core@7.24.9) - '@babel/plugin-transform-class-static-block': 7.24.7(@babel/core@7.24.9) - '@babel/plugin-transform-classes': 7.25.0(@babel/core@7.24.9) - '@babel/plugin-transform-computed-properties': 7.24.7(@babel/core@7.24.9) - '@babel/plugin-transform-destructuring': 7.24.8(@babel/core@7.24.9) - '@babel/plugin-transform-dotall-regex': 7.24.7(@babel/core@7.24.9) - '@babel/plugin-transform-duplicate-keys': 7.24.7(@babel/core@7.24.9) - '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.25.0(@babel/core@7.24.9) - '@babel/plugin-transform-dynamic-import': 7.24.7(@babel/core@7.24.9) - '@babel/plugin-transform-exponentiation-operator': 7.24.7(@babel/core@7.24.9) - '@babel/plugin-transform-export-namespace-from': 7.24.7(@babel/core@7.24.9) - '@babel/plugin-transform-for-of': 7.24.7(@babel/core@7.24.9) - '@babel/plugin-transform-function-name': 7.25.1(@babel/core@7.24.9) - '@babel/plugin-transform-json-strings': 7.24.7(@babel/core@7.24.9) - '@babel/plugin-transform-literals': 7.24.7(@babel/core@7.24.9) - '@babel/plugin-transform-logical-assignment-operators': 7.24.7(@babel/core@7.24.9) - '@babel/plugin-transform-member-expression-literals': 7.24.7(@babel/core@7.24.9) - '@babel/plugin-transform-modules-amd': 7.24.7(@babel/core@7.24.9) - '@babel/plugin-transform-modules-commonjs': 7.24.8(@babel/core@7.24.9) - '@babel/plugin-transform-modules-systemjs': 7.25.0(@babel/core@7.24.9) - '@babel/plugin-transform-modules-umd': 7.24.7(@babel/core@7.24.9) - '@babel/plugin-transform-named-capturing-groups-regex': 7.24.7(@babel/core@7.24.9) - '@babel/plugin-transform-new-target': 7.24.7(@babel/core@7.24.9) - '@babel/plugin-transform-nullish-coalescing-operator': 7.24.7(@babel/core@7.24.9) - '@babel/plugin-transform-numeric-separator': 7.24.7(@babel/core@7.24.9) - '@babel/plugin-transform-object-rest-spread': 7.24.7(@babel/core@7.24.9) - '@babel/plugin-transform-object-super': 7.24.7(@babel/core@7.24.9) - '@babel/plugin-transform-optional-catch-binding': 7.24.7(@babel/core@7.24.9) - '@babel/plugin-transform-optional-chaining': 7.24.8(@babel/core@7.24.9) - '@babel/plugin-transform-parameters': 7.24.7(@babel/core@7.24.9) - '@babel/plugin-transform-private-methods': 7.24.7(@babel/core@7.24.9) - '@babel/plugin-transform-private-property-in-object': 7.24.7(@babel/core@7.24.9) - '@babel/plugin-transform-property-literals': 7.24.7(@babel/core@7.24.9) - '@babel/plugin-transform-regenerator': 7.24.7(@babel/core@7.24.9) - '@babel/plugin-transform-reserved-words': 7.24.7(@babel/core@7.24.9) - '@babel/plugin-transform-shorthand-properties': 7.24.7(@babel/core@7.24.9) - '@babel/plugin-transform-spread': 7.24.7(@babel/core@7.24.9) - '@babel/plugin-transform-sticky-regex': 7.24.7(@babel/core@7.24.9) - '@babel/plugin-transform-template-literals': 7.24.7(@babel/core@7.24.9) - '@babel/plugin-transform-typeof-symbol': 7.24.8(@babel/core@7.24.9) - '@babel/plugin-transform-unicode-escapes': 7.24.7(@babel/core@7.24.9) - '@babel/plugin-transform-unicode-property-regex': 7.24.7(@babel/core@7.24.9) - '@babel/plugin-transform-unicode-regex': 7.24.7(@babel/core@7.24.9) - '@babel/plugin-transform-unicode-sets-regex': 7.24.7(@babel/core@7.24.9) - '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.24.9) - babel-plugin-polyfill-corejs2: 0.4.10(@babel/core@7.24.9) - babel-plugin-polyfill-corejs3: 0.10.4(@babel/core@7.24.9) - babel-plugin-polyfill-regenerator: 0.6.1(@babel/core@7.24.9) - core-js-compat: 3.37.1 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - '@babel/preset-flow@7.24.7(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 '@babel/helper-plugin-utils': 7.24.8 '@babel/helper-validator-option': 7.24.8 - '@babel/plugin-transform-flow-strip-types': 7.24.7(@babel/core@7.24.8) - - '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.24.8)': - dependencies: - '@babel/core': 7.24.8 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/types': 7.25.0 - esutils: 2.0.3 - optional: true + '@babel/plugin-transform-flow-strip-types': 7.24.7(@babel/core@7.24.8) - '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.24.9)': + '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.24.8)': dependencies: - '@babel/core': 7.24.9 + '@babel/core': 7.24.8 '@babel/helper-plugin-utils': 7.24.8 '@babel/types': 7.25.0 esutils: 2.0.3 + optional: true '@babel/preset-typescript@7.24.7(@babel/core@7.24.8)': dependencies: @@ -10697,17 +7790,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/preset-typescript@7.24.7(@babel/core@7.24.9)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-plugin-utils': 7.24.7 - '@babel/helper-validator-option': 7.24.7 - '@babel/plugin-syntax-jsx': 7.24.7(@babel/core@7.24.9) - '@babel/plugin-transform-modules-commonjs': 7.24.7(@babel/core@7.24.9) - '@babel/plugin-transform-typescript': 7.24.7(@babel/core@7.24.9) - transitivePeerDependencies: - - supports-color - '@babel/register@7.24.6(@babel/core@7.24.8)': dependencies: '@babel/core': 7.24.8 @@ -10717,7 +7799,8 @@ snapshots: pirates: 4.0.6 source-map-support: 0.5.21 - '@babel/regjsgen@0.8.0': {} + '@babel/regjsgen@0.8.0': + optional: true '@babel/runtime@7.24.8': dependencies: @@ -10957,120 +8040,6 @@ snapshots: human-id: 1.0.2 prettier: 2.8.8 - '@colors/colors@1.5.0': - optional: true - - '@commitlint/cli@19.3.0(@types/node@22.0.0)(typescript@5.5.4)': - dependencies: - '@commitlint/format': 19.3.0 - '@commitlint/lint': 19.2.2 - '@commitlint/load': 19.2.0(@types/node@22.0.0)(typescript@5.5.4) - '@commitlint/read': 19.2.1 - '@commitlint/types': 19.0.3 - execa: 8.0.1 - yargs: 17.7.2 - transitivePeerDependencies: - - '@types/node' - - typescript - - '@commitlint/config-conventional@19.2.2': - dependencies: - '@commitlint/types': 19.0.3 - conventional-changelog-conventionalcommits: 8.0.0 - - '@commitlint/config-validator@19.0.3': - dependencies: - '@commitlint/types': 19.0.3 - ajv: 8.12.0 - - '@commitlint/ensure@19.0.3': - dependencies: - '@commitlint/types': 19.0.3 - lodash.camelcase: 4.3.0 - lodash.kebabcase: 4.1.1 - lodash.snakecase: 4.1.1 - lodash.startcase: 4.4.0 - lodash.upperfirst: 4.3.1 - - '@commitlint/execute-rule@19.0.0': {} - - '@commitlint/format@19.3.0': - dependencies: - '@commitlint/types': 19.0.3 - chalk: 5.3.0 - - '@commitlint/is-ignored@19.2.2': - dependencies: - '@commitlint/types': 19.0.3 - semver: 7.6.0 - - '@commitlint/lint@19.2.2': - dependencies: - '@commitlint/is-ignored': 19.2.2 - '@commitlint/parse': 19.0.3 - '@commitlint/rules': 19.0.3 - '@commitlint/types': 19.0.3 - - '@commitlint/load@19.2.0(@types/node@22.0.0)(typescript@5.5.4)': - dependencies: - '@commitlint/config-validator': 19.0.3 - '@commitlint/execute-rule': 19.0.0 - '@commitlint/resolve-extends': 19.1.0 - '@commitlint/types': 19.0.3 - chalk: 5.3.0 - cosmiconfig: 9.0.0(typescript@5.5.4) - cosmiconfig-typescript-loader: 5.0.0(@types/node@22.0.0)(cosmiconfig@9.0.0(typescript@5.5.4))(typescript@5.5.4) - lodash.isplainobject: 4.0.6 - lodash.merge: 4.6.2 - lodash.uniq: 4.5.0 - transitivePeerDependencies: - - '@types/node' - - typescript - - '@commitlint/message@19.0.0': {} - - '@commitlint/parse@19.0.3': - dependencies: - '@commitlint/types': 19.0.3 - conventional-changelog-angular: 7.0.0 - conventional-commits-parser: 5.0.0 - - '@commitlint/read@19.2.1': - dependencies: - '@commitlint/top-level': 19.0.0 - '@commitlint/types': 19.0.3 - execa: 8.0.1 - git-raw-commits: 4.0.0 - minimist: 1.2.8 - - '@commitlint/resolve-extends@19.1.0': - dependencies: - '@commitlint/config-validator': 19.0.3 - '@commitlint/types': 19.0.3 - global-directory: 4.0.1 - import-meta-resolve: 4.0.0 - lodash.mergewith: 4.6.2 - resolve-from: 5.0.0 - - '@commitlint/rules@19.0.3': - dependencies: - '@commitlint/ensure': 19.0.3 - '@commitlint/message': 19.0.0 - '@commitlint/to-lines': 19.0.0 - '@commitlint/types': 19.0.3 - execa: 8.0.1 - - '@commitlint/to-lines@19.0.0': {} - - '@commitlint/top-level@19.0.0': - dependencies: - find-up: 7.0.0 - - '@commitlint/types@19.0.3': - dependencies: - '@types/conventional-commits-parser': 5.0.0 - chalk: 5.3.0 - '@cspotcode/source-map-support@0.8.1': dependencies: '@jridgewell/trace-mapping': 0.3.9 @@ -11258,12 +8227,6 @@ snapshots: '@floating-ui/utils@0.2.3': {} - '@graphql-tools/merge@8.3.1(graphql@15.8.0)': - dependencies: - '@graphql-tools/utils': 8.9.0(graphql@15.8.0) - graphql: 15.8.0 - tslib: 2.6.3 - '@graphql-tools/merge@9.0.3(graphql@16.9.0)': dependencies: '@graphql-tools/utils': 10.2.1(graphql@16.9.0) @@ -11278,14 +8241,6 @@ snapshots: tslib: 2.6.3 value-or-promise: 1.0.12 - '@graphql-tools/schema@8.5.1(graphql@15.8.0)': - dependencies: - '@graphql-tools/merge': 8.3.1(graphql@15.8.0) - '@graphql-tools/utils': 8.9.0(graphql@15.8.0) - graphql: 15.8.0 - tslib: 2.6.3 - value-or-promise: 1.0.11 - '@graphql-tools/utils@10.2.1(graphql@16.9.0)': dependencies: '@graphql-typed-document-node/core': 3.2.0(graphql@16.9.0) @@ -11294,16 +8249,6 @@ snapshots: graphql: 16.9.0 tslib: 2.6.3 - '@graphql-tools/utils@8.13.1(graphql@15.8.0)': - dependencies: - graphql: 15.8.0 - tslib: 2.6.3 - - '@graphql-tools/utils@8.9.0(graphql@15.8.0)': - dependencies: - graphql: 15.8.0 - tslib: 2.6.3 - '@graphql-typed-document-node/core@3.2.0(graphql@16.9.0)': dependencies: graphql: 16.9.0 @@ -11314,36 +8259,6 @@ snapshots: dependencies: '@hapi/hoek': 9.3.0 - '@httptoolkit/httpolyglot@2.2.1': - dependencies: - '@types/node': 22.0.0 - - '@httptoolkit/subscriptions-transport-ws@0.11.2(bufferutil@4.0.8)(graphql@15.8.0)(utf-8-validate@5.0.10)': - dependencies: - backo2: 1.0.2 - eventemitter3: 3.1.2 - graphql: 15.8.0 - iterall: 1.3.0 - symbol-observable: 1.2.0 - ws: 8.14.2(bufferutil@4.0.8)(utf-8-validate@5.0.10) - transitivePeerDependencies: - - bufferutil - - utf-8-validate - - '@httptoolkit/websocket-stream@6.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10)': - dependencies: - '@types/ws': 8.5.12 - duplexify: 3.7.1 - inherits: 2.0.4 - isomorphic-ws: 4.0.1(ws@8.14.2(bufferutil@4.0.8)(utf-8-validate@5.0.10)) - readable-stream: 2.3.8 - safe-buffer: 5.2.1 - ws: 8.14.2(bufferutil@4.0.8)(utf-8-validate@5.0.10) - xtend: 4.0.2 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - '@humanwhocodes/config-array@0.11.14': dependencies: '@humanwhocodes/object-schema': 2.0.2 @@ -11707,6 +8622,7 @@ snapshots: dependencies: '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 + optional: true '@jridgewell/sourcemap-codec@1.4.15': {} @@ -11756,81 +8672,11 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.15.0 - '@octokit/auth-token@5.1.1': {} - - '@octokit/core@6.1.2': - dependencies: - '@octokit/auth-token': 5.1.1 - '@octokit/graphql': 8.1.1 - '@octokit/request': 9.1.1 - '@octokit/request-error': 6.1.1 - '@octokit/types': 13.4.1 - before-after-hook: 3.0.2 - universal-user-agent: 7.0.2 - - '@octokit/endpoint@10.1.1': - dependencies: - '@octokit/types': 13.4.1 - universal-user-agent: 7.0.2 - - '@octokit/graphql@8.1.1': - dependencies: - '@octokit/request': 9.1.1 - '@octokit/types': 13.4.1 - universal-user-agent: 7.0.2 - - '@octokit/openapi-types@22.1.0': {} - - '@octokit/plugin-paginate-rest@11.1.1(@octokit/core@6.1.2)': - dependencies: - '@octokit/core': 6.1.2 - '@octokit/types': 13.4.1 - - '@octokit/plugin-retry@7.1.0(@octokit/core@6.1.2)': - dependencies: - '@octokit/core': 6.1.2 - '@octokit/request-error': 6.1.1 - '@octokit/types': 13.4.1 - bottleneck: 2.19.5 - - '@octokit/plugin-throttling@9.2.0(@octokit/core@6.1.2)': - dependencies: - '@octokit/core': 6.1.2 - '@octokit/types': 13.4.1 - bottleneck: 2.19.5 - - '@octokit/request-error@6.1.1': - dependencies: - '@octokit/types': 13.4.1 - - '@octokit/request@9.1.1': - dependencies: - '@octokit/endpoint': 10.1.1 - '@octokit/request-error': 6.1.1 - '@octokit/types': 13.4.1 - universal-user-agent: 7.0.2 - - '@octokit/types@13.4.1': - dependencies: - '@octokit/openapi-types': 22.1.0 - '@pkgjs/parseargs@0.11.0': optional: true '@pkgr/core@0.1.1': {} - '@pnpm/config.env-replace@1.1.0': {} - - '@pnpm/network.ca-file@1.0.2': - dependencies: - graceful-fs: 4.2.10 - - '@pnpm/npm-conf@2.2.2': - dependencies: - '@pnpm/config.env-replace': 1.1.0 - '@pnpm/network.ca-file': 1.0.2 - config-chain: 1.1.13 - '@radix-ui/colors@3.0.0': {} '@radix-ui/number@1.1.0': {} @@ -12480,84 +9326,10 @@ snapshots: '@types/react': 18.3.3 '@types/react-dom': 18.3.0 - '@rollup/plugin-alias@5.1.0(rollup@4.19.0)': - dependencies: - slash: 4.0.0 - optionalDependencies: - rollup: 4.19.0 - - '@rollup/plugin-babel@6.0.4(@babel/core@7.24.9)(@types/babel__core@7.20.1)(rollup@4.19.0)': - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-module-imports': 7.22.15 - '@rollup/pluginutils': 5.1.0(rollup@4.19.0) - optionalDependencies: - '@types/babel__core': 7.20.1 - rollup: 4.19.0 - - '@rollup/plugin-commonjs@26.0.1(rollup@4.19.0)': - dependencies: - '@rollup/pluginutils': 5.1.0(rollup@4.19.0) - commondir: 1.0.1 - estree-walker: 2.0.2 - glob: 10.4.1 - is-reference: 1.2.1 - magic-string: 0.30.10 - optionalDependencies: - rollup: 4.19.0 - - '@rollup/plugin-json@6.1.0(rollup@4.19.0)': - dependencies: - '@rollup/pluginutils': 5.1.0(rollup@4.19.0) - optionalDependencies: - rollup: 4.19.0 - - '@rollup/plugin-node-resolve@15.2.3(rollup@4.19.0)': - dependencies: - '@rollup/pluginutils': 5.0.2(rollup@4.19.0) - '@types/resolve': 1.20.2 - deepmerge: 4.3.1 - is-builtin-module: 3.2.1 - is-module: 1.0.0 - resolve: 1.22.8 - optionalDependencies: - rollup: 4.19.0 - - '@rollup/plugin-replace@5.0.7(rollup@4.19.0)': - dependencies: - '@rollup/pluginutils': 5.1.0(rollup@4.19.0) - magic-string: 0.30.10 - optionalDependencies: - rollup: 4.19.0 - - '@rollup/plugin-terser@0.4.4(rollup@4.19.0)': - dependencies: - serialize-javascript: 6.0.1 - smob: 1.4.0 - terser: 5.18.0 - optionalDependencies: - rollup: 4.19.0 - '@rollup/plugin-virtual@3.0.1(rollup@3.27.2)': optionalDependencies: rollup: 3.27.2 - '@rollup/pluginutils@5.0.2(rollup@4.19.0)': - dependencies: - '@types/estree': 1.0.5 - estree-walker: 2.0.2 - picomatch: 2.3.1 - optionalDependencies: - rollup: 4.19.0 - - '@rollup/pluginutils@5.1.0(rollup@4.19.0)': - dependencies: - '@types/estree': 1.0.5 - estree-walker: 2.0.2 - picomatch: 2.3.1 - optionalDependencies: - rollup: 4.19.0 - '@rollup/rollup-android-arm-eabi@4.19.0': optional: true @@ -12606,81 +9378,6 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.19.0': optional: true - '@sec-ant/readable-stream@0.4.1': {} - - '@semantic-release/commit-analyzer@13.0.0(semantic-release@24.0.0(typescript@5.5.4))': - dependencies: - conventional-changelog-angular: 8.0.0 - conventional-changelog-writer: 8.0.0 - conventional-commits-filter: 5.0.0 - conventional-commits-parser: 6.0.0 - debug: 4.3.5 - import-from-esm: 1.3.4 - lodash-es: 4.17.21 - micromatch: 4.0.7 - semantic-release: 24.0.0(typescript@5.5.4) - transitivePeerDependencies: - - supports-color - - '@semantic-release/error@4.0.0': {} - - '@semantic-release/github@10.0.5(semantic-release@24.0.0(typescript@5.5.4))': - dependencies: - '@octokit/core': 6.1.2 - '@octokit/plugin-paginate-rest': 11.1.1(@octokit/core@6.1.2) - '@octokit/plugin-retry': 7.1.0(@octokit/core@6.1.2) - '@octokit/plugin-throttling': 9.2.0(@octokit/core@6.1.2) - '@semantic-release/error': 4.0.0 - aggregate-error: 5.0.0 - debug: 4.3.5 - dir-glob: 3.0.1 - globby: 14.0.1 - http-proxy-agent: 7.0.0 - https-proxy-agent: 7.0.4 - issue-parser: 7.0.0 - lodash-es: 4.17.21 - mime: 4.0.1 - p-filter: 4.1.0 - semantic-release: 24.0.0(typescript@5.5.4) - url-join: 5.0.0 - transitivePeerDependencies: - - supports-color - - '@semantic-release/npm@12.0.1(semantic-release@24.0.0(typescript@5.5.4))': - dependencies: - '@semantic-release/error': 4.0.0 - aggregate-error: 5.0.0 - execa: 9.1.0 - fs-extra: 11.2.0 - lodash-es: 4.17.21 - nerf-dart: 1.0.0 - normalize-url: 8.0.0 - npm: 10.5.2 - rc: 1.2.8 - read-pkg: 9.0.1 - registry-auth-token: 5.0.2 - semantic-release: 24.0.0(typescript@5.5.4) - semver: 7.6.0 - tempy: 3.1.0 - - '@semantic-release/release-notes-generator@14.0.0(semantic-release@24.0.0(typescript@5.5.4))': - dependencies: - conventional-changelog-angular: 8.0.0 - conventional-changelog-writer: 8.0.0 - conventional-commits-filter: 5.0.0 - conventional-commits-parser: 6.0.0 - debug: 4.3.5 - get-stream: 7.0.1 - import-from-esm: 1.3.4 - into-stream: 7.0.0 - lodash-es: 4.17.21 - read-pkg-up: 11.0.0 - semantic-release: 24.0.0(typescript@5.5.4) - transitivePeerDependencies: - - supports-color - - '@shikijs/core@1.9.1': {} - '@sideway/address@4.1.5': dependencies: '@hapi/hoek': 9.3.0 @@ -12693,20 +9390,10 @@ snapshots: '@sinclair/typebox@0.32.18': {} - '@sindresorhus/is@4.6.0': {} - - '@sindresorhus/merge-streams@2.3.0': {} - - '@sindresorhus/merge-streams@4.0.0': {} - '@sinonjs/commons@1.8.6': dependencies: type-detect: 4.0.8 - '@sinonjs/commons@2.0.0': - dependencies: - type-detect: 4.0.8 - '@sinonjs/commons@3.0.1': dependencies: type-detect: 4.0.8 @@ -12719,14 +9406,6 @@ snapshots: dependencies: '@sinonjs/commons': 1.8.6 - '@sinonjs/samsam@8.0.0': - dependencies: - '@sinonjs/commons': 2.0.0 - lodash.get: 4.4.2 - type-detect: 4.0.8 - - '@sinonjs/text-encoding@0.7.2': {} - '@solana-program/memo@0.4.0(@solana/web3.js@packages+library)': dependencies: '@solana/web3.js': link:packages/library @@ -12764,6 +9443,28 @@ snapshots: '@wallet-standard/base': 0.0.0-20240607222957 '@wallet-standard/features': 1.0.3 + '@solana/web3.js@1.95.2(bufferutil@4.0.8)(utf-8-validate@5.0.10)': + dependencies: + '@babel/runtime': 7.25.0 + '@noble/curves': 1.4.2 + '@noble/hashes': 1.4.0 + '@solana/buffer-layout': 4.0.1 + agentkeepalive: 4.5.0 + bigint-buffer: 1.1.5 + bn.js: 5.2.1 + borsh: 0.7.0 + bs58: 4.0.1 + buffer: 6.0.3 + fast-stable-stringify: 1.0.0 + jayson: 4.1.1(bufferutil@4.0.8)(utf-8-validate@5.0.10) + node-fetch: 2.7.0 + rpc-websockets: 9.0.2 + superstruct: 2.0.2 + transitivePeerDependencies: + - bufferutil + - encoding + - utf-8-validate + '@swc/core-darwin-arm64@1.6.5': optional: true @@ -12830,8 +9531,6 @@ snapshots: '@tootallnate/once@2.0.0': {} - '@tootallnate/quickjs-emscripten@0.23.0': {} - '@tsconfig/node10@1.0.11': {} '@tsconfig/node12@1.0.11': {} @@ -12861,41 +9560,12 @@ snapshots: dependencies: '@babel/types': 7.25.0 - '@types/bn.js@5.1.5': - dependencies: - '@types/node': 18.19.21 - - '@types/bs58@4.0.1': - dependencies: - base-x: 3.0.9 - - '@types/chai-as-promised@7.1.8': - dependencies: - '@types/chai': 4.3.14 - - '@types/chai@4.3.14': {} - '@types/connect@3.4.35': dependencies: '@types/node': 22.0.0 - '@types/conventional-commits-parser@5.0.0': - dependencies: - '@types/node': 22.0.0 - - '@types/cors@2.8.17': - dependencies: - '@types/node': 22.0.0 - '@types/estree@1.0.5': {} - '@types/express-serve-static-core@4.19.5': - dependencies: - '@types/node': 18.19.21 - '@types/qs': 6.9.7 - '@types/range-parser': 1.2.4 - '@types/send': 0.17.1 - '@types/fastestsmallesttextencoderdecoder@1.0.2': {} '@types/fs-extra@11.0.4': @@ -12942,29 +9612,15 @@ snapshots: '@types/json-stable-stringify@1.0.36': {} - '@types/json5@0.0.29': {} - '@types/jsonfile@6.1.4': dependencies: '@types/node': 22.0.0 optional: true - '@types/mime@1.3.2': {} - - '@types/mocha@10.0.6': {} - '@types/mute-stream@0.0.4': dependencies: '@types/node': 22.0.0 - '@types/mz@2.7.4': - dependencies: - '@types/node': 18.19.21 - - '@types/node-fetch@2.1.0': - dependencies: - '@types/node': 18.19.21 - '@types/node@12.20.55': {} '@types/node@18.19.21': @@ -12980,50 +9636,26 @@ snapshots: dependencies: undici-types: 6.11.1 - '@types/normalize-package-data@2.4.4': {} - '@types/parse-json@4.0.0': {} '@types/prettier@2.7.3': {} '@types/prop-types@15.7.12': {} - '@types/qs@6.9.7': {} - - '@types/range-parser@1.2.4': {} - '@types/react-dom@18.3.0': dependencies: '@types/react': 18.3.3 - '@types/react-test-renderer@18.3.0': - dependencies: - '@types/react': 18.3.3 - - '@types/react@18.3.3': - dependencies: - '@types/prop-types': 15.7.12 - csstype: 3.1.3 - - '@types/resolve@1.20.2': {} - - '@types/semver@7.5.8': {} - - '@types/send@0.17.1': - dependencies: - '@types/mime': 1.3.2 - '@types/node': 22.0.0 - - '@types/sinon-chai@3.2.12': + '@types/react-test-renderer@18.3.0': dependencies: - '@types/chai': 4.3.14 - '@types/sinon': 17.0.3 + '@types/react': 18.3.3 - '@types/sinon@17.0.3': + '@types/react@18.3.3': dependencies: - '@types/sinonjs__fake-timers': 8.1.2 + '@types/prop-types': 15.7.12 + csstype: 3.1.3 - '@types/sinonjs__fake-timers@8.1.2': {} + '@types/semver@7.5.8': {} '@types/stack-utils@2.0.2': {} @@ -13039,10 +9671,6 @@ snapshots: dependencies: '@types/node': 22.0.0 - '@types/ws@8.5.11': - dependencies: - '@types/node': 22.0.0 - '@types/ws@8.5.12': dependencies: '@types/node': 22.0.0 @@ -13358,11 +9986,6 @@ snapshots: dependencies: event-target-shim: 5.0.1 - accepts@1.3.8: - dependencies: - mime-types: 2.1.35 - negotiator: 0.6.3 - acorn-jsx@5.3.2(acorn@7.4.1): dependencies: acorn: 7.4.1 @@ -13389,21 +10012,10 @@ snapshots: transitivePeerDependencies: - supports-color - agent-base@7.1.1: - dependencies: - debug: 4.3.5 - transitivePeerDependencies: - - supports-color - agentkeepalive@4.5.0: dependencies: humanize-ms: 1.2.1 - aggregate-error@5.0.0: - dependencies: - clean-stack: 5.2.0 - indent-string: 5.0.0 - ajv@6.12.6: dependencies: fast-deep-equal: 3.1.3 @@ -13411,15 +10023,6 @@ snapshots: json-schema-traverse: 0.4.1 uri-js: 4.4.1 - ajv@8.12.0: - dependencies: - fast-deep-equal: 3.1.3 - json-schema-traverse: 1.0.0 - require-from-string: 2.0.2 - uri-js: 4.4.1 - - ansi-colors@4.1.1: {} - ansi-colors@4.1.3: {} ansi-escapes@4.3.2: @@ -13463,69 +10066,12 @@ snapshots: argparse@2.0.1: {} - argv-formatter@1.0.0: {} - aria-hidden@1.2.4: dependencies: tslib: 2.6.3 - array-buffer-byte-length@1.0.0: - dependencies: - call-bind: 1.0.5 - is-array-buffer: 3.0.2 - - array-flatten@1.1.1: {} - - array-ify@1.0.0: {} - - array-includes@3.1.7: - dependencies: - call-bind: 1.0.5 - define-properties: 1.2.0 - es-abstract: 1.22.3 - get-intrinsic: 1.2.2 - is-string: 1.0.7 - array-union@2.1.0: {} - array.prototype.findlastindex@1.2.3: - dependencies: - call-bind: 1.0.5 - define-properties: 1.2.0 - es-abstract: 1.22.3 - es-shim-unscopables: 1.0.0 - get-intrinsic: 1.2.2 - - array.prototype.flat@1.3.2: - dependencies: - call-bind: 1.0.5 - define-properties: 1.2.0 - es-abstract: 1.22.3 - es-shim-unscopables: 1.0.0 - - array.prototype.flatmap@1.3.2: - dependencies: - call-bind: 1.0.5 - define-properties: 1.2.0 - es-abstract: 1.22.3 - es-shim-unscopables: 1.0.0 - - arraybuffer.prototype.slice@1.0.2: - dependencies: - array-buffer-byte-length: 1.0.0 - call-bind: 1.0.5 - define-properties: 1.2.0 - es-abstract: 1.22.3 - get-intrinsic: 1.2.2 - is-array-buffer: 3.0.2 - is-shared-array-buffer: 1.0.2 - - assertion-error@2.0.1: {} - - ast-types@0.13.4: - dependencies: - tslib: 2.6.3 - ast-types@0.14.2: dependencies: tslib: 2.6.3 @@ -13534,20 +10080,10 @@ snapshots: dependencies: tslib: 2.6.3 - async-mutex@0.5.0: - dependencies: - tslib: 2.6.3 - - async@2.6.4: - dependencies: - lodash: 4.17.21 - asynckit@0.4.0: {} atomic-sleep@1.0.0: {} - available-typed-arrays@1.0.5: {} - axios@1.6.8(debug@4.3.5): dependencies: follow-redirects: 1.15.6(debug@4.3.5) @@ -13596,15 +10132,6 @@ snapshots: - supports-color optional: true - babel-plugin-polyfill-corejs2@0.4.10(@babel/core@7.24.9): - dependencies: - '@babel/compat-data': 7.25.0 - '@babel/core': 7.24.9 - '@babel/helper-define-polyfill-provider': 0.6.1(@babel/core@7.24.9) - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - babel-plugin-polyfill-corejs3@0.10.4(@babel/core@7.24.8): dependencies: '@babel/core': 7.24.8 @@ -13614,14 +10141,6 @@ snapshots: - supports-color optional: true - babel-plugin-polyfill-corejs3@0.10.4(@babel/core@7.24.9): - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-define-polyfill-provider': 0.6.1(@babel/core@7.24.9) - core-js-compat: 3.37.1 - transitivePeerDependencies: - - supports-color - babel-plugin-polyfill-regenerator@0.6.1(@babel/core@7.24.8): dependencies: '@babel/core': 7.24.8 @@ -13630,13 +10149,6 @@ snapshots: - supports-color optional: true - babel-plugin-polyfill-regenerator@0.6.1(@babel/core@7.24.9): - dependencies: - '@babel/core': 7.24.9 - '@babel/helper-define-polyfill-provider': 0.6.1(@babel/core@7.24.9) - transitivePeerDependencies: - - supports-color - babel-preset-current-node-syntax@1.0.1(@babel/core@7.24.9): dependencies: '@babel/core': 7.24.9 @@ -13659,22 +10171,14 @@ snapshots: babel-plugin-jest-hoist: 30.0.0-alpha.5 babel-preset-current-node-syntax: 1.0.1(@babel/core@7.24.9) - backo2@1.0.2: {} - balanced-match@1.0.2: {} base-x@3.0.9: dependencies: safe-buffer: 5.2.1 - base64-arraybuffer@0.1.5: {} - base64-js@1.5.1: {} - basic-ftp@5.0.5: {} - - before-after-hook@3.0.2: {} - better-path-resolve@1.0.0: dependencies: is-windows: 1.0.2 @@ -13693,31 +10197,12 @@ snapshots: bn.js@5.2.1: {} - body-parser@1.20.2: - dependencies: - bytes: 3.1.2 - content-type: 1.0.5 - debug: 2.6.9 - depd: 2.0.0 - destroy: 1.2.0 - http-errors: 2.0.0 - iconv-lite: 0.4.24 - on-finished: 2.4.1 - qs: 6.11.0 - raw-body: 2.5.2 - type-is: 1.6.18 - unpipe: 1.0.0 - transitivePeerDependencies: - - supports-color - borsh@0.7.0: dependencies: bn.js: 5.2.1 bs58: 4.0.1 text-encoding-utf-8: 1.0.2 - bottleneck@2.19.5: {} - brace-expansion@1.1.11: dependencies: balanced-match: 1.0.2 @@ -13731,10 +10216,6 @@ snapshots: dependencies: fill-range: 7.1.1 - brotli-wasm@1.3.1: {} - - browser-stdout@1.3.1: {} - browserslist-to-esbuild@2.1.1(browserslist@4.23.2): dependencies: browserslist: 4.23.2 @@ -13767,19 +10248,13 @@ snapshots: node-gyp-build: 4.6.0 optional: true - builtin-modules@3.3.0: {} - bundle-require@5.0.0(esbuild@0.23.0): dependencies: esbuild: 0.23.0 load-tsconfig: 0.2.5 - bytes@3.1.2: {} - cac@6.7.14: {} - cacheable-lookup@6.1.0: {} - call-bind@1.0.5: dependencies: function-bind: 1.1.2 @@ -13794,19 +10269,6 @@ snapshots: caniuse-lite@1.0.30001641: {} - chai-as-promised@8.0.0(chai@5.1.1): - dependencies: - chai: 5.1.1 - check-error: 2.1.1 - - chai@5.1.1: - dependencies: - assertion-error: 2.0.1 - check-error: 2.1.1 - deep-eql: 5.0.1 - loupe: 3.1.0 - pathval: 2.0.0 - chalk@2.4.2: dependencies: ansi-styles: 3.2.1 @@ -13831,22 +10293,8 @@ snapshots: chardet@0.7.0: {} - check-error@2.1.1: {} - check-more-types@2.24.0: {} - chokidar@3.5.3: - dependencies: - anymatch: 3.1.3 - braces: 3.0.3 - glob-parent: 5.1.2 - is-binary-path: 2.1.0 - is-glob: 4.0.3 - normalize-path: 3.0.0 - readdirp: 3.6.0 - optionalDependencies: - fsevents: 2.3.3 - chokidar@3.6.0: dependencies: anymatch: 3.1.3 @@ -13867,37 +10315,12 @@ snapshots: classnames@2.3.2: {} - clean-stack@5.2.0: - dependencies: - escape-string-regexp: 5.0.0 - - cli-highlight@2.1.11: - dependencies: - chalk: 4.1.2 - highlight.js: 10.7.3 - mz: 2.7.0 - parse5: 5.1.1 - parse5-htmlparser2-tree-adapter: 6.0.1 - yargs: 16.2.0 - cli-spinners@2.9.2: {} - cli-table3@0.6.3: - dependencies: - string-width: 4.2.3 - optionalDependencies: - '@colors/colors': 1.5.0 - cli-width@4.1.0: {} client-only@0.0.1: {} - cliui@7.0.4: - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 7.0.0 - cliui@8.0.1: dependencies: string-width: 4.2.3 @@ -13940,109 +10363,20 @@ snapshots: commander@5.1.0: {} - commitlint@19.3.0(@types/node@22.0.0)(typescript@5.5.4): - dependencies: - '@commitlint/cli': 19.3.0(@types/node@22.0.0)(typescript@5.5.4) - '@commitlint/types': 19.0.3 - transitivePeerDependencies: - - '@types/node' - - typescript - - common-tags@1.8.2: {} - commondir@1.0.1: {} - compare-func@2.0.0: - dependencies: - array-ify: 1.0.0 - dot-prop: 5.3.0 - concat-map@0.0.1: {} - config-chain@1.1.13: - dependencies: - ini: 1.3.8 - proto-list: 1.2.4 - - connect@3.7.0: - dependencies: - debug: 2.6.9 - finalhandler: 1.1.2 - parseurl: 1.3.3 - utils-merge: 1.0.1 - transitivePeerDependencies: - - supports-color - consola@3.2.3: {} - content-disposition@0.5.4: - dependencies: - safe-buffer: 5.2.1 - - content-type@1.0.5: {} - - conventional-changelog-angular@7.0.0: - dependencies: - compare-func: 2.0.0 - - conventional-changelog-angular@8.0.0: - dependencies: - compare-func: 2.0.0 - - conventional-changelog-conventionalcommits@8.0.0: - dependencies: - compare-func: 2.0.0 - - conventional-changelog-writer@8.0.0: - dependencies: - '@types/semver': 7.5.8 - conventional-commits-filter: 5.0.0 - handlebars: 4.7.7 - meow: 13.2.0 - semver: 7.6.0 - - conventional-commits-filter@5.0.0: {} - - conventional-commits-parser@5.0.0: - dependencies: - JSONStream: 1.3.5 - is-text-path: 2.0.0 - meow: 12.1.1 - split2: 4.2.0 - - conventional-commits-parser@6.0.0: - dependencies: - meow: 13.2.0 - - convert-hrtime@5.0.0: {} - convert-source-map@1.9.0: {} convert-source-map@2.0.0: {} - cookie-signature@1.0.6: {} - - cookie@0.6.0: {} - core-js-compat@3.37.1: dependencies: browserslist: 4.23.2 - - core-util-is@1.0.3: {} - - cors-gate@1.1.3: {} - - cors@2.8.5: - dependencies: - object-assign: 4.1.1 - vary: 1.1.2 - - cosmiconfig-typescript-loader@5.0.0(@types/node@22.0.0)(cosmiconfig@9.0.0(typescript@5.5.4))(typescript@5.5.4): - dependencies: - '@types/node': 22.0.0 - cosmiconfig: 9.0.0(typescript@5.5.4) - jiti: 1.21.0 - typescript: 5.5.4 + optional: true cosmiconfig@7.1.0: dependencies: @@ -14052,15 +10386,6 @@ snapshots: path-type: 4.0.0 yaml: 1.10.2 - cosmiconfig@9.0.0(typescript@5.5.4): - dependencies: - env-paths: 2.2.1 - import-fresh: 3.3.0 - js-yaml: 4.1.0 - parse-json: 5.2.0 - optionalDependencies: - typescript: 5.5.4 - create-jest-runner@0.11.2: dependencies: chalk: 4.1.2 @@ -14075,16 +10400,6 @@ snapshots: create-require@1.1.1: {} - cross-env@7.0.3: - dependencies: - cross-spawn: 7.0.3 - - cross-fetch@3.1.8: - dependencies: - node-fetch: 2.7.0 - transitivePeerDependencies: - - encoding - cross-inspect@1.0.0: dependencies: tslib: 2.6.3 @@ -14101,10 +10416,6 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 - crypto-random-string@4.0.0: - dependencies: - type-fest: 1.4.0 - cssstyle@3.0.0: dependencies: rrweb-cssom: 0.6.0 @@ -14116,10 +10427,6 @@ snapshots: find-pkg: 0.1.2 fs-exists-sync: 0.1.0 - dargs@8.1.0: {} - - data-uri-to-buffer@6.0.2: {} - data-urls@4.0.0: dependencies: abab: 2.0.6 @@ -14132,34 +10439,18 @@ snapshots: dateformat@4.6.3: {} - debug@2.6.9: - dependencies: - ms: 2.0.0 - - debug@3.2.7: - dependencies: - ms: 2.1.3 - - debug@4.3.4(supports-color@8.1.1): + debug@4.3.4: dependencies: ms: 2.1.2 - optionalDependencies: - supports-color: 8.1.1 debug@4.3.5: dependencies: ms: 2.1.2 - decamelize@4.0.0: {} - decimal.js@10.4.3: {} dedent@1.5.1: {} - deep-eql@5.0.1: {} - - deep-extend@0.6.0: {} - deep-is@0.1.4: {} deepmerge@4.3.1: {} @@ -14170,29 +10461,10 @@ snapshots: gopd: 1.0.1 has-property-descriptors: 1.0.0 - define-properties@1.2.0: - dependencies: - has-property-descriptors: 1.0.0 - object-keys: 1.1.1 - - degenerator@5.0.1: - dependencies: - ast-types: 0.13.4 - escodegen: 2.1.0 - esprima: 4.0.1 - delay@5.0.0: {} delayed-stream@1.0.0: {} - depd@2.0.0: {} - - destroy@1.2.0: {} - - destroyable-server@1.0.2: - dependencies: - '@types/node': 22.0.0 - detect-indent@6.1.0: {} detect-newline@3.1.0: {} @@ -14207,18 +10479,10 @@ snapshots: diff@4.0.2: {} - diff@5.0.0: {} - - diff@5.2.0: {} - dir-glob@3.0.1: dependencies: path-type: 4.0.0 - doctrine@2.1.0: - dependencies: - esutils: 2.0.3 - doctrine@3.0.0: dependencies: esutils: 2.0.3 @@ -14227,10 +10491,6 @@ snapshots: dependencies: webidl-conversions: 7.0.0 - dot-prop@5.3.0: - dependencies: - is-obj: 2.0.0 - dot-prop@6.0.1: dependencies: is-obj: 2.0.0 @@ -14241,23 +10501,10 @@ snapshots: dset@3.1.3: {} - duplexer2@0.1.4: - dependencies: - readable-stream: 2.3.8 - duplexer@0.1.2: {} - duplexify@3.7.1: - dependencies: - end-of-stream: 1.4.4 - inherits: 2.0.4 - readable-stream: 2.3.8 - stream-shift: 1.0.3 - eastasianwidth@0.2.0: {} - ee-first@1.1.1: {} - electron-to-chromium@1.4.827: {} emittery@0.13.1: {} @@ -14268,16 +10515,12 @@ snapshots: emoji-regex@9.2.2: {} - emojilib@2.4.0: {} - emphasize@5.0.0: dependencies: chalk: 4.1.2 highlight.js: 11.0.1 lowlight: 2.0.1 - encodeurl@1.0.2: {} - end-of-stream@1.4.4: dependencies: once: 1.4.0 @@ -14285,78 +10528,13 @@ snapshots: enquirer@2.4.1: dependencies: ansi-colors: 4.1.3 - strip-ansi: 6.0.1 - - entities@4.5.0: {} - - env-ci@11.0.0: - dependencies: - execa: 8.0.1 - java-properties: 1.0.2 - - env-paths@2.2.1: {} - - error-ex@1.3.2: - dependencies: - is-arrayish: 0.2.1 - - es-abstract@1.22.3: - dependencies: - array-buffer-byte-length: 1.0.0 - arraybuffer.prototype.slice: 1.0.2 - available-typed-arrays: 1.0.5 - call-bind: 1.0.5 - es-set-tostringtag: 2.0.1 - es-to-primitive: 1.2.1 - function.prototype.name: 1.1.6 - get-intrinsic: 1.2.2 - get-symbol-description: 1.0.0 - globalthis: 1.0.3 - gopd: 1.0.1 - has-property-descriptors: 1.0.0 - has-proto: 1.0.1 - has-symbols: 1.0.3 - hasown: 2.0.0 - internal-slot: 1.0.5 - is-array-buffer: 3.0.2 - is-callable: 1.2.7 - is-negative-zero: 2.0.2 - is-regex: 1.1.4 - is-shared-array-buffer: 1.0.2 - is-string: 1.0.7 - is-typed-array: 1.1.12 - is-weakref: 1.0.2 - object-inspect: 1.13.1 - object-keys: 1.1.1 - object.assign: 4.1.4 - regexp.prototype.flags: 1.5.1 - safe-array-concat: 1.0.1 - safe-regex-test: 1.0.0 - string.prototype.trim: 1.2.8 - string.prototype.trimend: 1.0.7 - string.prototype.trimstart: 1.0.7 - typed-array-buffer: 1.0.0 - typed-array-byte-length: 1.0.0 - typed-array-byte-offset: 1.0.0 - typed-array-length: 1.0.4 - unbox-primitive: 1.0.2 - which-typed-array: 1.1.13 - - es-set-tostringtag@2.0.1: - dependencies: - get-intrinsic: 1.2.2 - has: 1.0.3 - has-tostringtag: 1.0.0 + strip-ansi: 6.0.1 - es-shim-unscopables@1.0.0: - dependencies: - has: 1.0.3 + entities@4.5.0: {} - es-to-primitive@1.2.1: + error-ex@1.3.2: dependencies: - is-callable: 1.2.7 - is-date-object: 1.0.5 - is-symbol: 1.0.4 + is-arrayish: 0.2.1 es6-promise@4.2.8: {} @@ -14421,78 +10599,17 @@ snapshots: escalade@3.1.2: {} - escape-html@1.0.3: {} - escape-string-regexp@1.0.5: {} escape-string-regexp@2.0.0: {} escape-string-regexp@4.0.0: {} - escape-string-regexp@5.0.0: {} - - escodegen@2.1.0: - dependencies: - esprima: 4.0.1 - estraverse: 5.3.0 - esutils: 2.0.3 - optionalDependencies: - source-map: 0.6.1 - - eslint-config-prettier@9.1.0(eslint@8.57.0): - dependencies: - eslint: 8.57.0 - eslint-config-turbo@2.0.9(eslint@8.57.0): dependencies: eslint: 8.57.0 eslint-plugin-turbo: 2.0.9(eslint@8.57.0) - eslint-import-resolver-node@0.3.9: - dependencies: - debug: 3.2.7 - is-core-module: 2.13.1 - resolve: 1.22.8 - transitivePeerDependencies: - - supports-color - - eslint-module-utils@2.8.0(@typescript-eslint/parser@7.17.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint@8.57.0): - dependencies: - debug: 3.2.7 - optionalDependencies: - '@typescript-eslint/parser': 7.17.0(eslint@8.57.0)(typescript@5.5.4) - eslint: 8.57.0 - eslint-import-resolver-node: 0.3.9 - transitivePeerDependencies: - - supports-color - - eslint-plugin-import@2.29.0(@typescript-eslint/parser@7.17.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0): - dependencies: - array-includes: 3.1.7 - array.prototype.findlastindex: 1.2.3 - array.prototype.flat: 1.3.2 - array.prototype.flatmap: 1.3.2 - debug: 3.2.7 - doctrine: 2.1.0 - eslint: 8.57.0 - eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@7.17.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint@8.57.0) - hasown: 2.0.0 - is-core-module: 2.13.1 - is-glob: 4.0.3 - minimatch: 3.1.2 - object.fromentries: 2.0.7 - object.groupby: 1.0.1 - object.values: 1.1.7 - semver: 6.3.1 - tsconfig-paths: 3.14.2 - optionalDependencies: - '@typescript-eslint/parser': 7.17.0(eslint@8.57.0)(typescript@5.5.4) - transitivePeerDependencies: - - eslint-import-resolver-typescript - - eslint-import-resolver-webpack - - supports-color - eslint-plugin-jest@27.9.0(@typescript-eslint/eslint-plugin@7.16.1(@typescript-eslint/parser@7.17.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(jest@30.0.0-alpha.5(@types/node@22.0.0)(ts-node@10.9.2(@swc/core@1.6.5(@swc/helpers@0.5.11))(@types/node@22.0.0)(typescript@5.5.4)))(typescript@5.5.4): dependencies: '@typescript-eslint/utils': 5.61.0(eslint@8.57.0)(typescript@5.5.4) @@ -14504,22 +10621,6 @@ snapshots: - supports-color - typescript - eslint-plugin-mocha@10.4.3(eslint@8.57.0): - dependencies: - eslint: 8.57.0 - eslint-utils: 3.0.0(eslint@8.57.0) - globals: 13.24.0 - rambda: 7.5.0 - - eslint-plugin-prettier@5.2.1(eslint-config-prettier@9.1.0(eslint@8.57.0))(eslint@8.57.0)(prettier@3.3.1): - dependencies: - eslint: 8.57.0 - prettier: 3.3.1 - prettier-linter-helpers: 1.0.0 - synckit: 0.9.1 - optionalDependencies: - eslint-config-prettier: 9.1.0(eslint@8.57.0) - eslint-plugin-react-hooks@4.6.2(eslint@8.57.0): dependencies: eslint: 8.57.0 @@ -14565,15 +10666,8 @@ snapshots: esrecurse: 4.3.0 estraverse: 5.3.0 - eslint-utils@3.0.0(eslint@8.57.0): - dependencies: - eslint: 8.57.0 - eslint-visitor-keys: 2.1.0 - eslint-visitor-keys@1.3.0: {} - eslint-visitor-keys@2.1.0: {} - eslint-visitor-keys@3.4.3: {} eslint@8.57.0: @@ -14589,7 +10683,7 @@ snapshots: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.3 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.4 doctrine: 3.0.0 escape-string-regexp: 4.0.0 eslint-scope: 7.2.2 @@ -14619,8 +10713,6 @@ snapshots: transitivePeerDependencies: - supports-color - esm@3.2.25: {} - espree@6.2.1: dependencies: acorn: 7.4.1 @@ -14647,14 +10739,8 @@ snapshots: estraverse@5.3.0: {} - estree-walker@0.6.1: {} - - estree-walker@2.0.2: {} - esutils@2.0.3: {} - etag@1.8.1: {} - event-stream@3.3.4: dependencies: duplexer: 0.1.2 @@ -14667,8 +10753,6 @@ snapshots: event-target-shim@5.0.1: {} - eventemitter3@3.1.2: {} - eventemitter3@5.0.1: {} events@3.3.0: {} @@ -14685,33 +10769,6 @@ snapshots: signal-exit: 3.0.7 strip-final-newline: 2.0.0 - execa@8.0.1: - dependencies: - cross-spawn: 7.0.3 - get-stream: 8.0.1 - human-signals: 5.0.0 - is-stream: 3.0.0 - merge-stream: 2.0.0 - npm-run-path: 5.3.0 - onetime: 6.0.0 - signal-exit: 4.1.0 - strip-final-newline: 3.0.0 - - execa@9.1.0: - dependencies: - '@sindresorhus/merge-streams': 4.0.0 - cross-spawn: 7.0.3 - figures: 6.1.0 - get-stream: 9.0.1 - human-signals: 7.0.0 - is-plain-obj: 4.1.0 - is-stream: 4.0.1 - npm-run-path: 5.3.0 - pretty-ms: 9.0.0 - signal-exit: 4.1.0 - strip-final-newline: 4.0.0 - yoctocolors: 2.0.2 - exit@0.1.2: {} expand-tilde@1.2.2: @@ -14741,42 +10798,6 @@ snapshots: jest-message-util: 30.0.0-alpha.5 jest-util: 30.0.0-alpha.5 - express@4.19.2: - dependencies: - accepts: 1.3.8 - array-flatten: 1.1.1 - body-parser: 1.20.2 - content-disposition: 0.5.4 - content-type: 1.0.5 - cookie: 0.6.0 - cookie-signature: 1.0.6 - debug: 2.6.9 - depd: 2.0.0 - encodeurl: 1.0.2 - escape-html: 1.0.3 - etag: 1.8.1 - finalhandler: 1.2.0 - fresh: 0.5.2 - http-errors: 2.0.0 - merge-descriptors: 1.0.1 - methods: 1.1.2 - on-finished: 2.4.1 - parseurl: 1.3.3 - path-to-regexp: 0.1.7 - proxy-addr: 2.0.7 - qs: 6.11.0 - range-parser: 1.2.1 - safe-buffer: 5.2.1 - send: 0.18.0 - serve-static: 1.15.0 - setprototypeof: 1.2.0 - statuses: 2.0.1 - type-is: 1.6.18 - utils-merge: 1.0.1 - vary: 1.1.2 - transitivePeerDependencies: - - supports-color - extendable-error@0.1.7: {} external-editor@3.1.0: @@ -14791,8 +10812,6 @@ snapshots: fast-deep-equal@3.1.3: {} - fast-diff@1.3.0: {} - fast-glob@3.3.2: dependencies: '@nodelib/fs.stat': 2.0.5 @@ -14801,8 +10820,6 @@ snapshots: merge2: 1.4.1 micromatch: 4.0.7 - fast-json-patch@3.1.1: {} - fast-json-stable-stringify@2.1.0: {} fast-levenshtein@2.0.6: {} @@ -14827,14 +10844,6 @@ snapshots: dependencies: bser: 2.1.1 - figures@2.0.0: - dependencies: - escape-string-regexp: 1.0.5 - - figures@6.1.0: - dependencies: - is-unicode-supported: 2.0.0 - file-entry-cache@6.0.1: dependencies: flat-cache: 3.0.4 @@ -14845,30 +10854,6 @@ snapshots: dependencies: to-regex-range: 5.0.1 - finalhandler@1.1.2: - dependencies: - debug: 2.6.9 - encodeurl: 1.0.2 - escape-html: 1.0.3 - on-finished: 2.3.0 - parseurl: 1.3.3 - statuses: 1.5.0 - unpipe: 1.0.0 - transitivePeerDependencies: - - supports-color - - finalhandler@1.2.0: - dependencies: - debug: 2.6.9 - encodeurl: 1.0.2 - escape-html: 1.0.3 - on-finished: 2.4.1 - parseurl: 1.3.3 - statuses: 2.0.1 - unpipe: 1.0.0 - transitivePeerDependencies: - - supports-color - find-cache-dir@2.1.0: dependencies: commondir: 1.0.1 @@ -14892,12 +10877,6 @@ snapshots: transitivePeerDependencies: - supports-color - find-up-simple@1.0.0: {} - - find-up@2.1.0: - dependencies: - locate-path: 2.0.0 - find-up@3.0.0: dependencies: locate-path: 3.0.0 @@ -14912,17 +10891,6 @@ snapshots: locate-path: 6.0.0 path-exists: 4.0.0 - find-up@7.0.0: - dependencies: - locate-path: 7.2.0 - path-exists: 5.0.0 - unicorn-magic: 0.1.0 - - find-versions@6.0.0: - dependencies: - semver-regex: 4.0.5 - super-regex: 1.0.0 - find-yarn-workspace-root2@1.2.16: dependencies: micromatch: 4.0.7 @@ -14933,8 +10901,6 @@ snapshots: flatted: 3.2.7 rimraf: 3.0.2 - flat@5.0.2: {} - flatted@3.2.7: {} flow-parser@0.238.0: {} @@ -14943,10 +10909,6 @@ snapshots: optionalDependencies: debug: 4.3.5 - for-each@0.3.3: - dependencies: - is-callable: 1.2.7 - foreground-child@3.1.1: dependencies: cross-spawn: 7.0.3 @@ -14960,25 +10922,10 @@ snapshots: format@0.2.2: {} - forwarded@0.2.0: {} - - fresh@0.5.2: {} - - from2@2.3.0: - dependencies: - inherits: 2.0.4 - readable-stream: 2.3.8 - from@0.1.7: {} fs-exists-sync@0.1.0: {} - fs-extra@11.2.0: - dependencies: - graceful-fs: 4.2.11 - jsonfile: 6.1.0 - universalify: 2.0.0 - fs-extra@7.0.1: dependencies: graceful-fs: 4.2.11 @@ -14998,23 +10945,10 @@ snapshots: function-bind@1.1.2: {} - function-timeout@1.0.1: {} - - function.prototype.name@1.1.6: - dependencies: - call-bind: 1.0.5 - define-properties: 1.2.0 - es-abstract: 1.22.3 - functions-have-names: 1.2.3 - - functions-have-names@1.2.3: {} - gensync@1.0.0-beta.2: {} get-caller-file@2.0.5: {} - get-func-name@2.0.2: {} - get-intrinsic@1.2.2: dependencies: function-bind: 1.1.2 @@ -15028,48 +10962,10 @@ snapshots: get-stream@6.0.1: {} - get-stream@7.0.1: {} - - get-stream@8.0.1: {} - - get-stream@9.0.1: - dependencies: - '@sec-ant/readable-stream': 0.4.1 - is-stream: 4.0.1 - - get-symbol-description@1.0.0: - dependencies: - call-bind: 1.0.5 - get-intrinsic: 1.2.2 - get-tsconfig@4.7.5: dependencies: resolve-pkg-maps: 1.0.0 - get-uri@6.0.3: - dependencies: - basic-ftp: 5.0.5 - data-uri-to-buffer: 6.0.2 - debug: 4.3.5 - fs-extra: 11.2.0 - transitivePeerDependencies: - - supports-color - - git-log-parser@1.2.0: - dependencies: - argv-formatter: 1.0.0 - spawn-error-forwarder: 1.0.0 - split2: 1.0.0 - stream-combiner2: 1.1.1 - through2: 2.0.5 - traverse: 0.6.7 - - git-raw-commits@4.0.0: - dependencies: - dargs: 8.1.0 - meow: 12.1.1 - split2: 4.2.0 - glob-parent@5.1.2: dependencies: is-glob: 4.0.3 @@ -15086,15 +10982,6 @@ snapshots: minipass: 7.1.2 path-scurry: 1.11.1 - glob@11.0.0: - dependencies: - foreground-child: 3.1.1 - jackspeak: 4.0.1 - minimatch: 10.0.1 - minipass: 7.1.2 - package-json-from-dist: 1.0.0 - path-scurry: 2.0.0 - glob@7.2.3: dependencies: fs.realpath: 1.0.0 @@ -15104,18 +10991,6 @@ snapshots: once: 1.4.0 path-is-absolute: 1.0.1 - glob@8.1.0: - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 5.1.6 - once: 1.4.0 - - global-directory@4.0.1: - dependencies: - ini: 4.1.1 - global-modules@0.2.3: dependencies: global-prefix: 0.1.5 @@ -15138,10 +11013,6 @@ snapshots: dependencies: type-fest: 0.20.2 - globalthis@1.0.3: - dependencies: - define-properties: 1.2.0 - globby@11.1.0: dependencies: array-union: 2.1.0 @@ -15151,54 +11022,16 @@ snapshots: merge2: 1.4.1 slash: 3.0.0 - globby@14.0.1: - dependencies: - '@sindresorhus/merge-streams': 2.3.0 - fast-glob: 3.3.2 - ignore: 5.3.1 - path-type: 5.0.0 - slash: 5.1.0 - unicorn-magic: 0.1.0 - gopd@1.0.1: dependencies: get-intrinsic: 1.2.2 - graceful-fs@4.2.10: {} - graceful-fs@4.2.11: {} graphemer@1.4.0: {} - graphql-http@1.22.0(graphql@15.8.0): - dependencies: - graphql: 15.8.0 - - graphql-subscriptions@1.2.1(graphql@15.8.0): - dependencies: - graphql: 15.8.0 - iterall: 1.3.0 - - graphql-tag@2.12.6(graphql@15.8.0): - dependencies: - graphql: 15.8.0 - tslib: 2.6.3 - - graphql@15.8.0: {} - graphql@16.9.0: {} - handlebars@4.7.7: - dependencies: - minimist: 1.2.8 - neo-async: 2.6.2 - source-map: 0.6.1 - wordwrap: 1.0.0 - optionalDependencies: - uglify-js: 3.17.4 - - has-bigints@1.0.2: {} - has-flag@3.0.0: {} has-flag@4.0.0: {} @@ -15211,56 +11044,24 @@ snapshots: has-symbols@1.0.3: {} - has-tostringtag@1.0.0: - dependencies: - has-symbols: 1.0.3 - - has@1.0.3: - dependencies: - function-bind: 1.1.2 - hasown@2.0.0: dependencies: function-bind: 1.1.2 - he@1.2.0: {} - help-me@5.0.0: {} - highlight.js@10.7.3: {} - highlight.js@11.0.1: {} homedir-polyfill@1.0.3: dependencies: parse-passwd: 1.0.0 - hook-std@3.0.0: {} - - hosted-git-info@7.0.1: - dependencies: - lru-cache: 10.2.0 - html-encoding-sniffer@3.0.0: dependencies: whatwg-encoding: 2.0.0 html-escaper@2.0.2: {} - http-encoding@1.5.1: - dependencies: - brotli-wasm: 1.3.1 - pify: 5.0.0 - zstd-codec: 0.1.4 - - http-errors@2.0.0: - dependencies: - depd: 2.0.0 - inherits: 2.0.4 - setprototypeof: 1.2.0 - statuses: 2.0.1 - toidentifier: 1.0.1 - http-proxy-agent@5.0.0: dependencies: '@tootallnate/once': 2.0.0 @@ -15269,18 +11070,6 @@ snapshots: transitivePeerDependencies: - supports-color - http-proxy-agent@7.0.0: - dependencies: - agent-base: 7.1.1 - debug: 4.3.5 - transitivePeerDependencies: - - supports-color - - http2-wrapper@2.2.1: - dependencies: - quick-lru: 5.1.1 - resolve-alpn: 1.2.1 - https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 @@ -15288,21 +11077,10 @@ snapshots: transitivePeerDependencies: - supports-color - https-proxy-agent@7.0.4: - dependencies: - agent-base: 7.1.1 - debug: 4.3.5 - transitivePeerDependencies: - - supports-color - human-id@1.0.2: {} human-signals@2.1.0: {} - human-signals@5.0.0: {} - - human-signals@7.0.0: {} - humanize-ms@1.2.1: dependencies: ms: 2.1.3 @@ -15326,26 +11104,13 @@ snapshots: parent-module: 1.0.1 resolve-from: 4.0.0 - import-from-esm@1.3.4: - dependencies: - debug: 4.3.5 - import-meta-resolve: 4.0.0 - transitivePeerDependencies: - - supports-color - import-local@3.1.0: dependencies: pkg-dir: 4.2.0 resolve-cwd: 3.0.0 - import-meta-resolve@4.0.0: {} - imurmurhash@0.1.4: {} - indent-string@5.0.0: {} - - index-to-position@0.1.2: {} - inflight@1.0.6: dependencies: once: 1.4.0 @@ -15355,65 +11120,20 @@ snapshots: ini@1.3.8: {} - ini@4.1.1: {} - - internal-slot@1.0.5: - dependencies: - get-intrinsic: 1.2.2 - has: 1.0.3 - side-channel: 1.0.4 - - into-stream@7.0.0: - dependencies: - from2: 2.3.0 - p-is-promise: 3.0.0 - invariant@2.2.4: dependencies: loose-envify: 1.4.0 - ip-address@9.0.5: - dependencies: - jsbn: 1.1.0 - sprintf-js: 1.1.3 - - ipaddr.js@1.9.1: {} - - is-array-buffer@3.0.2: - dependencies: - call-bind: 1.0.5 - get-intrinsic: 1.2.2 - is-typed-array: 1.1.12 - is-arrayish@0.2.1: {} - is-bigint@1.0.4: - dependencies: - has-bigints: 1.0.2 - is-binary-path@2.1.0: dependencies: binary-extensions: 2.2.0 - is-boolean-object@1.1.2: - dependencies: - call-bind: 1.0.5 - has-tostringtag: 1.0.0 - - is-builtin-module@3.2.1: - dependencies: - builtin-modules: 3.3.0 - - is-callable@1.2.7: {} - is-core-module@2.13.1: dependencies: hasown: 2.0.0 - is-date-object@1.0.5: - dependencies: - has-tostringtag: 1.0.0 - is-extglob@2.1.1: {} is-fullwidth-code-point@3.0.0: {} @@ -15424,85 +11144,30 @@ snapshots: dependencies: is-extglob: 2.1.1 - is-module@1.0.0: {} - - is-negative-zero@2.0.2: {} - - is-number-object@1.0.7: - dependencies: - has-tostringtag: 1.0.0 - - is-number@7.0.0: {} - - is-obj@2.0.0: {} - - is-path-inside@3.0.3: {} - - is-plain-obj@2.1.0: {} - - is-plain-obj@4.1.0: {} - - is-plain-object@2.0.4: - dependencies: - isobject: 3.0.1 - - is-potential-custom-element-name@1.0.1: {} - - is-reference@1.2.1: - dependencies: - '@types/estree': 1.0.5 - - is-regex@1.1.4: - dependencies: - call-bind: 1.0.5 - has-tostringtag: 1.0.0 - - is-shared-array-buffer@1.0.2: - dependencies: - call-bind: 1.0.5 - - is-stream@2.0.1: {} - - is-stream@3.0.0: {} + is-number@7.0.0: {} - is-stream@4.0.1: {} + is-obj@2.0.0: {} - is-string@1.0.7: - dependencies: - has-tostringtag: 1.0.0 + is-path-inside@3.0.3: {} - is-subdir@1.2.0: + is-plain-object@2.0.4: dependencies: - better-path-resolve: 1.0.0 + isobject: 3.0.1 - is-symbol@1.0.4: - dependencies: - has-symbols: 1.0.3 + is-potential-custom-element-name@1.0.1: {} - is-text-path@2.0.0: - dependencies: - text-extensions: 2.4.0 + is-stream@2.0.1: {} - is-typed-array@1.1.12: + is-subdir@1.2.0: dependencies: - which-typed-array: 1.1.13 + better-path-resolve: 1.0.0 is-typedarray@1.0.0: {} - is-unicode-supported@0.1.0: {} - - is-unicode-supported@2.0.0: {} - - is-weakref@1.0.2: - dependencies: - call-bind: 1.0.5 - is-windows@0.2.0: {} is-windows@1.0.2: {} - isarray@1.0.0: {} - isarray@2.0.5: {} isexe@2.0.0: {} @@ -15513,18 +11178,6 @@ snapshots: dependencies: ws: 7.5.10(bufferutil@4.0.8)(utf-8-validate@5.0.10) - isomorphic-ws@4.0.1(ws@8.14.2(bufferutil@4.0.8)(utf-8-validate@5.0.10)): - dependencies: - ws: 8.14.2(bufferutil@4.0.8)(utf-8-validate@5.0.10) - - issue-parser@7.0.0: - dependencies: - lodash.capitalize: 4.2.1 - lodash.escaperegexp: 4.1.2 - lodash.isplainobject: 4.0.6 - lodash.isstring: 4.0.1 - lodash.uniqby: 4.7.0 - istanbul-lib-coverage@3.2.0: {} istanbul-lib-instrument@5.2.1: @@ -15566,22 +11219,12 @@ snapshots: html-escaper: 2.0.2 istanbul-lib-report: 3.0.0 - iterall@1.3.0: {} - jackspeak@3.4.0: dependencies: '@isaacs/cliui': 8.0.2 optionalDependencies: '@pkgjs/parseargs': 0.11.0 - jackspeak@4.0.1: - dependencies: - '@isaacs/cliui': 8.0.2 - optionalDependencies: - '@pkgjs/parseargs': 0.11.0 - - java-properties@1.0.2: {} - jayson@4.1.1(bufferutil@4.0.8)(utf-8-validate@5.0.10): dependencies: '@types/connect': 3.4.35 @@ -16259,7 +11902,8 @@ snapshots: - supports-color - ts-node - jiti@1.21.0: {} + jiti@1.21.0: + optional: true joi@17.12.2: dependencies: @@ -16282,8 +11926,6 @@ snapshots: dependencies: argparse: 2.0.1 - jsbn@1.1.0: {} - jscodeshift@0.16.1(@babel/preset-env@7.25.0(@babel/core@7.24.8)): dependencies: '@babel/core': 7.24.8 @@ -16340,18 +11982,15 @@ snapshots: - supports-color - utf-8-validate - jsesc@0.5.0: {} + jsesc@0.5.0: + optional: true jsesc@2.5.2: {} - json-parse-better-errors@1.0.2: {} - json-parse-even-better-errors@2.3.1: {} json-schema-traverse@0.4.1: {} - json-schema-traverse@1.0.0: {} - json-schema@0.4.0: {} json-stable-stringify-without-jsonify@1.0.1: {} @@ -16365,10 +12004,6 @@ snapshots: json-stringify-safe@5.0.1: {} - json5@1.0.2: - dependencies: - minimist: 1.2.8 - json5@2.2.3: {} jsonc-parser@3.2.0: {} @@ -16377,18 +12012,10 @@ snapshots: optionalDependencies: graceful-fs: 4.2.11 - jsonfile@6.1.0: - dependencies: - universalify: 2.0.0 - optionalDependencies: - graceful-fs: 4.2.11 - jsonify@0.0.1: {} jsonparse@1.3.1: {} - just-extend@6.2.0: {} - kind-of@6.0.3: {} kleur@3.0.3: {} @@ -16406,17 +12033,6 @@ snapshots: lines-and-columns@1.2.4: {} - linkify-it@5.0.0: - dependencies: - uc.micro: 2.1.0 - - load-json-file@4.0.0: - dependencies: - graceful-fs: 4.2.11 - parse-json: 4.0.0 - pify: 3.0.0 - strip-bom: 3.0.0 - load-tsconfig@0.2.5: {} load-yaml-file@0.2.0: @@ -16426,11 +12042,6 @@ snapshots: pify: 4.0.1 strip-bom: 3.0.0 - locate-path@2.0.0: - dependencies: - p-locate: 2.0.0 - path-exists: 3.0.0 - locate-path@3.0.0: dependencies: p-locate: 3.0.0 @@ -16444,59 +12055,21 @@ snapshots: dependencies: p-locate: 5.0.0 - locate-path@7.2.0: - dependencies: - p-locate: 6.0.0 - - lodash-es@4.17.21: {} - - lodash.camelcase@4.3.0: {} - - lodash.capitalize@4.2.1: {} - - lodash.debounce@4.0.8: {} - - lodash.escaperegexp@4.1.2: {} - - lodash.get@4.4.2: {} - - lodash.isplainobject@4.0.6: {} - - lodash.isstring@4.0.1: {} - - lodash.kebabcase@4.1.1: {} + lodash.debounce@4.0.8: + optional: true lodash.merge@4.6.2: {} - lodash.mergewith@4.6.2: {} - - lodash.snakecase@4.1.1: {} - lodash.sortby@4.7.0: {} lodash.startcase@4.4.0: {} - lodash.uniq@4.5.0: {} - - lodash.uniqby@4.7.0: {} - - lodash.upperfirst@4.3.1: {} - lodash@4.17.21: {} - log-symbols@4.1.0: - dependencies: - chalk: 4.1.2 - is-unicode-supported: 0.1.0 - loose-envify@1.4.0: dependencies: js-tokens: 4.0.0 - loupe@3.1.0: - dependencies: - get-func-name: 2.0.2 - lowlight@2.0.1: dependencies: '@types/hast': 2.3.4 @@ -16505,8 +12078,6 @@ snapshots: lru-cache@10.2.0: {} - lru-cache@11.0.0: {} - lru-cache@4.1.5: dependencies: pseudomap: 1.0.2 @@ -16520,18 +12091,6 @@ snapshots: dependencies: yallist: 4.0.0 - lru-cache@7.18.3: {} - - lunr@2.3.9: {} - - magic-string@0.25.9: - dependencies: - sourcemap-codec: 1.4.8 - - magic-string@0.30.10: - dependencies: - '@jridgewell/sourcemap-codec': 1.4.15 - make-dir@2.1.0: dependencies: pify: 4.0.1 @@ -16549,43 +12108,12 @@ snapshots: map-stream@0.1.0: {} - markdown-it@14.1.0: - dependencies: - argparse: 2.0.1 - entities: 4.5.0 - linkify-it: 5.0.0 - mdurl: 2.0.0 - punycode.js: 2.3.1 - uc.micro: 2.1.0 - - marked-terminal@7.0.0(marked@12.0.1): - dependencies: - ansi-escapes: 6.2.0 - chalk: 5.3.0 - cli-highlight: 2.1.11 - cli-table3: 0.6.3 - marked: 12.0.1 - node-emoji: 2.1.3 - supports-hyperlinks: 3.0.0 - - marked@12.0.1: {} - - mdurl@2.0.0: {} - - media-typer@0.3.0: {} - - meow@12.1.1: {} - meow@13.2.0: {} - merge-descriptors@1.0.1: {} - merge-stream@2.0.0: {} merge2@1.4.1: {} - methods@1.1.2: {} - micromatch@4.0.7: dependencies: braces: 3.0.3 @@ -16597,30 +12125,12 @@ snapshots: dependencies: mime-db: 1.52.0 - mime@1.6.0: {} - - mime@4.0.1: {} - mimic-fn@2.1.0: {} - mimic-fn@4.0.0: {} - - minimatch@10.0.1: - dependencies: - brace-expansion: 2.0.1 - minimatch@3.1.2: dependencies: brace-expansion: 1.1.11 - minimatch@5.0.1: - dependencies: - brace-expansion: 2.0.1 - - minimatch@5.1.6: - dependencies: - brace-expansion: 2.0.1 - minimatch@9.0.5: dependencies: brace-expansion: 2.0.1 @@ -16633,85 +12143,10 @@ snapshots: dependencies: minimist: 1.2.8 - mocha@10.4.0: - dependencies: - ansi-colors: 4.1.1 - browser-stdout: 1.3.1 - chokidar: 3.5.3 - debug: 4.3.4(supports-color@8.1.1) - diff: 5.0.0 - escape-string-regexp: 4.0.0 - find-up: 5.0.0 - glob: 8.1.0 - he: 1.2.0 - js-yaml: 4.1.0 - log-symbols: 4.1.0 - minimatch: 5.0.1 - ms: 2.1.3 - serialize-javascript: 6.0.0 - strip-json-comments: 3.1.1 - supports-color: 8.1.1 - workerpool: 6.2.1 - yargs: 16.2.0 - yargs-parser: 20.2.4 - yargs-unparser: 2.0.0 - mock-socket@9.3.1: {} - mockttp@3.15.0(bufferutil@4.0.8)(utf-8-validate@5.0.10): - dependencies: - '@graphql-tools/schema': 8.5.1(graphql@15.8.0) - '@graphql-tools/utils': 8.13.1(graphql@15.8.0) - '@httptoolkit/httpolyglot': 2.2.1 - '@httptoolkit/subscriptions-transport-ws': 0.11.2(bufferutil@4.0.8)(graphql@15.8.0)(utf-8-validate@5.0.10) - '@httptoolkit/websocket-stream': 6.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10) - '@types/cors': 2.8.17 - '@types/node': 18.19.21 - async-mutex: 0.5.0 - base64-arraybuffer: 0.1.5 - body-parser: 1.20.2 - cacheable-lookup: 6.1.0 - common-tags: 1.8.2 - connect: 3.7.0 - cors: 2.8.5 - cors-gate: 1.1.3 - cross-fetch: 3.1.8 - destroyable-server: 1.0.2 - express: 4.19.2 - fast-json-patch: 3.1.1 - graphql: 15.8.0 - graphql-http: 1.22.0(graphql@15.8.0) - graphql-subscriptions: 1.2.1(graphql@15.8.0) - graphql-tag: 2.12.6(graphql@15.8.0) - http-encoding: 1.5.1 - http2-wrapper: 2.2.1 - https-proxy-agent: 5.0.1 - isomorphic-ws: 4.0.1(ws@8.14.2(bufferutil@4.0.8)(utf-8-validate@5.0.10)) - lodash: 4.17.21 - lru-cache: 7.18.3 - native-duplexpair: 1.0.0 - node-forge: 1.3.1 - pac-proxy-agent: 7.0.1 - parse-multipart-data: 1.5.0 - performance-now: 2.1.0 - portfinder: 1.0.32 - read-tls-client-hello: 1.0.1 - semver: 7.6.0 - socks-proxy-agent: 7.0.0 - typed-error: 3.2.2 - urlpattern-polyfill: 8.0.2 - uuid: 8.3.2 - ws: 8.14.2(bufferutil@4.0.8)(utf-8-validate@5.0.10) - transitivePeerDependencies: - - bufferutil - - encoding - - supports-color - - utf-8-validate - mri@1.2.0: {} - ms@2.0.0: {} - ms@2.1.2: {} ms@2.1.3: {} @@ -16726,47 +12161,20 @@ snapshots: nanoid@3.3.7: {} - native-duplexpair@1.0.0: {} - natural-compare-lite@1.4.0: {} natural-compare@1.4.0: {} - negotiator@0.6.3: {} - neo-async@2.6.2: {} - nerf-dart@1.0.0: {} - - netmask@2.0.2: {} - - nise@6.0.0: - dependencies: - '@sinonjs/commons': 3.0.1 - '@sinonjs/fake-timers': 11.2.2 - '@sinonjs/text-encoding': 0.7.2 - just-extend: 6.2.0 - path-to-regexp: 6.2.2 - - node-abort-controller@3.0.1: {} - node-dir@0.1.17: dependencies: minimatch: 3.1.2 - node-emoji@2.1.3: - dependencies: - '@sindresorhus/is': 4.6.0 - char-regex: 1.0.2 - emojilib: 2.4.0 - skin-tone: 2.0.0 - node-fetch@2.7.0: dependencies: whatwg-url: 5.0.0 - node-forge@1.3.1: {} - node-gyp-build@4.6.0: optional: true @@ -16774,71 +12182,20 @@ snapshots: node-releases@2.0.14: {} - normalize-package-data@6.0.0: - dependencies: - hosted-git-info: 7.0.1 - is-core-module: 2.13.1 - semver: 7.6.0 - validate-npm-package-license: 3.0.4 - normalize-path@3.0.0: {} - normalize-url@8.0.0: {} - npm-run-path@4.0.1: dependencies: path-key: 3.1.1 - npm-run-path@5.3.0: - dependencies: - path-key: 4.0.0 - - npm@10.5.2: {} - nwsapi@2.2.5: {} object-assign@4.1.1: {} - object-inspect@1.13.1: {} - object-keys@1.1.1: {} - object.assign@4.1.4: - dependencies: - call-bind: 1.0.5 - define-properties: 1.2.0 - has-symbols: 1.0.3 - object-keys: 1.1.1 - - object.fromentries@2.0.7: - dependencies: - call-bind: 1.0.5 - define-properties: 1.2.0 - es-abstract: 1.22.3 - - object.groupby@1.0.1: - dependencies: - call-bind: 1.0.5 - define-properties: 1.2.0 - es-abstract: 1.22.3 - get-intrinsic: 1.2.2 - - object.values@1.1.7: - dependencies: - call-bind: 1.0.5 - define-properties: 1.2.0 - es-abstract: 1.22.3 - on-exit-leak-free@2.1.2: {} - on-finished@2.3.0: - dependencies: - ee-first: 1.1.1 - - on-finished@2.4.1: - dependencies: - ee-first: 1.1.1 - once@1.4.0: dependencies: wrappy: 1.0.2 @@ -16847,10 +12204,6 @@ snapshots: dependencies: mimic-fn: 2.1.0 - onetime@6.0.0: - dependencies: - mimic-fn: 4.0.0 - optionator@0.9.3: dependencies: '@aashutoshrathi/word-wrap': 1.2.6 @@ -16866,22 +12219,10 @@ snapshots: outdent@0.5.0: {} - p-each-series@3.0.0: {} - p-filter@2.1.0: dependencies: p-map: 2.1.0 - p-filter@4.1.0: - dependencies: - p-map: 7.0.2 - - p-is-promise@3.0.0: {} - - p-limit@1.3.0: - dependencies: - p-try: 1.0.0 - p-limit@2.3.0: dependencies: p-try: 2.2.0 @@ -16894,10 +12235,6 @@ snapshots: dependencies: yocto-queue: 1.0.0 - p-locate@2.0.0: - dependencies: - p-limit: 1.3.0 - p-locate@3.0.0: dependencies: p-limit: 2.3.0 @@ -16910,49 +12247,14 @@ snapshots: dependencies: p-limit: 3.1.0 - p-locate@6.0.0: - dependencies: - p-limit: 4.0.0 - p-map@2.1.0: {} - p-map@7.0.2: {} - - p-reduce@3.0.0: {} - - p-try@1.0.0: {} - p-try@2.2.0: {} - pac-proxy-agent@7.0.1: - dependencies: - '@tootallnate/quickjs-emscripten': 0.23.0 - agent-base: 7.1.1 - debug: 4.3.5 - get-uri: 6.0.3 - http-proxy-agent: 7.0.0 - https-proxy-agent: 7.0.4 - pac-resolver: 7.0.1 - socks-proxy-agent: 8.0.3 - transitivePeerDependencies: - - supports-color - - pac-resolver@7.0.1: - dependencies: - degenerator: 5.0.1 - netmask: 2.0.2 - - package-json-from-dist@1.0.0: {} - parent-module@1.0.1: dependencies: callsites: 3.1.0 - parse-json@4.0.0: - dependencies: - error-ex: 1.3.2 - json-parse-better-errors: 1.0.2 - parse-json@5.2.0: dependencies: '@babel/code-frame': 7.24.7 @@ -16960,44 +12262,20 @@ snapshots: json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 - parse-json@8.1.0: - dependencies: - '@babel/code-frame': 7.24.7 - index-to-position: 0.1.2 - type-fest: 4.15.0 - - parse-ms@4.0.0: {} - - parse-multipart-data@1.5.0: {} - parse-passwd@1.0.0: {} - parse5-htmlparser2-tree-adapter@6.0.1: - dependencies: - parse5: 6.0.1 - - parse5@5.1.1: {} - - parse5@6.0.1: {} - parse5@7.1.2: dependencies: entities: 4.5.0 - parseurl@1.3.3: {} - path-exists@3.0.0: {} path-exists@4.0.0: {} - path-exists@5.0.0: {} - path-is-absolute@1.0.1: {} path-key@3.1.1: {} - path-key@4.0.0: {} - path-parse@1.0.7: {} path-scurry@1.11.1: @@ -17005,39 +12283,20 @@ snapshots: lru-cache: 10.2.0 minipass: 7.1.2 - path-scurry@2.0.0: - dependencies: - lru-cache: 11.0.0 - minipass: 7.1.2 - - path-to-regexp@0.1.7: {} - - path-to-regexp@6.2.2: {} - path-type@4.0.0: {} - path-type@5.0.0: {} - - pathval@2.0.0: {} - pause-stream@0.0.11: dependencies: through: 2.3.8 - performance-now@2.1.0: {} - picocolors@1.0.1: {} picomatch@2.3.1: {} picomatch@4.0.2: {} - pify@3.0.0: {} - pify@4.0.1: {} - pify@5.0.0: {} - pino-abstract-transport@1.2.0: dependencies: readable-stream: 4.5.2 @@ -17078,11 +12337,6 @@ snapshots: pirates@4.0.6: {} - pkg-conf@2.1.0: - dependencies: - find-up: 2.1.0 - load-json-file: 4.0.0 - pkg-dir@3.0.0: dependencies: find-up: 3.0.0 @@ -17091,14 +12345,6 @@ snapshots: dependencies: find-up: 4.1.0 - portfinder@1.0.32: - dependencies: - async: 2.6.4 - debug: 3.2.7 - mkdirp: 0.5.6 - transitivePeerDependencies: - - supports-color - postcss-load-config@6.0.1(jiti@1.21.0)(postcss@8.4.39)(tsx@4.16.2)(yaml@2.4.5): dependencies: lilconfig: 3.1.2 @@ -17123,14 +12369,8 @@ snapshots: prelude-ls@1.2.1: {} - prettier-linter-helpers@1.0.0: - dependencies: - fast-diff: 1.3.0 - prettier@2.8.8: {} - prettier@3.3.1: {} - prettier@3.3.3: {} pretty-format@27.5.1: @@ -17151,12 +12391,6 @@ snapshots: ansi-styles: 5.2.0 react-is: 18.3.1 - pretty-ms@9.0.0: - dependencies: - parse-ms: 4.0.0 - - process-nextick-args@2.0.1: {} - process-warning@4.0.0: {} process@0.11.10: {} @@ -17166,13 +12400,6 @@ snapshots: kleur: 3.0.3 sisteransi: 1.0.5 - proto-list@1.2.4: {} - - proxy-addr@2.0.7: - dependencies: - forwarded: 0.2.0 - ipaddr.js: 1.9.1 - proxy-from-env@1.1.0: {} ps-tree@1.2.0: @@ -17188,45 +12415,15 @@ snapshots: end-of-stream: 1.4.4 once: 1.4.0 - punycode.js@2.3.1: {} - punycode@2.3.0: {} - pure-rand@6.0.2: {} - - qs@6.11.0: - dependencies: - side-channel: 1.0.4 - - querystringify@2.2.0: {} - - queue-microtask@1.2.3: {} - - quick-format-unescaped@4.0.4: {} - - quick-lru@5.1.1: {} - - rambda@7.5.0: {} - - randombytes@2.1.0: - dependencies: - safe-buffer: 5.2.1 + pure-rand@6.0.2: {} - range-parser@1.2.1: {} + querystringify@2.2.0: {} - raw-body@2.5.2: - dependencies: - bytes: 3.1.2 - http-errors: 2.0.0 - iconv-lite: 0.4.24 - unpipe: 1.0.0 + queue-microtask@1.2.3: {} - rc@1.2.8: - dependencies: - deep-extend: 0.6.0 - ini: 1.3.8 - minimist: 1.2.8 - strip-json-comments: 2.0.1 + quick-format-unescaped@4.0.4: {} react-dom@18.3.1(react@18.3.1): dependencies: @@ -17298,30 +12495,6 @@ snapshots: dependencies: loose-envify: 1.4.0 - read-package-up@11.0.0: - dependencies: - find-up-simple: 1.0.0 - read-pkg: 9.0.1 - type-fest: 4.15.0 - - read-pkg-up@11.0.0: - dependencies: - find-up-simple: 1.0.0 - read-pkg: 9.0.1 - type-fest: 4.15.0 - - read-pkg@9.0.1: - dependencies: - '@types/normalize-package-data': 2.4.4 - normalize-package-data: 6.0.0 - parse-json: 8.1.0 - type-fest: 4.15.0 - unicorn-magic: 0.1.0 - - read-tls-client-hello@1.0.1: - dependencies: - '@types/node': 22.0.0 - read-yaml-file@1.1.0: dependencies: graceful-fs: 4.2.11 @@ -17329,16 +12502,6 @@ snapshots: pify: 4.0.1 strip-bom: 3.0.0 - readable-stream@2.3.8: - dependencies: - core-util-is: 1.0.3 - inherits: 2.0.4 - isarray: 1.0.0 - process-nextick-args: 2.0.1 - safe-buffer: 5.1.2 - string_decoder: 1.1.1 - util-deprecate: 1.0.2 - readable-stream@4.5.2: dependencies: abort-controller: 3.0.0 @@ -17371,20 +12534,17 @@ snapshots: regenerate-unicode-properties@10.1.0: dependencies: regenerate: 1.4.2 + optional: true - regenerate@1.4.2: {} + regenerate@1.4.2: + optional: true regenerator-runtime@0.14.0: {} regenerator-transform@0.15.2: dependencies: '@babel/runtime': 7.25.0 - - regexp.prototype.flags@1.5.1: - dependencies: - call-bind: 1.0.5 - define-properties: 1.2.0 - set-function-name: 2.0.1 + optional: true regexpu-core@5.3.2: dependencies: @@ -17394,25 +12554,19 @@ snapshots: regjsparser: 0.9.1 unicode-match-property-ecmascript: 2.0.0 unicode-match-property-value-ecmascript: 2.1.0 - - registry-auth-token@5.0.2: - dependencies: - '@pnpm/npm-conf': 2.2.2 + optional: true regjsparser@0.9.1: dependencies: jsesc: 0.5.0 + optional: true require-directory@2.1.1: {} - require-from-string@2.0.2: {} - requireindex@1.2.0: {} requires-port@1.0.0: {} - resolve-alpn@1.2.1: {} - resolve-cwd@3.0.0: dependencies: resolve-from: 5.0.0 @@ -17448,33 +12602,6 @@ snapshots: dependencies: glob: 7.2.3 - rimraf@6.0.1: - dependencies: - glob: 11.0.0 - package-json-from-dist: 1.0.0 - - rollup-plugin-dts@6.1.1(rollup@4.19.0)(typescript@5.5.4): - dependencies: - magic-string: 0.30.10 - rollup: 4.19.0 - typescript: 5.5.4 - optionalDependencies: - '@babel/code-frame': 7.24.6 - - rollup-plugin-inject@3.0.2: - dependencies: - estree-walker: 0.6.1 - magic-string: 0.25.9 - rollup-pluginutils: 2.8.2 - - rollup-plugin-node-polyfills@0.2.1: - dependencies: - rollup-plugin-inject: 3.0.2 - - rollup-pluginutils@2.8.2: - dependencies: - estree-walker: 0.6.1 - rollup@3.27.2: optionalDependencies: fsevents: 2.3.3 @@ -17505,7 +12632,7 @@ snapshots: dependencies: '@swc/helpers': 0.5.11 '@types/uuid': 8.3.4 - '@types/ws': 8.5.11 + '@types/ws': 8.5.12 buffer: 6.0.3 eventemitter3: 5.0.1 uuid: 8.3.2 @@ -17524,23 +12651,8 @@ snapshots: dependencies: tslib: 2.6.3 - safe-array-concat@1.0.1: - dependencies: - call-bind: 1.0.5 - get-intrinsic: 1.2.2 - has-symbols: 1.0.3 - isarray: 2.0.5 - - safe-buffer@5.1.2: {} - safe-buffer@5.2.1: {} - safe-regex-test@1.0.0: - dependencies: - call-bind: 1.0.5 - get-intrinsic: 1.2.2 - is-regex: 1.1.4 - safe-stable-stringify@2.4.3: {} safer-buffer@2.1.2: {} @@ -17555,47 +12667,6 @@ snapshots: secure-json-parse@2.7.0: {} - semantic-release@24.0.0(typescript@5.5.4): - dependencies: - '@semantic-release/commit-analyzer': 13.0.0(semantic-release@24.0.0(typescript@5.5.4)) - '@semantic-release/error': 4.0.0 - '@semantic-release/github': 10.0.5(semantic-release@24.0.0(typescript@5.5.4)) - '@semantic-release/npm': 12.0.1(semantic-release@24.0.0(typescript@5.5.4)) - '@semantic-release/release-notes-generator': 14.0.0(semantic-release@24.0.0(typescript@5.5.4)) - aggregate-error: 5.0.0 - cosmiconfig: 9.0.0(typescript@5.5.4) - debug: 4.3.4(supports-color@8.1.1) - env-ci: 11.0.0 - execa: 9.1.0 - figures: 6.1.0 - find-versions: 6.0.0 - get-stream: 6.0.1 - git-log-parser: 1.2.0 - hook-std: 3.0.0 - hosted-git-info: 7.0.1 - import-from-esm: 1.3.4 - lodash-es: 4.17.21 - marked: 12.0.1 - marked-terminal: 7.0.0(marked@12.0.1) - micromatch: 4.0.7 - p-each-series: 3.0.0 - p-reduce: 3.0.0 - read-package-up: 11.0.0 - resolve-from: 5.0.0 - semver: 7.6.0 - semver-diff: 4.0.0 - signale: 1.4.0 - yargs: 17.7.2 - transitivePeerDependencies: - - supports-color - - typescript - - semver-diff@4.0.0: - dependencies: - semver: 7.6.0 - - semver-regex@4.0.5: {} - semver@5.7.1: {} semver@6.3.1: {} @@ -17604,41 +12675,6 @@ snapshots: dependencies: lru-cache: 6.0.0 - send@0.18.0: - dependencies: - debug: 2.6.9 - depd: 2.0.0 - destroy: 1.2.0 - encodeurl: 1.0.2 - escape-html: 1.0.3 - etag: 1.8.1 - fresh: 0.5.2 - http-errors: 2.0.0 - mime: 1.6.0 - ms: 2.1.3 - on-finished: 2.4.1 - range-parser: 1.2.1 - statuses: 2.0.1 - transitivePeerDependencies: - - supports-color - - serialize-javascript@6.0.0: - dependencies: - randombytes: 2.1.0 - - serialize-javascript@6.0.1: - dependencies: - randombytes: 2.1.0 - - serve-static@1.15.0: - dependencies: - encodeurl: 1.0.2 - escape-html: 1.0.3 - parseurl: 1.3.3 - send: 0.18.0 - transitivePeerDependencies: - - supports-color - set-function-length@1.1.1: dependencies: define-data-property: 1.1.1 @@ -17646,14 +12682,6 @@ snapshots: gopd: 1.0.1 has-property-descriptors: 1.0.0 - set-function-name@2.0.1: - dependencies: - define-data-property: 1.1.1 - functions-have-names: 1.2.3 - has-property-descriptors: 1.0.0 - - setprototypeof@1.2.0: {} - shallow-clone@3.0.1: dependencies: kind-of: 6.0.3 @@ -17670,77 +12698,16 @@ snapshots: shebang-regex@3.0.0: {} - shiki@1.9.1: - dependencies: - '@shikijs/core': 1.9.1 - - side-channel@1.0.4: - dependencies: - call-bind: 1.0.5 - get-intrinsic: 1.2.2 - object-inspect: 1.13.1 - signal-exit@3.0.7: {} signal-exit@4.1.0: {} - signale@1.4.0: - dependencies: - chalk: 2.4.2 - figures: 2.0.0 - pkg-conf: 2.1.0 - - sinon-chai@4.0.0(chai@5.1.1)(sinon@18.0.0): - dependencies: - chai: 5.1.1 - sinon: 18.0.0 - - sinon@18.0.0: - dependencies: - '@sinonjs/commons': 3.0.1 - '@sinonjs/fake-timers': 11.2.2 - '@sinonjs/samsam': 8.0.0 - diff: 5.2.0 - nise: 6.0.0 - supports-color: 7.2.0 - sisteransi@1.0.5: {} - skin-tone@2.0.0: - dependencies: - unicode-emoji-modifier-base: 1.0.0 - slash@3.0.0: {} - slash@4.0.0: {} - slash@5.1.0: {} - smart-buffer@4.2.0: {} - - smob@1.4.0: {} - - socks-proxy-agent@7.0.0: - dependencies: - agent-base: 6.0.2 - debug: 4.3.5 - socks: 2.8.1 - transitivePeerDependencies: - - supports-color - - socks-proxy-agent@8.0.3: - dependencies: - agent-base: 7.1.1 - debug: 4.3.5 - socks: 2.8.1 - transitivePeerDependencies: - - supports-color - - socks@2.8.1: - dependencies: - ip-address: 9.0.5 - smart-buffer: 4.2.0 - sonic-boom@4.0.1: dependencies: atomic-sleep: 1.0.0 @@ -17763,10 +12730,6 @@ snapshots: dependencies: whatwg-url: 7.1.0 - sourcemap-codec@1.4.8: {} - - spawn-error-forwarder@1.0.0: {} - spawnd@10.0.0: dependencies: signal-exit: 4.1.0 @@ -17777,24 +12740,6 @@ snapshots: cross-spawn: 5.1.0 signal-exit: 3.0.7 - spdx-correct@3.2.0: - dependencies: - spdx-expression-parse: 3.0.1 - spdx-license-ids: 3.0.13 - - spdx-exceptions@2.3.0: {} - - spdx-expression-parse@3.0.1: - dependencies: - spdx-exceptions: 2.3.0 - spdx-license-ids: 3.0.13 - - spdx-license-ids@3.0.13: {} - - split2@1.0.0: - dependencies: - through2: 2.0.5 - split2@4.2.0: {} split@0.3.3: @@ -17803,8 +12748,6 @@ snapshots: sprintf-js@1.0.3: {} - sprintf-js@1.1.3: {} - stack-utils@2.0.6: dependencies: escape-string-regexp: 2.0.0 @@ -17822,21 +12765,10 @@ snapshots: transitivePeerDependencies: - supports-color - statuses@1.5.0: {} - - statuses@2.0.1: {} - - stream-combiner2@1.1.1: - dependencies: - duplexer2: 0.1.4 - readable-stream: 2.3.8 - stream-combiner@0.0.4: dependencies: duplexer: 0.1.2 - stream-shift@1.0.3: {} - string-length@4.0.2: dependencies: char-regex: 1.0.2 @@ -17859,28 +12791,6 @@ snapshots: emoji-regex: 9.2.2 strip-ansi: 7.1.0 - string.prototype.trim@1.2.8: - dependencies: - call-bind: 1.0.5 - define-properties: 1.2.0 - es-abstract: 1.22.3 - - string.prototype.trimend@1.0.7: - dependencies: - call-bind: 1.0.5 - define-properties: 1.2.0 - es-abstract: 1.22.3 - - string.prototype.trimstart@1.0.7: - dependencies: - call-bind: 1.0.5 - define-properties: 1.2.0 - es-abstract: 1.22.3 - - string_decoder@1.1.1: - dependencies: - safe-buffer: 5.1.2 - string_decoder@1.3.0: dependencies: safe-buffer: 5.2.1 @@ -17899,12 +12809,6 @@ snapshots: strip-final-newline@2.0.0: {} - strip-final-newline@3.0.0: {} - - strip-final-newline@4.0.0: {} - - strip-json-comments@2.0.1: {} - strip-json-comments@3.1.1: {} sucrase@3.35.0: @@ -17917,11 +12821,6 @@ snapshots: pirates: 4.0.6 ts-interface-checker: 0.1.13 - super-regex@1.0.0: - dependencies: - function-timeout: 1.0.1 - time-span: 5.1.0 - superstruct@2.0.2: {} supports-color@5.5.0: @@ -17936,11 +12835,6 @@ snapshots: dependencies: has-flag: 4.0.0 - supports-hyperlinks@3.0.0: - dependencies: - has-flag: 4.0.0 - supports-color: 7.2.0 - supports-preserve-symlinks-flag@1.0.0: {} swr@2.2.5(react@18.3.1): @@ -17949,8 +12843,6 @@ snapshots: react: 18.3.1 use-sync-external-store: 1.2.2(react@18.3.1) - symbol-observable@1.2.0: {} - symbol-tree@3.2.4: {} synckit@0.9.1: @@ -17958,20 +12850,11 @@ snapshots: '@pkgr/core': 0.1.1 tslib: 2.6.3 - temp-dir@3.0.0: {} - temp@0.9.4: dependencies: mkdirp: 0.5.6 rimraf: 2.6.3 - tempy@3.1.0: - dependencies: - is-stream: 3.0.0 - temp-dir: 3.0.0 - type-fest: 2.19.0 - unique-string: 3.0.0 - term-size@2.2.1: {} terser@5.18.0: @@ -17980,6 +12863,7 @@ snapshots: acorn: 8.10.0 commander: 2.20.3 source-map-support: 0.5.21 + optional: true test-exclude@6.0.0: dependencies: @@ -17989,8 +12873,6 @@ snapshots: text-encoding-utf-8@1.0.2: {} - text-extensions@2.4.0: {} - text-table@0.2.0: {} thenify-all@1.6.0: @@ -18007,17 +12889,8 @@ snapshots: throat@6.0.2: {} - through2@2.0.5: - dependencies: - readable-stream: 2.3.8 - xtend: 4.0.2 - through@2.3.8: {} - time-span@5.1.0: - dependencies: - convert-hrtime: 5.0.0 - tiny-invariant@1.3.3: {} tinybench@2.8.0: {} @@ -18034,8 +12907,6 @@ snapshots: dependencies: is-number: 7.0.0 - toidentifier@1.0.1: {} - tough-cookie@4.1.3: dependencies: psl: 1.9.0 @@ -18053,8 +12924,6 @@ snapshots: dependencies: punycode: 2.3.0 - traverse@0.6.7: {} - tree-kill@1.2.2: {} ts-api-utils@1.3.0(typescript@5.5.4): @@ -18083,13 +12952,6 @@ snapshots: optionalDependencies: '@swc/core': 1.6.5(@swc/helpers@0.5.11) - tsconfig-paths@3.14.2: - dependencies: - '@types/json5': 0.0.29 - json5: 1.0.2 - minimist: 1.2.8 - strip-bom: 3.0.0 - tslib@1.14.1: {} tslib@2.6.3: {} @@ -18171,77 +13033,16 @@ snapshots: type-fest@0.21.3: {} - type-fest@1.4.0: {} - - type-fest@2.19.0: {} - type-fest@3.12.0: {} - type-fest@4.15.0: {} - - type-is@1.6.18: - dependencies: - media-typer: 0.3.0 - mime-types: 2.1.35 - - typed-array-buffer@1.0.0: - dependencies: - call-bind: 1.0.5 - get-intrinsic: 1.2.2 - is-typed-array: 1.1.12 - - typed-array-byte-length@1.0.0: - dependencies: - call-bind: 1.0.5 - for-each: 0.3.3 - has-proto: 1.0.1 - is-typed-array: 1.1.12 - - typed-array-byte-offset@1.0.0: - dependencies: - available-typed-arrays: 1.0.5 - call-bind: 1.0.5 - for-each: 0.3.3 - has-proto: 1.0.1 - is-typed-array: 1.1.12 - - typed-array-length@1.0.4: - dependencies: - call-bind: 1.0.5 - for-each: 0.3.3 - is-typed-array: 1.1.12 - - typed-error@3.2.2: {} - typedarray-to-buffer@3.1.5: dependencies: is-typedarray: 1.0.0 - typedoc@0.26.5(typescript@5.5.4): - dependencies: - lunr: 2.3.9 - markdown-it: 14.1.0 - minimatch: 9.0.5 - shiki: 1.9.1 - typescript: 5.5.4 - yaml: 2.4.5 - typescript@5.5.2: {} typescript@5.5.4: {} - uc.micro@2.1.0: {} - - uglify-js@3.17.4: - optional: true - - unbox-primitive@1.0.2: - dependencies: - call-bind: 1.0.5 - has-bigints: 1.0.2 - has-symbols: 1.0.3 - which-boxed-primitive: 1.0.2 - undici-types@5.26.5: {} undici-types@6.11.1: {} @@ -18250,35 +13051,25 @@ snapshots: undici@6.19.4: {} - unicode-canonical-property-names-ecmascript@2.0.0: {} - - unicode-emoji-modifier-base@1.0.0: {} + unicode-canonical-property-names-ecmascript@2.0.0: + optional: true unicode-match-property-ecmascript@2.0.0: dependencies: unicode-canonical-property-names-ecmascript: 2.0.0 unicode-property-aliases-ecmascript: 2.1.0 + optional: true - unicode-match-property-value-ecmascript@2.1.0: {} - - unicode-property-aliases-ecmascript@2.1.0: {} - - unicorn-magic@0.1.0: {} - - unique-string@3.0.0: - dependencies: - crypto-random-string: 4.0.0 + unicode-match-property-value-ecmascript@2.1.0: + optional: true - universal-user-agent@7.0.2: {} + unicode-property-aliases-ecmascript@2.1.0: + optional: true universalify@0.1.2: {} universalify@0.2.0: {} - universalify@2.0.0: {} - - unpipe@1.0.0: {} - update-browserslist-db@1.1.0(browserslist@4.23.2): dependencies: browserslist: 4.23.2 @@ -18289,15 +13080,11 @@ snapshots: dependencies: punycode: 2.3.0 - url-join@5.0.0: {} - url-parse@1.5.10: dependencies: querystringify: 2.2.0 requires-port: 1.0.0 - urlpattern-polyfill@8.0.2: {} - use-callback-ref@1.3.2(@types/react@18.3.3)(react@18.3.1): dependencies: react: 18.3.1 @@ -18322,10 +13109,6 @@ snapshots: node-gyp-build: 4.6.0 optional: true - util-deprecate@1.0.2: {} - - utils-merge@1.0.1: {} - uuid@8.3.2: {} v8-compile-cache-lib@3.0.1: {} @@ -18336,17 +13119,8 @@ snapshots: '@types/istanbul-lib-coverage': 2.0.4 convert-source-map: 1.9.0 - validate-npm-package-license@3.0.4: - dependencies: - spdx-correct: 3.2.0 - spdx-expression-parse: 3.0.1 - - value-or-promise@1.0.11: {} - value-or-promise@1.0.12: {} - vary@1.1.2: {} - vite@5.3.5(@types/node@22.0.0)(terser@5.18.0): dependencies: esbuild: 0.21.5 @@ -18405,27 +13179,11 @@ snapshots: tr46: 1.0.1 webidl-conversions: 4.0.2 - which-boxed-primitive@1.0.2: - dependencies: - is-bigint: 1.0.4 - is-boolean-object: 1.1.2 - is-number-object: 1.0.7 - is-string: 1.0.7 - is-symbol: 1.0.4 - which-pm@2.0.0: dependencies: load-yaml-file: 0.2.0 path-exists: 4.0.0 - which-typed-array@1.1.13: - dependencies: - available-typed-arrays: 1.0.5 - call-bind: 1.0.5 - for-each: 0.3.3 - gopd: 1.0.1 - has-tostringtag: 1.0.0 - which@1.3.1: dependencies: isexe: 2.0.0 @@ -18434,10 +13192,6 @@ snapshots: dependencies: isexe: 2.0.0 - wordwrap@1.0.0: {} - - workerpool@6.2.1: {} - wrap-ansi@6.2.0: dependencies: ansi-styles: 4.3.0 @@ -18489,8 +13243,6 @@ snapshots: xmlchars@2.2.0: {} - xtend@4.0.2: {} - y18n@5.0.8: {} yallist@2.1.2: {} @@ -18501,31 +13253,11 @@ snapshots: yaml@1.10.2: {} - yaml@2.4.5: {} - - yargs-parser@20.2.4: {} - - yargs-parser@20.2.9: {} + yaml@2.4.5: + optional: true yargs-parser@21.1.1: {} - yargs-unparser@2.0.0: - dependencies: - camelcase: 6.3.0 - decamelize: 4.0.0 - flat: 5.0.2 - is-plain-obj: 2.1.0 - - yargs@16.2.0: - dependencies: - cliui: 7.0.4 - escalade: 3.1.1 - get-caller-file: 2.0.5 - require-directory: 2.1.1 - string-width: 4.2.3 - y18n: 5.0.8 - yargs-parser: 20.2.9 - yargs@17.7.2: dependencies: cliui: 8.0.1 @@ -18544,12 +13276,8 @@ snapshots: yoctocolors-cjs@2.1.2: {} - yoctocolors@2.0.2: {} - yoctocolors@2.1.1: {} - zstd-codec@0.1.4: {} - zx@8.1.4: optionalDependencies: '@types/fs-extra': 11.0.4 diff --git a/scripts/fixtures/legacy-token-test-mint-account.json b/scripts/fixtures/legacy-token-test-mint-account.json deleted file mode 100644 index 5842cbfaa083..000000000000 --- a/scripts/fixtures/legacy-token-test-mint-account.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "pubkey": "7MbpdfJa5xqwexkp6WUvkYHTPo4VgxYACDBNFWYLwCdo", - "account": { - "lamports": 1461600, - "data": [ - "AQAAAHcJbkUYh4l63GiAnsWEYIXJ+GFRCPDM7Llpzw531Qu8ZysAAAAAAAACAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==", - "base64" - ], - "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", - "executable": false, - "rentEpoch": 0, - "space": 82 - } -} diff --git a/scripts/fixtures/legacy-token-test-token-account.json b/scripts/fixtures/legacy-token-test-token-account.json deleted file mode 100644 index 99a33e0eb15d..000000000000 --- a/scripts/fixtures/legacy-token-test-token-account.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "pubkey": "EryTMgfSEabo5Fc7dN5z3nBQKzfHUJRpHAMnXdCrTq4S", - "account": { - "lamports": 2039280, - "data": [ - "Xm0cOPd0hEH7bBdAi+cMVTdGREX7rlH2xK4VEXbE7SKM93A2eCCodkhzviKrfg93/K0yrQgKYO8VIF5DJSuR+WYrAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", - "base64" - ], - "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", - "executable": false, - "rentEpoch": 0, - "space": 165 - } -} diff --git a/scripts/fixtures/legacy-token-test-token-owner.json b/scripts/fixtures/legacy-token-test-token-owner.json deleted file mode 100644 index 852550df3ee1..000000000000 --- a/scripts/fixtures/legacy-token-test-token-owner.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "pubkey": "AVGuygVeBmbYiJ47V7tgBNLSukNqW7pWZYJsKUNWhHpc", - "account": { - "lamports": 10000000000, - "data": ["", "base64"], - "owner": "11111111111111111111111111111111", - "executable": false, - "rentEpoch": 0, - "space": 0 - } -} diff --git a/turbo.json b/turbo.json index ddf3de0af7cc..60a605a03001 100644 --- a/turbo.json +++ b/turbo.json @@ -45,20 +45,6 @@ ], "passThroughEnv": ["GH_TOKEN", "NPM_TOKEN"] }, - "publish-packages-legacy": { - "cache": false, - "dependsOn": [ - "compile:docs", - "compile:js", - "compile:typedefs", - "test:lint", - "test:live-with-test-validator", - "test:prettier", - "test:typecheck", - "test:unit:node" - ], - "passThroughEnv": ["GH_TOKEN", "NPM_TOKEN"] - }, "style:fix": { "inputs": ["$TURBO_DEFAULT$", "*"], "outputs": ["*"] @@ -102,62 +88,8 @@ "inputs": ["$TURBO_DEFAULT$", "index.html", "tsconfig.*", "vite.config.ts", "public/**", "src/**"], "outputs": ["dist/**"] }, - "@solana/web3.js#build": { - "dependsOn": [ - "clean", - "compile:docs", - "compile:js", - "compile:typedefs", - "test:lint", - "test:live-with-test-validator", - "test:prettier", - "test:typecheck", - "test:unit:node" - ], - "outputs": ["doc/**", "declarations/**", "lib/**"] - }, - "@solana/web3.js#clean": { - "outputs": ["doc/**", "declarations/**", "lib/**"] - }, - "@solana/web3.js#compile:docs": { - "dependsOn": ["clean"], - "inputs": ["$TURBO_DEFAULT$", "src/**"], - "outputs": ["doc/**"] - }, - "@solana/web3.js#compile:js": { - "dependsOn": ["clean", "^compile:js"], - "inputs": ["$TURBO_DEFAULT$", "babel.config.json", "rollup.config.mjs", "tsconfig.*", "src/**"], - "outputs": ["lib/**"] - }, - "@solana/web3.js#compile:typedefs": { - "dependsOn": ["clean", "^compile:typedefs"], - "inputs": [ - "$TURBO_DEFAULT$", - "rollup.config.types.mjs", - "scripts/typegen.sh", - "src/**", - "test/__shadow-jest-types.d.ts", - "tsconfig.*" - ], - "outputs": ["declarations/**", "lib/**/*.d.ts"] - }, - "@solana/web3.js#test:lint": { - "inputs": ["$TURBO_DEFAULT$", "src/**", "test/**"] - }, - "@solana/web3.js#test:live-with-test-validator": { - "dependsOn": ["compile:js"], - "inputs": ["$TURBO_DEFAULT$", "../../.agave/**/version.yml", "src/**", "test/**"] - }, - "@solana/web3.js#test:typecheck": { - "dependsOn": ["compile:typedefs"], - "inputs": ["$TURBO_DEFAULT$", "src/**", "test/**", "tsconfig.*"] - }, - "@solana/web3.js#test:unit:node": { - "dependsOn": ["compile:js"], - "inputs": ["$TURBO_DEFAULT$", "src/**", "test/**"] - }, "//#compile:ghpages": { - "dependsOn": ["@solana/example-react-app#compile:js", "@solana/web3.js#compile:docs"] + "dependsOn": ["@solana/example-react-app#compile:js"] } }, "ui": "stream"