From fac413397fc24b342a8029477d5e84788c13f102 Mon Sep 17 00:00:00 2001 From: alexander-sei Date: Sun, 23 Aug 2026 00:58:24 +0200 Subject: [PATCH 1/4] fix(sei-global-wallet): harden consumer integrations Align Dynamic peers, make browser and EIP-6963 behavior reliable, and verify the explicit upstream security waiver in real npm and Bun consumers. Co-authored-by: Cursor --- .../fix-global-wallet-release-blockers.md | 48 ++ .github/workflows/sei-global-wallet-smoke.yml | 48 ++ bun.lock | 157 ++-- package.json | 1 + packages/sei-global-wallet/README.md | 120 ++- packages/sei-global-wallet/package.json | 28 +- packages/sei-global-wallet/src/eip6963.ts | 13 +- packages/sei-global-wallet/src/ethereum.ts | 2 +- packages/sei-global-wallet/src/index.ts | 3 +- .../src/lib/EIP6963Emitter.ts | 70 +- .../src/lib/__tests__/EIP6963Emitter.spec.ts | 108 ++- .../lib/__tests__/browserIntegration.spec.ts | 102 +++ .../src/lib/__tests__/config.spec.ts | 14 +- .../src/lib/__tests__/entrypoints.spec.ts | 22 + .../__tests__/registerSolanaStandard.spec.ts | 31 +- .../src/lib/browserGlobal.ts | 29 + packages/sei-global-wallet/src/lib/config.ts | 19 +- .../src/lib/dynamicClient.ts | 7 + .../src/lib/dynamicEthereum.ts | 3 + .../src/lib/dynamicFeatures.ts | 3 + .../src/lib/dynamicSolana.ts | 3 + .../src/lib/dynamicZerodev.ts | 3 + .../src/lib/registerSolanaStandard.ts | 25 +- packages/sei-global-wallet/src/lib/wallet.ts | 2 +- packages/sei-global-wallet/src/solana.ts | 3 +- packages/sei-global-wallet/src/zerodev.ts | 2 +- packages/sei-global-wallet/tsconfig.json | 3 +- scripts/check-sei-global-wallet.ts | 694 ++++++++++++++++++ 28 files changed, 1424 insertions(+), 139 deletions(-) create mode 100644 .changeset/fix-global-wallet-release-blockers.md create mode 100644 .github/workflows/sei-global-wallet-smoke.yml create mode 100644 packages/sei-global-wallet/src/lib/__tests__/browserIntegration.spec.ts create mode 100644 packages/sei-global-wallet/src/lib/__tests__/entrypoints.spec.ts create mode 100644 packages/sei-global-wallet/src/lib/browserGlobal.ts create mode 100644 packages/sei-global-wallet/src/lib/dynamicClient.ts create mode 100644 packages/sei-global-wallet/src/lib/dynamicEthereum.ts create mode 100644 packages/sei-global-wallet/src/lib/dynamicFeatures.ts create mode 100644 packages/sei-global-wallet/src/lib/dynamicSolana.ts create mode 100644 packages/sei-global-wallet/src/lib/dynamicZerodev.ts create mode 100644 scripts/check-sei-global-wallet.ts diff --git a/.changeset/fix-global-wallet-release-blockers.md b/.changeset/fix-global-wallet-release-blockers.md new file mode 100644 index 000000000..1730099e4 --- /dev/null +++ b/.changeset/fix-global-wallet-release-blockers.md @@ -0,0 +1,48 @@ +--- +"@sei-js/sei-global-wallet": patch +--- + +Fix the Sei Global Wallet browser, peer-dependency, EIP-6963, and packaging release blockers. + +- Pin `@dynamic-labs/global-wallet-client` to the audited 4.96.3 release and mirror its optional peer contract, including exact Dynamic AA, Solana web3, ZeroDev, and zkSync SSO versions plus the compatible Viem floor and wallet-standard ranges. +- Initialize Dynamic's required globals before loading its modules in browsers and edge-like SSR runtimes, without consumer bundler configuration and without replacing consumer-defined values. +- Dispatch the initial EIP-6963 announcement, re-announce on every provider request, expose cleanup helpers, use stable UUIDv4 provider metadata, and replace the non-square wordmark with the unmodified square black mark from the official Sei brand kit. +- Verify real npm and Bun consumers, all five entrypoints, EIP-6963 and Solana registration, ZeroDev resolution, esbuild and Vite browser runtimes, SSR imports, types, audits, and package contents. + +> [!WARNING] +> This release has a temporary consumer security waiver. Dynamic 4.96.3 transitively pins vulnerable `axios@1.16.0` and `uuid@11.1.0`, and dependency overrides in a library do not propagate. + +Complete npm root overrides without optional AA: + +```json +{ + "overrides": { + "axios": "1.18.0", + "uuid": "11.1.1", + "viem": { + "ws": "8.21.0" + } + } +} +``` + +Complete Bun root overrides without optional AA: + +```json +{ + "overrides": { + "axios": "1.18.0", + "uuid": "11.1.1" + } +} +``` + +The high-severity Axios issue applies to the Node HTTP adapter and requires a prerequisite prototype-pollution/interceptor pattern; browser wallet paths avoid that adapter. The UUID issue applies to v3/v5/v6 buffer APIs, while Dynamic's observed usage is v4. Those constraints reduce exploitability but do not remove the audit findings or the root-override requirement. + +Consumers enabling the optional ZeroDev / Dynamic AA path should use npm's package-scoped overrides to replace the exact vulnerable `bn.js@4.11.6` copies beneath `ethjs-unit` and `number-to-bn` with major-compatible `bn.js@4.12.5` (the GHSA fix floor is 4.12.3). This coexists with Solana's `bn.js@5.2.5` and produces a clean npm audit. + +Bun 1.3.14 does not support those scoped overrides. Bun consumers must not globally downgrade bn.js or upgrade ws because that breaks Solana/borsh bn5 or Jayson ws7 contracts. With the safe Axios/UUID overrides, a Bun consumer enabling AA retains the documented bn.js and Viem ws advisories as part of this explicit waiver. + +The ZeroDev browser path pins `viem@2.45.3` to avoid the `node:worker_threads` Vite externalization introduced by the previously tested Viem 2.55.19/Ox Tempo graph. npm scopes Viem's ws8 subtree to patched `ws@8.21.0` while preserving Jayson `ws@7.5.13` from its ws7 range. Bun preserves Viem `ws@8.18.3` and Jayson ws7 and accepts exactly GHSA-378v-28hj-76wf, GHSA-58qx-3vcg-4xpx, and GHSA-96hv-2xvq-fx4p. Browser checks invoke the released `./zerodev` export in both esbuild and Vite and reject worker externalization warnings. + +Dynamic's direct wallet/AA graph is 4.96.3. Regenerating the Bun lockfile proved the previous nested Dynamic 4.96.1 logger/message-transport subtree was stale rather than required by `@dynamic-labs-wallet/browser-wallet-client@1.0.92`'s compatible ranges. Clean npm/Bun graph and browser-metafile checks now reject any remaining Dynamic 4.96.1 runtime. diff --git a/.github/workflows/sei-global-wallet-smoke.yml b/.github/workflows/sei-global-wallet-smoke.yml new file mode 100644 index 000000000..31a805e79 --- /dev/null +++ b/.github/workflows/sei-global-wallet-smoke.yml @@ -0,0 +1,48 @@ +name: Sei Global Wallet Consumer Smoke + +on: + pull_request: + paths: + - '.changeset/**' + - '.github/workflows/sei-global-wallet-smoke.yml' + - 'bun.lock' + - 'package.json' + - 'packages/sei-global-wallet/**' + - 'scripts/check-sei-global-wallet.ts' + - 'tsconfig.base.json' + - 'tsconfig.test.json' + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + consumers: + name: npm, Bun, edge, and browser consumers + runs-on: ubuntu-latest + timeout-minutes: 20 + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + registry-url: 'https://registry.npmjs.org' + + - name: Setup Bun + uses: oven-sh/setup-bun@v2 + with: + bun-version: '1.3.14' + + - name: Install workspace dependencies + run: bun install --frozen-lockfile + + - name: Verify npm and waived Bun consumers + run: bun run test:sei-global-wallet-release diff --git a/bun.lock b/bun.lock index e6537aed8..638fa75d2 100644 --- a/bun.lock +++ b/bun.lock @@ -76,23 +76,31 @@ "name": "@sei-js/sei-global-wallet", "version": "1.4.1", "dependencies": { - "@dynamic-labs/global-wallet-client": "^4.60.1", - "@wallet-standard/wallet": "^1.1.0", + "@dynamic-labs/global-wallet-client": "4.96.3", + "events": "3.3.0", + "process": "0.11.10", }, "devDependencies": { "@solana/wallet-standard-features": "^1.2.0", - "@solana/web3.js": "^1.92.1", + "@solana/web3.js": "1.98.1", + "@wallet-standard/base": "^1.0.1", + "@wallet-standard/features": "^1.0.3", + "@wallet-standard/wallet": "^1.1.0", + "@zerodev/sdk": "5.5.7", "typescript": "^5.7.3", + "viem": "2.45.3", + "zksync-sso": "0.2.0", }, "peerDependencies": { - "@dynamic-labs/ethereum-aa": "^4.15.0", + "@dynamic-labs/ethereum-aa": "4.96.3", "@solana/wallet-standard-features": "^1.2.0", - "@solana/web3.js": "^1.92.1", + "@solana/web3.js": "1.98.1", "@wallet-standard/base": "^1.0.1", "@wallet-standard/features": "^1.0.3", "@wallet-standard/wallet": "^1.1.0", - "@zerodev/sdk": "5.4.36", - "viem": "^2.7.12", + "@zerodev/sdk": "5.5.7", + "viem": "2.45.3", + "zksync-sso": "0.2.0", }, "optionalPeers": [ "@dynamic-labs/ethereum-aa", @@ -103,6 +111,7 @@ "@wallet-standard/wallet", "@zerodev/sdk", "viem", + "zksync-sso", ], }, }, @@ -179,9 +188,9 @@ "@colors/colors": ["@colors/colors@1.5.0", "", {}, "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ=="], - "@dynamic-labs-sdk/assert-package-version": ["@dynamic-labs-sdk/assert-package-version@1.20.0", "", {}, "sha512-mde7Cc4P/fSDlvFMqD9D0uTToJeQzRxAq4N0ph94QSGVppAO4hL/tlE8StySVIXZlN2Ku1L+7DKDurMaHnzmSg=="], + "@dynamic-labs-sdk/assert-package-version": ["@dynamic-labs-sdk/assert-package-version@1.27.1", "", {}, "sha512-eO5RCFOJ9L8QkJAuo5IJBam7QWvljr6dqThBZt1zPxu5BWmxGgDg8BxN0D3GqbI22kjLhMJRkkPLUTIUPVraVg=="], - "@dynamic-labs-sdk/client": ["@dynamic-labs-sdk/client@1.20.0", "", { "dependencies": { "@dynamic-labs-sdk/assert-package-version": "1.20.0", "@dynamic-labs-wallet/browser-wallet-client": "1.0.70", "@dynamic-labs-wallet/forward-mpc-client": "1.0.1", "@dynamic-labs/sdk-api-core": "0.0.1074", "@simplewebauthn/browser": "13.1.0", "ably": "2.17.1", "buffer": "6.0.3", "eventemitter3": "5.0.1", "zod": "4.0.5" }, "peerDependencies": { "@react-native-async-storage/async-storage": "^2.2.0", "react-native": ">=0.73.6", "react-native-inappbrowser-reborn": "^3.7.0", "react-native-keychain": "^10.0.0", "react-native-passkey": ">=3.3.2" }, "optionalPeers": ["@react-native-async-storage/async-storage", "react-native", "react-native-inappbrowser-reborn", "react-native-keychain", "react-native-passkey"] }, "sha512-D5yEBgY5NaBQdz9OnpWd2Kxu8QnXDTAqvxoRorIdF35KIZje3ily+tqEZUYP44cirWKKxyakIcyu6AO3y3chMg=="], + "@dynamic-labs-sdk/client": ["@dynamic-labs-sdk/client@1.27.1", "", { "dependencies": { "@dynamic-labs-sdk/assert-package-version": "1.27.1", "@dynamic-labs-wallet/browser-wallet-client": "1.0.99", "@dynamic-labs-wallet/forward-mpc-client": "1.0.1", "@dynamic-labs/sdk-api-core": "0.0.1125", "@simplewebauthn/browser": "13.1.0", "ably": "2.17.1", "buffer": "6.0.3", "eventemitter3": "5.0.1", "zod": "4.0.5" }, "peerDependencies": { "@react-native-async-storage/async-storage": "^2.2.0", "react-native": ">=0.73.6", "react-native-inappbrowser-reborn": "^3.7.0", "react-native-keychain": "^10.0.0", "react-native-passkey": ">=3.3.2" }, "optionalPeers": ["@react-native-async-storage/async-storage", "react-native", "react-native-inappbrowser-reborn", "react-native-keychain", "react-native-passkey"] }, "sha512-9ahR6VgUEbPCc7TTBvCG4AmfCQtO0vGRt+X3/pcQN3IjogPQ+nmxjjR/2Iqcp1aE2p9B+nnYJUHWWRSaAkpG8w=="], "@dynamic-labs-wallet/browser-wallet-client": ["@dynamic-labs-wallet/browser-wallet-client@1.0.92", "", { "dependencies": { "@dynamic-labs-wallet/core": "1.0.92", "@dynamic-labs/logger": "^4.81.0", "@dynamic-labs/message-transport": "^4.81.0" } }, "sha512-9jKkTl5PnQ482lAf642PTC+hI10Zyq2yJyjFkSOjfekVNYLXLhmBk5mZn3x3QlLW+jmk6bVAejQ5xpZJU4lJAQ=="], @@ -191,37 +200,37 @@ "@dynamic-labs-wallet/forward-mpc-shared": ["@dynamic-labs-wallet/forward-mpc-shared@0.7.1", "", { "dependencies": { "@noble/ciphers": "^0.4.1", "@noble/hashes": "^2.0.0", "@noble/post-quantum": "^0.5.1", "fp-ts": "^2.16.11", "io-ts": "^2.2.22" }, "peerDependencies": { "@dynamic-labs-wallet/primitives": ">=0.0.336 || 0.0.1" } }, "sha512-GPTYQ55z0nj18bkEAJEgvodH0l8phE03hY3VDOz1J4U91bFL+BKh6tjJQU6uycAhP/DouZggPYr0qKi/RBBdbA=="], - "@dynamic-labs-wallet/primitives": ["@dynamic-labs-wallet/primitives@1.0.92", "", {}, "sha512-/v2ZNA4rxoMf9hoo2CVzTG9BceS/UVfkKPNmXUqsjqEkl/KQAA0p0fTCeba8FGLjUtub/U1UmmU9SpNlCU8/+Q=="], + "@dynamic-labs-wallet/primitives": ["@dynamic-labs-wallet/primitives@1.0.99", "", {}, "sha512-ASfmh3Gjl3+IX56Yh4eeZL+zJpWqqCIYp5gzRGLvFRzQCxhmKgmOCfuzUxbVmFAGGzrnM4LO5yFQGQRxBIkxyQ=="], - "@dynamic-labs/assert-package-version": ["@dynamic-labs/assert-package-version@4.96.1", "", { "dependencies": { "@dynamic-labs/logger": "4.96.1" } }, "sha512-h3MGktUfvVCPs6T5x35jiORRTEX7/1TZjYGlgg+gH4FvTItzdksujQc7vUOMkwGVwxMSiDo8vPzqk5OKX8BREQ=="], + "@dynamic-labs/assert-package-version": ["@dynamic-labs/assert-package-version@4.96.3", "", { "dependencies": { "@dynamic-labs/logger": "4.96.3" } }, "sha512-x+UGpnia+yO8g6E00iVi1V0Pp6W6too+WZUpIqH1+lL5SjH5HcjSwpSPOo6viciRwBF4ZbmZooBG2RYmFgQ2Yg=="], - "@dynamic-labs/ethereum-aa-core": ["@dynamic-labs/ethereum-aa-core@4.96.1", "", { "dependencies": { "@dynamic-labs/assert-package-version": "4.96.1", "@dynamic-labs/ethereum-core": "4.96.1", "@dynamic-labs/sdk-api-core": "0.0.1093", "@dynamic-labs/types": "4.96.1", "@dynamic-labs/utils": "4.96.1", "@dynamic-labs/wallet-book": "4.96.1", "@dynamic-labs/wallet-connector-core": "4.96.1" }, "peerDependencies": { "viem": "^2.45.3" } }, "sha512-nj1zkPKdY7IE9g1UxCGwsUaT3A+ZDojW+AW9MSl+KW9uvOkqJTXXR9NoZvXKWjDn/+XzP0+V9coFz5vwxPmzMg=="], + "@dynamic-labs/ethereum-aa-core": ["@dynamic-labs/ethereum-aa-core@4.96.3", "", { "dependencies": { "@dynamic-labs/assert-package-version": "4.96.3", "@dynamic-labs/ethereum-core": "4.96.3", "@dynamic-labs/sdk-api-core": "0.12.0", "@dynamic-labs/types": "4.96.3", "@dynamic-labs/utils": "4.96.3", "@dynamic-labs/wallet-book": "4.96.3", "@dynamic-labs/wallet-connector-core": "4.96.3" }, "peerDependencies": { "viem": "^2.45.3" } }, "sha512-B4RBIpbUI4dc6xv6h6sU++4z+wjUVc86jS5zK2TNilfYNg2HfxNbVBY67ecIYAJQQSLh73NKTeMWKkpDVzdaew=="], - "@dynamic-labs/ethereum-aa-zksync": ["@dynamic-labs/ethereum-aa-zksync@4.96.1", "", { "dependencies": { "@dynamic-labs/assert-package-version": "4.96.1", "@dynamic-labs/ethereum-aa-core": "4.96.1", "@dynamic-labs/ethereum-core": "4.96.1", "@dynamic-labs/sdk-api-core": "0.0.1093", "@dynamic-labs/types": "4.96.1", "@dynamic-labs/utils": "4.96.1", "@dynamic-labs/wallet-book": "4.96.1", "@dynamic-labs/wallet-connector-core": "4.96.1", "zksync-sso": "0.2.0" }, "peerDependencies": { "viem": "^2.45.3" } }, "sha512-P5rtWY4nxyLTBufwjfdevApBA0w+3zuJxkjZamFqHWRovfKi2E/JBhpOssVzW7PkbQTCjAHDARWAR9czARUs5w=="], + "@dynamic-labs/ethereum-aa-zksync": ["@dynamic-labs/ethereum-aa-zksync@4.96.3", "", { "dependencies": { "@dynamic-labs/assert-package-version": "4.96.3", "@dynamic-labs/ethereum-aa-core": "4.96.3", "@dynamic-labs/ethereum-core": "4.96.3", "@dynamic-labs/sdk-api-core": "0.12.0", "@dynamic-labs/types": "4.96.3", "@dynamic-labs/utils": "4.96.3", "@dynamic-labs/wallet-book": "4.96.3", "@dynamic-labs/wallet-connector-core": "4.96.3", "zksync-sso": "0.2.0" }, "peerDependencies": { "viem": "^2.45.3" } }, "sha512-cv8BFyHK3KvCo4vphbFPnBX/RP6ndCxte/RNqSlxZ1bgw9g0A5AJZ6e821Z0CKv3NjixJ4QBcGM2IBIBl0PteA=="], - "@dynamic-labs/ethereum-core": ["@dynamic-labs/ethereum-core@4.96.1", "", { "dependencies": { "@dynamic-labs/assert-package-version": "4.96.1", "@dynamic-labs/logger": "4.96.1", "@dynamic-labs/rpc-providers": "4.96.1", "@dynamic-labs/sdk-api-core": "0.0.1093", "@dynamic-labs/types": "4.96.1", "@dynamic-labs/utils": "4.96.1", "@dynamic-labs/wallet-book": "4.96.1", "@dynamic-labs/wallet-connector-core": "4.96.1" }, "peerDependencies": { "viem": "^2.45.3" } }, "sha512-fXjWHi/COfkYl8nr5cAVj02qsGredC7vYW2YOoR83qnFWwXEQipK4/AxxIxrmCLSeeBER9sUzjfXESKcYnmoDA=="], + "@dynamic-labs/ethereum-core": ["@dynamic-labs/ethereum-core@4.96.3", "", { "dependencies": { "@dynamic-labs/assert-package-version": "4.96.3", "@dynamic-labs/logger": "4.96.3", "@dynamic-labs/rpc-providers": "4.96.3", "@dynamic-labs/sdk-api-core": "0.12.0", "@dynamic-labs/types": "4.96.3", "@dynamic-labs/utils": "4.96.3", "@dynamic-labs/wallet-book": "4.96.3", "@dynamic-labs/wallet-connector-core": "4.96.3" }, "peerDependencies": { "viem": "^2.45.3" } }, "sha512-wx1JqIeVbc38ghODYk8F21jHvPTdTKd7OMp0CZu5+4JETbFij8wl/FS5UrbrkBUi5hbrpLVyGqxIkfV3b+GIcg=="], - "@dynamic-labs/global-wallet-client": ["@dynamic-labs/global-wallet-client@4.96.1", "", { "dependencies": { "@dynamic-labs/assert-package-version": "4.96.1", "@dynamic-labs/ethereum-aa-zksync": "4.96.1", "@dynamic-labs/logger": "4.96.1", "@dynamic-labs/message-transport": "4.96.1", "@dynamic-labs/store": "4.96.1", "@dynamic-labs/types": "4.96.1", "@dynamic-labs/utils": "4.96.1", "eventemitter3": "5.0.1" }, "peerDependencies": { "@dynamic-labs/ethereum-aa": "4.96.1", "@solana/wallet-standard-features": "^1.2.0", "@solana/web3.js": "1.98.1", "@wallet-standard/base": "^1.0.1", "@wallet-standard/features": "^1.0.3", "@wallet-standard/wallet": "^1.1.0", "@zerodev/sdk": "5.5.7", "viem": "^2.45.3", "zksync-sso": "0.2.0" }, "optionalPeers": ["@dynamic-labs/ethereum-aa", "@solana/wallet-standard-features", "@solana/web3.js", "@wallet-standard/base", "@wallet-standard/features", "@wallet-standard/wallet", "@zerodev/sdk", "viem", "zksync-sso"] }, "sha512-vWM5ohYSRXXwJZLqC3Vv8VABNlRomMkfug08f6P8pJ5V8PPYFVx/WBie79WogSRp8zLi2dQTAEFDJuSxsJVVTw=="], + "@dynamic-labs/global-wallet-client": ["@dynamic-labs/global-wallet-client@4.96.3", "", { "dependencies": { "@dynamic-labs/assert-package-version": "4.96.3", "@dynamic-labs/ethereum-aa-zksync": "4.96.3", "@dynamic-labs/logger": "4.96.3", "@dynamic-labs/message-transport": "4.96.3", "@dynamic-labs/store": "4.96.3", "@dynamic-labs/types": "4.96.3", "@dynamic-labs/utils": "4.96.3", "eventemitter3": "5.0.1" }, "peerDependencies": { "@dynamic-labs/ethereum-aa": "4.96.3", "@solana/wallet-standard-features": "^1.2.0", "@solana/web3.js": "1.98.1", "@wallet-standard/base": "^1.0.1", "@wallet-standard/features": "^1.0.3", "@wallet-standard/wallet": "^1.1.0", "@zerodev/sdk": "5.5.7", "viem": "^2.45.3", "zksync-sso": "0.2.0" }, "optionalPeers": ["@dynamic-labs/ethereum-aa", "@solana/wallet-standard-features", "@solana/web3.js", "@wallet-standard/base", "@wallet-standard/features", "@wallet-standard/wallet", "@zerodev/sdk", "viem", "zksync-sso"] }, "sha512-DUdGRbJXzrlgwVIYudSJGZSOkBhcFG1GRCnGd9/KlRI5v3BssXkl5Stg27lPmwdq7a497kM5fNSCoX6gm/bJQQ=="], - "@dynamic-labs/iconic": ["@dynamic-labs/iconic@4.96.1", "", { "dependencies": { "@dynamic-labs/assert-package-version": "4.96.1", "@dynamic-labs/logger": "4.96.1", "sharp": "0.35.0", "url": "0.11.0" }, "peerDependencies": { "react": ">=18.0.0 <20.0.0", "react-dom": ">=18.0.0 <20.0.0" } }, "sha512-eGspUTCASO+MgGo+8UImKHJBBbaSby2hUTLi1Bqy9s6H/El9PhNek9TeYWrez8VrGgKZLOAvcq9YEEH3FxAYLA=="], + "@dynamic-labs/iconic": ["@dynamic-labs/iconic@4.96.3", "", { "dependencies": { "@dynamic-labs/assert-package-version": "4.96.3", "@dynamic-labs/logger": "4.96.3", "sharp": "0.35.0", "url": "0.11.0" }, "peerDependencies": { "react": ">=18.0.0 <20.0.0", "react-dom": ">=18.0.0 <20.0.0" } }, "sha512-j0/9Ai+nvvkoBtp4vRax0HT+KnL/qZC85bIxwAUXpfBwKmNQDtWqJXfcpkXDgou0kLsZhJzAbJQbSTJfecNmbA=="], - "@dynamic-labs/logger": ["@dynamic-labs/logger@4.96.1", "", { "dependencies": { "eventemitter3": "5.0.1" } }, "sha512-O/9VUliqsiWWB79VZKsbA+mUI/5oppdCOYzEyB/wZ4EF5HamIqY98NBdEl/isUdCCVbOL7DA/bK7Hf0ThBocmg=="], + "@dynamic-labs/logger": ["@dynamic-labs/logger@4.96.3", "", { "dependencies": { "eventemitter3": "5.0.1" } }, "sha512-fI6BFQbAQZrAD8mCw8DQXiyt8BeRIKGktAxGaoFFlsgw0pHcIv0rBW7BKW/I9LH4UPUZnpaV+y9S5C2jv0lrZA=="], - "@dynamic-labs/message-transport": ["@dynamic-labs/message-transport@4.96.1", "", { "dependencies": { "@dynamic-labs/assert-package-version": "4.96.1", "@dynamic-labs/logger": "4.96.1", "@dynamic-labs/utils": "4.96.1", "@vue/reactivity": "^3.4.21", "eventemitter3": "5.0.1" } }, "sha512-fFwbrzfTZGKrz+F+8g0Hsaf3fWxvaUopqqyVNHZ17COnS0N87O9ZfRKgKNy1oXQ7pwRnq4HLdrOawpWRFNcRqw=="], + "@dynamic-labs/message-transport": ["@dynamic-labs/message-transport@4.96.3", "", { "dependencies": { "@dynamic-labs/assert-package-version": "4.96.3", "@dynamic-labs/logger": "4.96.3", "@dynamic-labs/utils": "4.96.3", "@vue/reactivity": "^3.4.21", "eventemitter3": "5.0.1" } }, "sha512-0zg9G/Hot8/sV9Q/WqpK1C3GJY3k/o9BWwhRLE2qRX1WwfGC6ghfaO5TP5oJKJ/+vXuMY2l8GN5Jah1ausT6ew=="], - "@dynamic-labs/rpc-providers": ["@dynamic-labs/rpc-providers@4.96.1", "", { "dependencies": { "@dynamic-labs/assert-package-version": "4.96.1", "@dynamic-labs/types": "4.96.1" } }, "sha512-5smNTPDUGqNQmePkUlbNpGxhYqITL8fRktpCe1kuZQ+K5qh4zMwF0BQS81ReUkXDfQajnpMGuhV+bqUlTqtoAw=="], + "@dynamic-labs/rpc-providers": ["@dynamic-labs/rpc-providers@4.96.3", "", { "dependencies": { "@dynamic-labs/assert-package-version": "4.96.3", "@dynamic-labs/types": "4.96.3" } }, "sha512-bAGV7JkZ55TUYjIkpLVDcZIJJqa7CLwMomeek0uSi7lGkJJTqrQDuYYF7M2sHOGFigQEJf9TQSSKEk2r+FFDBA=="], - "@dynamic-labs/sdk-api-core": ["@dynamic-labs/sdk-api-core@0.0.1093", "", {}, "sha512-NdtIGe5XlgY4ohvy//RHjokUiMJ/1BHA+IV12awIDwPfeR9+dp0gMKurlTIbnOqn0P95pbUQKdpbtxZmtCWDRw=="], + "@dynamic-labs/sdk-api-core": ["@dynamic-labs/sdk-api-core@0.12.0", "", {}, "sha512-3e7gCCljkGc3NHxg2sy/DhSlAAqxA6cJBX2eaNhqL26OQi/bzivadwtEaVWSJ430+gtO1+Aa779BCJ40/WO5vw=="], - "@dynamic-labs/store": ["@dynamic-labs/store@4.96.1", "", { "dependencies": { "@dynamic-labs/assert-package-version": "4.96.1", "@dynamic-labs/logger": "4.96.1" } }, "sha512-MiRhvov++gA1jZ7RG/WzgYFoL/0dVNbbAe8Y8moEvyUOOyt3RQLpYAOadPoZH3WdvE/VDCnFDOAMNebMlDnYQQ=="], + "@dynamic-labs/store": ["@dynamic-labs/store@4.96.3", "", { "dependencies": { "@dynamic-labs/assert-package-version": "4.96.3", "@dynamic-labs/logger": "4.96.3" } }, "sha512-N/xmCvDRGjz6y6mvEVOxA26T5fvW33yqo8e9cVRUGllBsI6BK9bV3Da/mP+ZxSbFXnc+X+yAf+K/YPtfg+yqVg=="], - "@dynamic-labs/types": ["@dynamic-labs/types@4.96.1", "", { "dependencies": { "@dynamic-labs/assert-package-version": "4.96.1", "@dynamic-labs/sdk-api-core": "0.0.1093" } }, "sha512-Vio1KRMVsPy0hiUorQoJ+tDlKJIkPi+zXd4gZBZABVMjTGiVuOdEZRap6SxACwfSjKh7amsyn6Aw2Md1fORwUw=="], + "@dynamic-labs/types": ["@dynamic-labs/types@4.96.3", "", { "dependencies": { "@dynamic-labs/assert-package-version": "4.96.3", "@dynamic-labs/sdk-api-core": "0.12.0" } }, "sha512-gqqkV4go3yQyVFHkYE/GsB515DvfAbsUngLkx/OKolSd5D+UkscTSNOrjBJlsc/yEbsdsO8/TyWUxdpl/aVKnQ=="], - "@dynamic-labs/utils": ["@dynamic-labs/utils@4.96.1", "", { "dependencies": { "@dynamic-labs/assert-package-version": "4.96.1", "@dynamic-labs/logger": "4.96.1", "@dynamic-labs/sdk-api-core": "0.0.1093", "@dynamic-labs/types": "4.96.1", "buffer": "6.0.3", "eventemitter3": "5.0.1", "tldts": "6.0.16" } }, "sha512-yCqhsyF2Ob9CpB2nHo7ThWggOHeC9xK53v+XKZ1EJ3pHauoLu9DpS3OySEZWz53vfHoFF4U+QYehYjWk840w1g=="], + "@dynamic-labs/utils": ["@dynamic-labs/utils@4.96.3", "", { "dependencies": { "@dynamic-labs/assert-package-version": "4.96.3", "@dynamic-labs/logger": "4.96.3", "@dynamic-labs/sdk-api-core": "0.12.0", "@dynamic-labs/types": "4.96.3", "buffer": "6.0.3", "eventemitter3": "5.0.1", "tldts": "6.0.16" } }, "sha512-du5wkV2N2IjJDZcoZPpCLb7uloDpdTHmxvW16pEwSfW2STbXEj4TE3cMpMGJQ1O/VQ9+8XjJLYeN2v9RHbJTnw=="], - "@dynamic-labs/wallet-book": ["@dynamic-labs/wallet-book@4.96.1", "", { "dependencies": { "@dynamic-labs/assert-package-version": "4.96.1", "@dynamic-labs/iconic": "4.96.1", "@dynamic-labs/logger": "4.96.1", "@dynamic-labs/utils": "4.96.1", "eventemitter3": "5.0.1", "util": "0.12.5", "zod": "4.0.5" }, "peerDependencies": { "react": ">=18.0.0 <20.0.0", "react-dom": ">=18.0.0 <20.0.0" } }, "sha512-EWwqA+WDEfOyuMPzGjlujA1Twl0ucnxOvQTNpeHj8YONU09m/KkprFZq5DqHpCFFGe6xCA64DU+GEcJjKgX1Rg=="], + "@dynamic-labs/wallet-book": ["@dynamic-labs/wallet-book@4.96.3", "", { "dependencies": { "@dynamic-labs/assert-package-version": "4.96.3", "@dynamic-labs/iconic": "4.96.3", "@dynamic-labs/logger": "4.96.3", "@dynamic-labs/utils": "4.96.3", "eventemitter3": "5.0.1", "util": "0.12.5", "zod": "4.0.5" }, "peerDependencies": { "react": ">=18.0.0 <20.0.0", "react-dom": ">=18.0.0 <20.0.0" } }, "sha512-Y76B/X1WFwn+7/77wTfZ5DG78Ag3hUG4NenZDAH5fTCgyCF75kAsQXI2Ar4nL7DBBr7S34mqiH0BcmGh8ObDKg=="], - "@dynamic-labs/wallet-connector-core": ["@dynamic-labs/wallet-connector-core@4.96.1", "", { "dependencies": { "@dynamic-labs-sdk/client": "1.20.0", "@dynamic-labs-wallet/browser-wallet-client": "1.0.92", "@dynamic-labs-wallet/forward-mpc-client": "1.0.1", "@dynamic-labs/assert-package-version": "4.96.1", "@dynamic-labs/logger": "4.96.1", "@dynamic-labs/rpc-providers": "4.96.1", "@dynamic-labs/sdk-api-core": "0.0.1093", "@dynamic-labs/types": "4.96.1", "@dynamic-labs/utils": "4.96.1", "@dynamic-labs/wallet-book": "4.96.1", "eventemitter3": "5.0.1" } }, "sha512-w6J6xCE49PE6qPNQX6spcCRnGIWy9FTrbMNC/9awe2WjjlGELiqfFpSjh0euyDEfcHMUvKJwZ5DoWGyGi4xU8Q=="], + "@dynamic-labs/wallet-connector-core": ["@dynamic-labs/wallet-connector-core@4.96.3", "", { "dependencies": { "@dynamic-labs-sdk/client": "1.27.1", "@dynamic-labs-wallet/browser-wallet-client": "1.0.92", "@dynamic-labs-wallet/forward-mpc-client": "1.0.1", "@dynamic-labs/assert-package-version": "4.96.3", "@dynamic-labs/logger": "4.96.3", "@dynamic-labs/rpc-providers": "4.96.3", "@dynamic-labs/sdk-api-core": "0.12.0", "@dynamic-labs/types": "4.96.3", "@dynamic-labs/utils": "4.96.3", "@dynamic-labs/wallet-book": "4.96.3", "eventemitter3": "5.0.1" } }, "sha512-DmdwelVqaTHDinznFfE5mPAsTWPSt7Ppq96ayh4uJTGjm81/xQY6y/h6ZTVHw+4kh5g6B8XUrEZZlB4daVLR4g=="], "@emnapi/runtime": ["@emnapi/runtime@1.11.3", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA=="], @@ -281,7 +290,7 @@ "@hexagon/base64": ["@hexagon/base64@1.1.28", "", {}, "sha512-lhqDEAvWixy3bZ+UOYbPwUbBkwBq5C1LAJ/xPC8Oi+lL54oyakv/npbA0aU2hgCsx/1NUd4IBvV03+aUBWxerw=="], - "@hono/node-server": ["@hono/node-server@2.1.0", "", { "peerDependencies": { "hono": "^4" } }, "sha512-XovyyCCnBzW+zKu+z/zq8hwNs4KOR5rEMAOxo2f40Q5xoOI37IMm6MIg2COOUtUApo0i6850MTBKH2u4QLGIqg=="], + "@hono/node-server": ["@hono/node-server@2.1.1", "", { "peerDependencies": { "hono": "^4" } }, "sha512-ELuehkj5VCBdgEw9zs+ivkKwyzzUCSQuE96YmiPvn1ECBoZCczbFXJLeEGMTYjphP6gydh4pHMqEYPVMYUVgQg=="], "@img/colour": ["@img/colour@1.1.0", "", {}, "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ=="], @@ -367,33 +376,33 @@ "@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="], - "@peculiar/asn1-android": ["@peculiar/asn1-android@2.8.0", "", { "dependencies": { "@peculiar/asn1-schema": "^2.8.0", "asn1js": "^3.0.10", "tslib": "^2.8.1" } }, "sha512-skLbS+IOGv1lUgDqtChr8xvtvEr3HMse/JGBaL2r1J1o/n7a8wqOrovMtlRq/UXLhxvmLaONP67hwtshgzwfzA=="], + "@peculiar/asn1-android": ["@peculiar/asn1-android@2.9.4", "", { "dependencies": { "@peculiar/asn1-schema": "^2.9.4", "asn1js": "^3.0.10", "tslib": "^2.8.1" } }, "sha512-SYHm4SoWSI0nRCoos6jpGusIqhPH9bbGBqv7ohlZ+H6BunrDzzQPk2ePgDuEUzV82OdvbLgtW4twUDwhU9P3YQ=="], - "@peculiar/asn1-cms": ["@peculiar/asn1-cms@2.8.0", "", { "dependencies": { "@peculiar/asn1-schema": "^2.8.0", "@peculiar/asn1-x509": "^2.8.0", "@peculiar/asn1-x509-attr": "^2.8.0", "asn1js": "^3.0.10", "tslib": "^2.8.1" } }, "sha512-NgekZOrSJFSBFLFoLfwePguAWAx7z1+f2TEsWFUMyiqqfntZ4+S/S5hzqME3q4pCA0iOsFKdwiQ35dwY24eVqA=="], + "@peculiar/asn1-cms": ["@peculiar/asn1-cms@2.9.4", "", { "dependencies": { "@peculiar/asn1-schema": "^2.9.4", "@peculiar/asn1-x509": "^2.9.4", "@peculiar/asn1-x509-attr": "^2.9.4", "asn1js": "^3.0.10", "tslib": "^2.8.1" } }, "sha512-cben7oxmQsUGZqotus7yt0srYdncOT6RNWcTQ77T2RFOXejYVYkXadrfePdRcrVpO9K95IRLKKglG2k38jKXuw=="], - "@peculiar/asn1-csr": ["@peculiar/asn1-csr@2.8.0", "", { "dependencies": { "@peculiar/asn1-schema": "^2.8.0", "@peculiar/asn1-x509": "^2.8.0", "asn1js": "^3.0.10", "tslib": "^2.8.1" } }, "sha512-akbF8+uvleHs8sejNPQxwmVFuInAg6FMNHOwMILXfP518YfFJwdR3jr6oNUPOaEJfuEhn/vkNOCIT6ASUd4mbg=="], + "@peculiar/asn1-csr": ["@peculiar/asn1-csr@2.9.4", "", { "dependencies": { "@peculiar/asn1-schema": "^2.9.4", "@peculiar/asn1-x509": "^2.9.4", "asn1js": "^3.0.10", "tslib": "^2.8.1" } }, "sha512-xd4YN4vpRjkDAQWVfZZkeu12IEND7DOpkqaHSIHxZl1uggUNa9Ju0QxY2jHvDAS9pP0zhRBytg8ifsnGo3V0jw=="], - "@peculiar/asn1-ecc": ["@peculiar/asn1-ecc@2.8.0", "", { "dependencies": { "@peculiar/asn1-schema": "^2.8.0", "@peculiar/asn1-x509": "^2.8.0", "asn1js": "^3.0.10", "tslib": "^2.8.1" } }, "sha512-ohwlk+u9Rv2NOAY1c6MfHj45ATVF8R1DUN/WCgABiRtLi2ZftlZWZX7KvpAbU8v9xPcmoILfELeEABj/rn18AQ=="], + "@peculiar/asn1-ecc": ["@peculiar/asn1-ecc@2.9.4", "", { "dependencies": { "@peculiar/asn1-schema": "^2.9.4", "@peculiar/asn1-x509": "^2.9.4", "asn1js": "^3.0.10", "tslib": "^2.8.1" } }, "sha512-JJXefFshRAuVAjWQo/39bkg1ywc1VaiO44S8RRC+Ykvf/u2KDmYffoDb0ZBPCR5uJy4AGKQhl8mX+Q8ShcWaXQ=="], - "@peculiar/asn1-pfx": ["@peculiar/asn1-pfx@2.8.0", "", { "dependencies": { "@peculiar/asn1-cms": "^2.8.0", "@peculiar/asn1-pkcs8": "^2.8.0", "@peculiar/asn1-rsa": "^2.8.0", "@peculiar/asn1-schema": "^2.8.0", "asn1js": "^3.0.10", "tslib": "^2.8.1" } }, "sha512-5yof1ytoB++RQtaFbqSUJ8pxDJtZT6vbVqZ8XoJ61ph7UjNVvfFwAilnCodqkNsAodpy13gDhoxZXw00pghnyg=="], + "@peculiar/asn1-pfx": ["@peculiar/asn1-pfx@2.9.4", "", { "dependencies": { "@peculiar/asn1-cms": "^2.9.4", "@peculiar/asn1-pkcs8": "^2.9.4", "@peculiar/asn1-rsa": "^2.9.4", "@peculiar/asn1-schema": "^2.9.4", "asn1js": "^3.0.10", "tslib": "^2.8.1" } }, "sha512-khuGzHTzNzk4GDlIBEILyIs6Lce0yn0ZBdoI9v93kmNncfZRhD+AQ5ODFqdhvoE8cMJF/JMTQ8yA+t1D14kqCw=="], - "@peculiar/asn1-pkcs8": ["@peculiar/asn1-pkcs8@2.8.0", "", { "dependencies": { "@peculiar/asn1-schema": "^2.8.0", "@peculiar/asn1-x509": "^2.8.0", "asn1js": "^3.0.10", "tslib": "^2.8.1" } }, "sha512-qAKXtLpBEw9LqhKpjw3ajZSXlBur+ipW+y2ivVBQAG6F6qRx94yO+1ZR4mvw+YaCfKSaOzLeYEzsPaBp4SJELA=="], + "@peculiar/asn1-pkcs8": ["@peculiar/asn1-pkcs8@2.9.4", "", { "dependencies": { "@peculiar/asn1-schema": "^2.9.4", "@peculiar/asn1-x509": "^2.9.4", "asn1js": "^3.0.10", "tslib": "^2.8.1" } }, "sha512-duRdotlUx9eDZe6QrQpQKl61RbWykCHBCkKayP8V8XdEFwlKHZ8qGGDMyS6Pye7OX7nLFttTTpRkJeet78ckwQ=="], - "@peculiar/asn1-pkcs9": ["@peculiar/asn1-pkcs9@2.8.0", "", { "dependencies": { "@peculiar/asn1-cms": "^2.8.0", "@peculiar/asn1-pfx": "^2.8.0", "@peculiar/asn1-pkcs8": "^2.8.0", "@peculiar/asn1-schema": "^2.8.0", "@peculiar/asn1-x509": "^2.8.0", "@peculiar/asn1-x509-attr": "^2.8.0", "asn1js": "^3.0.10", "tslib": "^2.8.1" } }, "sha512-b5nDWCnkV60+cQ141D6sVVwK9nz64R5n3zSVnklGd+ECdkW2Ol3U1a6yYFlalpSOaD557yuJB64A+q42jG7lUQ=="], + "@peculiar/asn1-pkcs9": ["@peculiar/asn1-pkcs9@2.9.4", "", { "dependencies": { "@peculiar/asn1-cms": "^2.9.4", "@peculiar/asn1-pfx": "^2.9.4", "@peculiar/asn1-pkcs8": "^2.9.4", "@peculiar/asn1-schema": "^2.9.4", "@peculiar/asn1-x509": "^2.9.4", "@peculiar/asn1-x509-attr": "^2.9.4", "asn1js": "^3.0.10", "tslib": "^2.8.1" } }, "sha512-kaL4cNxBpdQE2dKlyZBqz4ygCrwffO+8wfoxTEqM1Z8RadvCeELBRzcv0dzM8aY9azHMwODO5nxU65zXmhToOQ=="], - "@peculiar/asn1-rsa": ["@peculiar/asn1-rsa@2.8.0", "", { "dependencies": { "@peculiar/asn1-schema": "^2.8.0", "@peculiar/asn1-x509": "^2.8.0", "asn1js": "^3.0.10", "tslib": "^2.8.1" } }, "sha512-zHEUlCqB2mk7x2lxDwHHJy7hWZOPdGHVlsmITWKB5/PbQo61atbu9PJ/0r9dQNMwFzbKPXZ8uK8/91eUhRznSg=="], + "@peculiar/asn1-rsa": ["@peculiar/asn1-rsa@2.9.4", "", { "dependencies": { "@peculiar/asn1-schema": "^2.9.4", "@peculiar/asn1-x509": "^2.9.4", "asn1js": "^3.0.10", "tslib": "^2.8.1" } }, "sha512-pZ96eD1PptovcWQ/GSmuNFXd/7EQJNlKfDaNCyE2rx3W0v6QFelkzquVqRSRyyDXXCYD69ZXJDzZ8GhIiQzKoA=="], - "@peculiar/asn1-schema": ["@peculiar/asn1-schema@2.8.0", "", { "dependencies": { "@peculiar/utils": "^2.0.2", "asn1js": "^3.0.10", "tslib": "^2.8.1" } }, "sha512-7YT0U/ze0tF2QOBbE15gKZwy5tvgGyLRiRHLzhlbOpf7BT032oBSd0haZqXn5W6l26WLlu3dyxzjM+2638/z2Q=="], + "@peculiar/asn1-schema": ["@peculiar/asn1-schema@2.9.4", "", { "dependencies": { "@peculiar/utils": "^2.0.2", "asn1js": "^3.0.10", "tslib": "^2.8.1" } }, "sha512-GjzePcT9Iw8NzeOPf73iNS9xM+TBhd/FilAfP+RQGkTMQJTVWtytN3JHJACCjf/ABNau5S7mS3g+DcuxmRgYEg=="], - "@peculiar/asn1-x509": ["@peculiar/asn1-x509@2.8.0", "", { "dependencies": { "@peculiar/asn1-schema": "^2.8.0", "@peculiar/utils": "^2.0.2", "asn1js": "^3.0.10", "tslib": "^2.8.1" } }, "sha512-N0CMuhWUzsWEVq6F1q9X6+VKUnWzSW+cSVg+aPaGGwDdbFoFWTYgin5MHwXgpWd6y9COMBxnfy/Qc+Xc7F0Zwg=="], + "@peculiar/asn1-x509": ["@peculiar/asn1-x509@2.9.4", "", { "dependencies": { "@peculiar/asn1-schema": "^2.9.4", "@peculiar/utils": "^2.0.2", "asn1js": "^3.0.10", "tslib": "^2.8.1" } }, "sha512-CxhBo/RdEbMMob7T31ZdQjGuoyRFLVwrDzTn25bihzBasRg9kRm/0IxIPvhgQtcK/9dNcO1XQL2fuPugwELL0Q=="], - "@peculiar/asn1-x509-attr": ["@peculiar/asn1-x509-attr@2.8.0", "", { "dependencies": { "@peculiar/asn1-schema": "^2.8.0", "@peculiar/asn1-x509": "^2.8.0", "asn1js": "^3.0.10", "tslib": "^2.8.1" } }, "sha512-tHjkfS/qhMnmrlB2J9NhflQlQ7In3khO3CfmVrriOlpTeErY9ZIKOso1hQ5JQiyrJ7ShvqVPk7E5fQmbclkSKA=="], + "@peculiar/asn1-x509-attr": ["@peculiar/asn1-x509-attr@2.9.4", "", { "dependencies": { "@peculiar/asn1-schema": "^2.9.4", "@peculiar/asn1-x509": "^2.9.4", "asn1js": "^3.0.10", "tslib": "^2.8.1" } }, "sha512-ehQXbpQaQYycgu8OrvigwSPTFfVRcu0ECNYCWw+yzBp02Lw5paRqzzhUpfOgO2K38+WfFZuEz/0RPtam5g0OMg=="], "@peculiar/utils": ["@peculiar/utils@2.0.3", "", { "dependencies": { "tslib": "^2.8.1" } }, "sha512-+oL3HPFRIZ1St2K50lWCXiioIgSoxzz7R1J3uF6neO2yl1sgmpgY6XXJH4BdpoDkMWznQTeYF6oWNDZLCdQ4eQ=="], "@peculiar/x509": ["@peculiar/x509@1.14.3", "", { "dependencies": { "@peculiar/asn1-cms": "^2.6.0", "@peculiar/asn1-csr": "^2.6.0", "@peculiar/asn1-ecc": "^2.6.0", "@peculiar/asn1-pkcs9": "^2.6.0", "@peculiar/asn1-rsa": "^2.6.0", "@peculiar/asn1-schema": "^2.6.0", "@peculiar/asn1-x509": "^2.6.0", "pvtsutils": "^1.3.6", "reflect-metadata": "^0.2.2", "tslib": "^2.8.1", "tsyringe": "^4.10.0" } }, "sha512-C2Xj8FZ0uHWeCXXqX5B4/gVFQmtSkiuOolzAgutjTfseNOHT3pUjljDZsTSxXFGgio54bCzVFqmEOUrIVk8RDA=="], - "@publint/pack": ["@publint/pack@0.1.6", "", { "dependencies": { "tinyexec": "^1.2.4" } }, "sha512-3uVNyGcVplhPZSLVyeIpL7+cIRn1YCSNHLG/rUIlBQMVH8YuN9++YF+5+UDIIO9RW98dujiUoTltO7RDB5bFJA=="], + "@publint/pack": ["@publint/pack@0.1.7", "", { "dependencies": { "tinyexec": "^1.3.0" } }, "sha512-4EDEmvxWtgsCnnVeBvtFIFZtUhPPt1+bA9JrSwU4Sa//6oKtzCSlGGXYJr44OD9aGISymbieJ4mCKHUygUDU+g=="], "@scure/base": ["@scure/base@1.2.6", "", {}, "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg=="], @@ -427,7 +436,7 @@ "@solana/wallet-standard-features": ["@solana/wallet-standard-features@1.4.0", "", { "dependencies": { "@wallet-standard/base": "^1.1.0", "@wallet-standard/features": "^1.1.0" } }, "sha512-f0tAdqwM2aL6CiFbIgt9h5zKFp+mgY/iNGwoxPMTj9VSTeQj7d1GGSmWhZw0XWoZ4N/1tnKTKmYFq+Dyq08jRw=="], - "@solana/web3.js": ["@solana/web3.js@1.98.4", "", { "dependencies": { "@babel/runtime": "^7.25.0", "@noble/curves": "^1.4.2", "@noble/hashes": "^1.4.0", "@solana/buffer-layout": "^4.0.1", "@solana/codecs-numbers": "^2.1.0", "agentkeepalive": "^4.5.0", "bn.js": "^5.2.1", "borsh": "^0.7.0", "bs58": "^4.0.1", "buffer": "6.0.3", "fast-stable-stringify": "^1.0.0", "jayson": "^4.1.1", "node-fetch": "^2.7.0", "rpc-websockets": "^9.0.2", "superstruct": "^2.0.2" } }, "sha512-vv9lfnvjUsRiq//+j5pBdXig0IQdtzA0BRZ3bXEP4KaIyF1CcaydWqgyzQgfZMNIsWNWmG+AUHwPy4AHOD6gpw=="], + "@solana/web3.js": ["@solana/web3.js@1.98.1", "", { "dependencies": { "@babel/runtime": "^7.25.0", "@noble/curves": "^1.4.2", "@noble/hashes": "^1.4.0", "@solana/buffer-layout": "^4.0.1", "@solana/codecs-numbers": "^2.1.0", "agentkeepalive": "^4.5.0", "bn.js": "^5.2.1", "borsh": "^0.7.0", "bs58": "^4.0.1", "buffer": "6.0.3", "fast-stable-stringify": "^1.0.0", "jayson": "^4.1.1", "node-fetch": "^2.7.0", "rpc-websockets": "^9.0.2", "superstruct": "^2.0.2" } }, "sha512-gRAq1YPbfSDAbmho4kY7P/8iLIjMWXAzBJdP9iENFR+dFQSBSueHzjK/ou8fxhqHP9j+J4Msl4p/oDemFcIjlg=="], "@swc/helpers": ["@swc/helpers@0.5.23", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw=="], @@ -479,6 +488,8 @@ "@wallet-standard/wallet": ["@wallet-standard/wallet@1.1.1", "", { "dependencies": { "@wallet-standard/base": "^1.1.1" } }, "sha512-8WiRPaKk/wNNRZhB2eVhpR/JW7/aqTCMoZhgVUCujuzDmxxmGvsosMxdCG4NAdYkoyozAHCX8/xLtlWUn5mNdQ=="], + "@zerodev/sdk": ["@zerodev/sdk@5.5.7", "", { "dependencies": { "semver": "^7.6.0" }, "peerDependencies": { "viem": "^2.28.0" } }, "sha512-Sf4G13yi131H8ujun64obvXIpk1UWn64GiGJjfvGx8aIKg+OWTRz9AZHgGKK+bE/evAmqIg4nchuSvKPhOau1w=="], + "abitype": ["abitype@1.2.3", "", { "peerDependencies": { "typescript": ">=5.0.4", "zod": "^3.22.0 || ^4.0.0" }, "optionalPeers": ["typescript", "zod"] }, "sha512-Ofer5QUnuUdTFsBRwARMoWKOH1ND5ehwYhJ3OJ/BQO+StkwQjHw0XyVh4vDttzHB7QOFhPHa/o413PJ82gU/Tg=="], "ably": ["ably@2.17.1", "", { "dependencies": { "@ably/msgpack-js": "^0.4.0", "dequal": "^2.0.3", "fastestsmallesttextencoderdecoder": "^1.0.22", "got": "^11.8.5", "ulid": "^2.3.0", "ws": "^8.17.1" }, "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" }, "optionalPeers": ["react", "react-dom"] }, "sha512-70yfXHoM7JtJD/8FCtPD1gkWW0f+AJqbJp0PsqDAqiyxFB8cPFY+FuKHgNTYb8eRHKXq8hT1xiDphUcY0+GHnA=="], @@ -683,6 +694,8 @@ "eventemitter3": ["eventemitter3@5.0.1", "", {}, "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA=="], + "events": ["events@3.3.0", "", {}, "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q=="], + "eventsource": ["eventsource@3.0.7", "", { "dependencies": { "eventsource-parser": "^3.0.1" } }, "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA=="], "eventsource-parser": ["eventsource-parser@3.1.1", "", {}, "sha512-EKN1vKAMcZ8MlYMpaNuxN6R9yakzH6uajHcHVTqWJzvu5pWw9DyhbP35HH8MVBQ+dZjAfDxk+A8NiR9KWaXiyQ=="], @@ -763,7 +776,7 @@ "highlight.js": ["highlight.js@10.7.3", "", {}, "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A=="], - "hono": ["hono@4.13.2", "", {}, "sha512-JydRilDRkYBQMt9qR9U92mXxmbGqsqSn/IKOrh4e7/gEbn+0zSr8igTu0obwJoNGN4sez28DIql7FBHWydoJpA=="], + "hono": ["hono@4.13.3", "", {}, "sha512-r8AO2mYHoLxSHkgafNeC/BXyb2vWRxD3jem4Ts+ptav8oTG5FIRifAjuJEmZI4bSvvc2ns0GxmIYiZnHqN3mMw=="], "http-cache-semantics": ["http-cache-semantics@4.2.0", "", {}, "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ=="], @@ -773,7 +786,7 @@ "https-proxy-agent": ["https-proxy-agent@5.0.1", "", { "dependencies": { "agent-base": "6", "debug": "4" } }, "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA=="], - "human-id": ["human-id@4.2.0", "", { "bin": { "human-id": "dist/cli.js" } }, "sha512-K3GbkIWqyvvlpfhBPlbEvD97TtqBpAYA4kt+cn2lD2x2HuohzZCibcA2nOlnJT6exqvJLggoB5nv2dNf192nEA=="], + "human-id": ["human-id@4.2.1", "", { "bin": { "human-id": "dist/cli.js" } }, "sha512-zPGsiS+dWoTZtZ4AtpA9Y+BdSFSNWvnouNlWNoUFyAM6xHOHmdCvqO3k8AIbdamCOv4gUFUVNPf6rJFfc4UiJw=="], "humanize-ms": ["humanize-ms@1.2.1", "", { "dependencies": { "ms": "^2.0.0" } }, "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ=="], @@ -829,7 +842,7 @@ "jayson": ["jayson@4.3.0", "", { "dependencies": { "@types/connect": "^3.4.33", "@types/node": "^12.12.54", "@types/ws": "^7.4.4", "commander": "^2.20.3", "delay": "^5.0.0", "es6-promisify": "^5.0.0", "eyes": "^0.1.8", "isomorphic-ws": "^4.0.1", "json-stringify-safe": "^5.0.1", "stream-json": "^1.9.1", "uuid": "^8.3.2", "ws": "^7.5.10" }, "bin": { "jayson": "bin/jayson.js" } }, "sha512-AauzHcUcqs8OBnCHOkJY280VaTiCm57AbuO7lqzcw7JapGj50BisE3xhksye4zlTSR1+1tAz67wLTl8tEH1obQ=="], - "jose": ["jose@6.2.8", "", {}, "sha512-Bsdjwm3Qsd/P0jR+BHDe3LytDfY7WBq2HmCCLIwuVRHMuEC9ae7/R474GIUdF1NgCyZjzVo/A9DOiOBtXq8ZoQ=="], + "jose": ["jose@6.2.10", "", {}, "sha512-iiW7J9qRFlGxvCOIBDBDxFePQSn7ZMAnrYGhrrOo6siO/MIqwfyilLR27pkfDgUk+raLuzADS8A3S/KLBisc0g=="], "js-yaml": ["js-yaml@4.3.1", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ=="], @@ -887,7 +900,7 @@ "mri": ["mri@1.2.0", "", {}, "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA=="], - "ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], "mute-stream": ["mute-stream@1.0.0", "", {}, "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA=="], @@ -959,6 +972,8 @@ "prettier": ["prettier@2.8.8", "", { "bin": { "prettier": "bin-prettier.js" } }, "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q=="], + "process": ["process@0.11.10", "", {}, "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A=="], + "proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="], "proxy-from-env": ["proxy-from-env@2.1.0", "", {}, "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA=="], @@ -1183,12 +1198,16 @@ "@arethetypeswrong/core/typescript": ["typescript@5.6.1-rc", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-E3b2+1zEFu84jB0YQi9BORDjz9+jGbwwy1Zi3G0LUNw7a7cePUrHMRNy8aPh53nXpkFGVHSxIZo5vKTfYaFiBQ=="], - "@dynamic-labs-sdk/client/@dynamic-labs-wallet/browser-wallet-client": ["@dynamic-labs-wallet/browser-wallet-client@1.0.70", "", { "dependencies": { "@dynamic-labs-wallet/core": "1.0.70", "@dynamic-labs/logger": "^4.81.0", "@dynamic-labs/message-transport": "^4.81.0" } }, "sha512-n0iKSn1rj9rGrfDDvgqeW3rHc09TAp7k1S481NsyNbsdWkSkACXLD8YYggVIvvXVq7w/5MfOqp6b/ZjoF4bXKg=="], + "@dynamic-labs-sdk/client/@dynamic-labs-wallet/browser-wallet-client": ["@dynamic-labs-wallet/browser-wallet-client@1.0.99", "", { "dependencies": { "@dynamic-labs-wallet/core": "1.0.99", "@dynamic-labs/logger": "^5.0.0", "@dynamic-labs/message-transport": "^5.0.0" } }, "sha512-dyvqU6yAF5OvLpcLI8064qsLNniWE15mcLWf61KjimPsVryoon0vPU9xxmgxrvKtixx4I2LeQxDtlv7C1iyHMQ=="], - "@dynamic-labs-sdk/client/@dynamic-labs/sdk-api-core": ["@dynamic-labs/sdk-api-core@0.0.1074", "", {}, "sha512-bUkwDnREU6vSiQk5fv4NBWKCNxJOYHXgbOgh92J5gWH/M3ey1gaINRBXgQUMFFi81wsxGdyVto7266JY7QnnWw=="], + "@dynamic-labs-sdk/client/@dynamic-labs/sdk-api-core": ["@dynamic-labs/sdk-api-core@0.0.1125", "", {}, "sha512-DZiEWOJD9ibwJRknhp3sed2YALaE7d8DGyM0zXIaFNzQ0GpYABDlXSLRCAFnYOof1yK7qMsOlYq9C5WD5tf7Hg=="], "@dynamic-labs-sdk/client/zod": ["zod@4.0.5", "", {}, "sha512-/5UuuRPStvHXu7RS+gmvRf4NXrNxpSllGwDnCBcJZtQsKrviYXm54yDGV2KYNLT5kq0lHGcl7lqWJLgSaG+tgA=="], + "@dynamic-labs-wallet/core/@dynamic-labs-wallet/primitives": ["@dynamic-labs-wallet/primitives@1.0.92", "", {}, "sha512-/v2ZNA4rxoMf9hoo2CVzTG9BceS/UVfkKPNmXUqsjqEkl/KQAA0p0fTCeba8FGLjUtub/U1UmmU9SpNlCU8/+Q=="], + + "@dynamic-labs-wallet/core/@dynamic-labs/sdk-api-core": ["@dynamic-labs/sdk-api-core@0.0.1093", "", {}, "sha512-NdtIGe5XlgY4ohvy//RHjokUiMJ/1BHA+IV12awIDwPfeR9+dp0gMKurlTIbnOqn0P95pbUQKdpbtxZmtCWDRw=="], + "@dynamic-labs-wallet/forward-mpc-client/@noble/hashes": ["@noble/hashes@2.3.0", "", {}, "sha512-oN+QwyX7VSHotibwubG3kpzbwKrfnyR6OOO+3Nk/53ADL7FmgHHz4TgrbaYKvvOw09u6QTx0oiH1cNCIOuN0CQ=="], "@dynamic-labs-wallet/forward-mpc-shared/@noble/ciphers": ["@noble/ciphers@0.4.1", "", {}, "sha512-QCOA9cgf3Rc33owG0AYBB9wszz+Ul2kramWN8tXG44Gyciud/tbkEqvxRF/IpqQaBpRBNi9f4jdNxqB2CQCIXg=="], @@ -1209,6 +1228,8 @@ "@modelcontextprotocol/sdk/express": ["express@5.2.1", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.1", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "depd": "^2.0.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw=="], + "@modelcontextprotocol/sdk/zod": ["zod@4.0.5", "", {}, "sha512-/5UuuRPStvHXu7RS+gmvRf4NXrNxpSllGwDnCBcJZtQsKrviYXm54yDGV2KYNLT5kq0lHGcl7lqWJLgSaG+tgA=="], + "@noble/post-quantum/@noble/curves": ["@noble/curves@2.0.1", "", { "dependencies": { "@noble/hashes": "2.0.1" } }, "sha512-vs1Az2OOTBiP4q0pwjW5aF0xp9n4MxVrmkFBxc6EKZc6ddYx5gaZiAsZoq0uRRXWbi3AT/sBqn05eRPtn1JCPw=="], "@noble/post-quantum/@noble/hashes": ["@noble/hashes@2.0.1", "", {}, "sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw=="], @@ -1243,6 +1264,8 @@ "@sei-js/mcp-server/commander": ["commander@14.0.3", "", {}, "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw=="], + "@sei-js/sei-global-wallet/viem": ["viem@2.45.3", "", { "dependencies": { "@noble/curves": "1.9.1", "@noble/hashes": "1.8.0", "@scure/bip32": "1.7.0", "@scure/bip39": "1.6.0", "abitype": "1.2.3", "isows": "1.0.7", "ox": "0.12.1", "ws": "8.18.3" }, "peerDependencies": { "typescript": ">=5.0.4" }, "optionalPeers": ["typescript"] }, "sha512-axOD7rIbGiDHHA1MHKmpqqTz3CMCw7YpE/FVypddQMXL5i364VkNZh9JeEJH17NO484LaZUOMueo35IXyL76Mw=="], + "@solana/errors/chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="], "@solana/errors/commander": ["commander@14.0.3", "", {}, "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw=="], @@ -1277,6 +1300,8 @@ "clone-response/mimic-response": ["mimic-response@1.0.1", "", {}, "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ=="], + "debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], + "ethers/@noble/curves": ["@noble/curves@1.2.0", "", { "dependencies": { "@noble/hashes": "1.3.2" } }, "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw=="], "ethers/@noble/hashes": ["@noble/hashes@1.3.2", "", {}, "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ=="], @@ -1289,8 +1314,6 @@ "https-proxy-agent/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" }, "peerDependencies": { "supports-color": "*" }, "optionalPeers": ["supports-color"] }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], - "humanize-ms/ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], - "inquirer/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], "inquirer/wrap-ansi": ["wrap-ansi@6.2.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA=="], @@ -1321,7 +1344,7 @@ "rpc-websockets/@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="], - "send/ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + "rxjs/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], "string-width/strip-ansi": ["strip-ansi@7.2.0", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="], @@ -1337,9 +1360,11 @@ "yargs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], - "zksync-sso/ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + "@dynamic-labs-sdk/client/@dynamic-labs-wallet/browser-wallet-client/@dynamic-labs-wallet/core": ["@dynamic-labs-wallet/core@1.0.99", "", { "dependencies": { "@dynamic-labs-wallet/primitives": "1.0.99", "@dynamic-labs/sdk-api-core": "^0.0.1093", "axios": "1.16.0", "uuid": "11.1.0" }, "peerDependencies": { "@dynamic-labs-wallet/forward-mpc-client": "1.0.1" } }, "sha512-5/X3c0kAnRrpF0+U090ukoah7iSHw+/n3ct+Ul6+FtK7gBxlETWwczvHJC3OD1UVL8nK1MJLbrA/rpNGFnIVbQ=="], + + "@dynamic-labs-sdk/client/@dynamic-labs-wallet/browser-wallet-client/@dynamic-labs/logger": ["@dynamic-labs/logger@5.3.2", "", { "dependencies": { "eventemitter3": "5.0.1" } }, "sha512-BafajCDxq2tTg465Z1cJYMDnnQHUtEiuSUKkRd6HEZtbW1OQdY3yQFhkffZxxwdruqWC7/yXUUgqs4ngyTWOSw=="], - "@dynamic-labs-sdk/client/@dynamic-labs-wallet/browser-wallet-client/@dynamic-labs-wallet/core": ["@dynamic-labs-wallet/core@1.0.70", "", { "dependencies": { "@dynamic-labs-wallet/primitives": "1.0.70", "@dynamic-labs/sdk-api-core": "^0.0.984", "axios": "1.16.0", "uuid": "11.1.0" }, "peerDependencies": { "@dynamic-labs-wallet/forward-mpc-client": "1.0.1" } }, "sha512-brTbTiAwS2TEhB6G2lL43dFx9Bj19wB5GPngi49yiX6veQJkQP9kkqqcxv97zYSEIUbBaPP/GndkPSewXPXYew=="], + "@dynamic-labs-sdk/client/@dynamic-labs-wallet/browser-wallet-client/@dynamic-labs/message-transport": ["@dynamic-labs/message-transport@5.3.2", "", { "dependencies": { "@dynamic-labs/assert-package-version": "5.3.2", "@dynamic-labs/logger": "5.3.2", "@dynamic-labs/utils": "5.3.2", "@vue/reactivity": "^3.4.21", "eventemitter3": "5.0.1" } }, "sha512-bBx6+DM9U6bFGVkW8lgfCeZAWQQ29qTfVMhqsFzRSiy+C3ZV0EYQ9QnYZeIO6V3QHOLOuUZMnMEMpQfcc3gN/g=="], "@modelcontextprotocol/sdk/express/accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="], @@ -1363,9 +1388,11 @@ "@modelcontextprotocol/sdk/express/type-is": ["type-is@2.1.0", "", { "dependencies": { "content-type": "^2.0.0", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA=="], - "accepts/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], + "@sei-js/sei-global-wallet/viem/ox": ["ox@0.12.1", "", { "dependencies": { "@adraffy/ens-normalize": "^1.11.0", "@noble/ciphers": "^1.3.0", "@noble/curves": "1.9.1", "@noble/hashes": "^1.8.0", "@scure/bip32": "^1.7.0", "@scure/bip39": "^1.6.0", "abitype": "^1.2.3", "eventemitter3": "5.0.1" }, "peerDependencies": { "typescript": ">=5.4.0" }, "optionalPeers": ["typescript"] }, "sha512-uU0llpthaaw4UJoXlseCyBHmQ3bLrQmz9rRLIAUHqv46uHuae9SE+ukYBRIPVCnlEnHKuWjDUcDFHWx9gbGNoA=="], - "agent-base/debug/ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + "@sei-js/sei-global-wallet/viem/ws": ["ws@8.18.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg=="], + + "accepts/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], "ansi-align/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], @@ -1375,36 +1402,34 @@ "ethers/@types/node/undici-types": ["undici-types@6.19.8", "", {}, "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw=="], - "express-rate-limit/debug/ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], - "form-data/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], - "https-proxy-agent/debug/ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], - "inquirer/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], "read-yaml-file/js-yaml/argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="], - "router/debug/ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], - "type-is/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], "yargs/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], - "@dynamic-labs-sdk/client/@dynamic-labs-wallet/browser-wallet-client/@dynamic-labs-wallet/core/@dynamic-labs-wallet/primitives": ["@dynamic-labs-wallet/primitives@1.0.70", "", {}, "sha512-epxiBEyu5YVZPbj3jre4AkAht+yuf/9IfDzQiY5uUP4BoNGtn8ezveRAEFgTfhytyuyl1GiI78t6K7xW8Zi5LA=="], - - "@dynamic-labs-sdk/client/@dynamic-labs-wallet/browser-wallet-client/@dynamic-labs-wallet/core/@dynamic-labs/sdk-api-core": ["@dynamic-labs/sdk-api-core@0.0.984", "", {}, "sha512-smSL1nUDZ753Ldeb848GJufOzEMzkGUcDdxUVcfmfHnA8kEdmKO+c/4nfQEUeDNvaFxd9ueB9ZKTYkLC2t/uXg=="], + "@dynamic-labs-sdk/client/@dynamic-labs-wallet/browser-wallet-client/@dynamic-labs-wallet/core/@dynamic-labs/sdk-api-core": ["@dynamic-labs/sdk-api-core@0.0.1093", "", {}, "sha512-NdtIGe5XlgY4ohvy//RHjokUiMJ/1BHA+IV12awIDwPfeR9+dp0gMKurlTIbnOqn0P95pbUQKdpbtxZmtCWDRw=="], - "@modelcontextprotocol/sdk/express/accepts/negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="], + "@dynamic-labs-sdk/client/@dynamic-labs-wallet/browser-wallet-client/@dynamic-labs/message-transport/@dynamic-labs/assert-package-version": ["@dynamic-labs/assert-package-version@5.3.2", "", { "dependencies": { "@dynamic-labs/logger": "5.3.2" } }, "sha512-Ic5RWXoIJlVAhysclN9QCnHZ6I9YDzbZXUBo0aOtyrDq6QRGP+qImDj1+m7eiixyXA9BeVGeiQc4jDUlzJrQkg=="], - "@modelcontextprotocol/sdk/express/body-parser/content-type": ["content-type@2.0.0", "", {}, "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ=="], + "@dynamic-labs-sdk/client/@dynamic-labs-wallet/browser-wallet-client/@dynamic-labs/message-transport/@dynamic-labs/utils": ["@dynamic-labs/utils@5.3.2", "", { "dependencies": { "@dynamic-labs/assert-package-version": "5.3.2", "@dynamic-labs/logger": "5.3.2", "@dynamic-labs/sdk-api-core": "0.12.0", "@dynamic-labs/types": "5.3.2", "buffer": "6.0.3", "eventemitter3": "5.0.1", "tldts": "6.0.16" } }, "sha512-x0k2bQSFnNAlD2OxTWMiQrFlJdRGIUfCSBvOc/J5TDJ60RoEcwHF0ucMvZmpvhiUAuZkgzCuYrMkgjRQA1b4gA=="], - "@modelcontextprotocol/sdk/express/debug/ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + "@modelcontextprotocol/sdk/express/accepts/negotiator": ["negotiator@1.1.0", "", { "dependencies": { "content-type": "^2.1.0" } }, "sha512-NMPBRMJgiQHjbd8phG3Vebdx4kZ1H121rbl5IkMqeOsahptB9BKo/d7oJ3zTXqTgagn2bWlNSXkh0QUGM31RYg=="], - "@modelcontextprotocol/sdk/express/send/ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + "@modelcontextprotocol/sdk/express/body-parser/content-type": ["content-type@2.1.0", "", {}, "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag=="], - "@modelcontextprotocol/sdk/express/type-is/content-type": ["content-type@2.0.0", "", {}, "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ=="], + "@modelcontextprotocol/sdk/express/type-is/content-type": ["content-type@2.1.0", "", {}, "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag=="], "@modelcontextprotocol/sdk/express/type-is/media-typer": ["media-typer@1.1.1", "", {}, "sha512-yz3xRaG20c6/BOzvYoDaGtPmGscs7YivItZEEqe6GbwNfHuxu9YNmvnEkMzKldAGY4/80pRcQRZSEnhquk9XuQ=="], + + "@dynamic-labs-sdk/client/@dynamic-labs-wallet/browser-wallet-client/@dynamic-labs/message-transport/@dynamic-labs/utils/@dynamic-labs/sdk-api-core": ["@dynamic-labs/sdk-api-core@0.12.0", "", {}, "sha512-3e7gCCljkGc3NHxg2sy/DhSlAAqxA6cJBX2eaNhqL26OQi/bzivadwtEaVWSJ430+gtO1+Aa779BCJ40/WO5vw=="], + + "@dynamic-labs-sdk/client/@dynamic-labs-wallet/browser-wallet-client/@dynamic-labs/message-transport/@dynamic-labs/utils/@dynamic-labs/types": ["@dynamic-labs/types@5.3.2", "", { "dependencies": { "@dynamic-labs/assert-package-version": "5.3.2", "@dynamic-labs/sdk-api-core": "0.12.0" } }, "sha512-oHPrly4hXFehh5tFH20CS/5DPjKr6KLpQ9V05pEd36nFj3VrQCsTrW77VKSTRi8Wphnqqq0xUcX7dVv4g6QiZQ=="], + + "@modelcontextprotocol/sdk/express/accepts/negotiator/content-type": ["content-type@2.1.0", "", {}, "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag=="], } } diff --git a/package.json b/package.json index 30e25c712..b44c0b485 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "test:all": "bun run test", "test:coverage": "bun test --isolate --coverage --coverage-reporter=lcov packages", "test:create-sei-release": "bun run --cwd packages/create-sei test:release", + "test:sei-global-wallet-release": "bun scripts/check-sei-global-wallet.ts", "test:scripts": "bun test --isolate scripts", "typecheck": "tsc --project tsconfig.test.json" }, diff --git a/packages/sei-global-wallet/README.md b/packages/sei-global-wallet/README.md index aed7d1620..a792132f5 100644 --- a/packages/sei-global-wallet/README.md +++ b/packages/sei-global-wallet/README.md @@ -13,16 +13,132 @@ -## 🚀 Quick Start +> [!WARNING] +> **Temporary consumer security waiver:** Dynamic Global Wallet Client 4.96.3 transitively pins vulnerable `axios@1.16.0` and `uuid@11.1.0`. +> Dependency overrides are root-only in both npm and Bun; this package cannot propagate them to your application. Add the overrides below before installing. + +## Required consumer overrides + +Dependency overrides are root-only; this package cannot propagate them to an application. npm and Bun require different policies. + +Complete npm root overrides when the optional AA path is not enabled: +```json +{ + "overrides": { + "axios": "1.18.0", + "uuid": "11.1.1", + "viem": { + "ws": "8.21.0" + } + } +} +``` + +Complete Bun root overrides when the optional AA path is not enabled: +```json +{ + "overrides": { + "axios": "1.18.0", + "uuid": "11.1.1" + } +} +``` + +The Axios and UUID overrides are temporary until Dynamic updates its exact transitive pins: + +- The high-severity Axios issue is in the Node HTTP adapter and requires a prerequisite prototype-pollution/interceptor pattern. Browser wallet paths do not use that adapter, which reduces exploitability but does not make the vulnerable install acceptable. +- The UUID issue affects the v3, v5, and v6 buffer APIs. Dynamic's observed call sites use UUID v4, which reduces exploitability but does not clear the audit finding. + +Applications using the optional `./zerodev` / Dynamic account-abstraction path must also replace the vulnerable exact `bn.js@4.11.6` copies used by `ethjs-unit` and `number-to-bn`. The complete npm root override block is: +```json +{ + "overrides": { + "axios": "1.18.0", + "ethjs-unit": { + "bn.js": "4.12.5" + }, + "number-to-bn": { + "bn.js": "4.12.5" + }, + "uuid": "11.1.1", + "viem": { + "ws": "8.21.0" + } + } +} +``` + +Bun 1.3.14 does not support nested overrides. Do **not** globally override `bn.js` or `ws`: Solana/borsh require bn5 while Jayson requires ws7. Bun AA consumers use the same complete safe root block shown above for Bun: +```json +{ + "overrides": { + "axios": "1.18.0", + "uuid": "11.1.1" + } +} +``` + +For npm, scoped `bn.js@4.12.5` stays on the legacy dependencies' expected major while Solana resolves `bn.js@5.2.5`. Scoped `ws@8.21.0` patches Viem's ws8 subtree while Jayson resolves `ws@7.5.13` from its `^7.5.10` range. The result is audit-clean. + +The browser path is temporarily pinned to `viem@2.45.3`: the previously tested 2.55.19 pulls Ox Tempo's `node:worker_threads` path into Vite resolution, while 2.45.3 predates that path. + +For Bun, scoped overrides are unavailable. The selected waiver therefore accepts exactly these unresolved optional-AA advisories while preserving compatible majors: + +- `GHSA-378v-28hj-76wf` on `bn.js@4.11.6` — moderate, CVSS 5.3. +- `GHSA-58qx-3vcg-4xpx` on Viem's `ws@8.18.3` — moderate, CVSS 4.4. +- `GHSA-96hv-2xvq-fx4p` on Viem's `ws@8.18.3` — high, CVSS 7.5. + +Jayson remains on `ws@7.5.13`; globally forcing ws8 would violate that major contract. The verifier rejects every advisory outside this exact Bun set. + +## Quick start ```bash npm install @sei-js/sei-global-wallet ``` -Then import to register with EIP-6963 standard: +Then import the side-effect entrypoint to register with EIP-6963: ```javascript import '@sei-js/sei-global-wallet/eip6963'; ``` This single import enables Sei Global Wallet across all compatible wallet libraries (RainbowKit, ConnectKit, Web3-React, Wagmi, etc.). + +The entrypoint dispatches the required initial `eip6963:announceProvider` event and re-announces for every `eip6963:requestProvider` event. It is safe to import during SSR; registration occurs only in a browser. + +## Entrypoints + +- `@sei-js/sei-global-wallet` exports the configured wallet client and Dynamic wallet features. +- `@sei-js/sei-global-wallet/eip6963` registers the EIP-6963 provider and exports registration, cleanup, and stable provider-info helpers. +- `@sei-js/sei-global-wallet/ethereum` exports `createEIP1193Provider`. +- `@sei-js/sei-global-wallet/solana` registers the wallet-standard provider and exports `createSolanaWallet` and `registerSolanaStandard`. +- `@sei-js/sei-global-wallet/zerodev` exports `createKernelClient`. + +All entrypoints are ESM-only. The package installs missing `global` and `process` aliases before loading Dynamic code in browsers and edge-like SSR runtimes, while preserving consumer-defined values. Consumers do not need Vite, esbuild, or other bundler shims. + +## Optional peer versions + +The package mirrors Dynamic 4.96.3's optional peer contract. Install only the peers needed by the subpaths your application uses: + +- `@dynamic-labs/ethereum-aa@4.96.3` +- `@solana/web3.js@1.98.1` +- `@solana/wallet-standard-features@^1.2.0` +- `@wallet-standard/base@^1.0.1` +- `@wallet-standard/features@^1.0.3` +- `@wallet-standard/wallet@^1.1.0` +- `@zerodev/sdk@5.5.7` +- `viem@2.45.3` +- `zksync-sso@0.2.0` + +Dynamic's direct wallet and AA packages resolve to 4.96.3. A full Bun lockfile regeneration showed that the previous isolated Dynamic 4.96.1 subtree beneath `@dynamic-labs-wallet/browser-wallet-client@1.0.92` was stale: its `^4.81.0` ranges resolve compatibly without 4.96.1. Clean npm and Bun graphs now contain no Dynamic 4.96.1 packages, and browser metafile checks reject their return as direct runtime code. + +## Brand asset + +The EIP-6963 and wallet-standard icon is an exact, unrecolored data-URI encoding of the square black +[official Sei mark](https://github.com/sei-protocol/sei-docs/blob/8710d6078058bdf67ec704b346f75ee9883e25ea/assets/brand/logo/sei-mark.svg) +from the [Sei brand kit](https://brand.sei.io/). Its proportions, paths, and `#000000` fill are unchanged. +The pinned source includes its terminal newline and has SHA-256 `e288cd08b510afbc19f1ea85c990397de2cad2077459a6833d64e26f86b761fa`. + +## Release verification + +The dedicated `Sei Global Wallet Consumer Smoke` workflow runs on wallet-related pull-request paths and can be started manually with `workflow_dispatch` before release. It executes `bun run test:sei-global-wallet-release`, including an audit-clean scoped npm consumer, a waiver-aware Bun consumer, native and bundled edge-like SSR, real local ZeroDev provider operations in esbuild/Vite, dependency graphs, and package contents. Its output names the exact accepted Bun set: `GHSA-378v-28hj-76wf`, `GHSA-58qx-3vcg-4xpx`, and `GHSA-96hv-2xvq-fx4p`; the verifier fails if Bun reports any new, missing, or different advisory. Regular package tests remain deterministic and do not perform clean consumer installs. diff --git a/packages/sei-global-wallet/package.json b/packages/sei-global-wallet/package.json index 7c09f948e..395dedbb2 100644 --- a/packages/sei-global-wallet/package.json +++ b/packages/sei-global-wallet/package.json @@ -12,6 +12,7 @@ "module": "./dist/index.js", "types": "./dist/index.d.ts", "license": "ISC", + "sideEffects": true, "files": [ "dist" ], @@ -23,23 +24,31 @@ "test": "bun test --isolate src" }, "dependencies": { - "@dynamic-labs/global-wallet-client": "^4.60.1", - "@wallet-standard/wallet": "^1.1.0" + "@dynamic-labs/global-wallet-client": "4.96.3", + "events": "3.3.0", + "process": "0.11.10" }, "devDependencies": { "@solana/wallet-standard-features": "^1.2.0", - "@solana/web3.js": "^1.92.1", - "typescript": "^5.7.3" + "@solana/web3.js": "1.98.1", + "@wallet-standard/base": "^1.0.1", + "@wallet-standard/features": "^1.0.3", + "@wallet-standard/wallet": "^1.1.0", + "@zerodev/sdk": "5.5.7", + "typescript": "^5.7.3", + "viem": "2.45.3", + "zksync-sso": "0.2.0" }, "peerDependencies": { - "@dynamic-labs/ethereum-aa": "^4.15.0", + "@dynamic-labs/ethereum-aa": "4.96.3", "@solana/wallet-standard-features": "^1.2.0", - "@solana/web3.js": "^1.92.1", + "@solana/web3.js": "1.98.1", "@wallet-standard/base": "^1.0.1", "@wallet-standard/features": "^1.0.3", "@wallet-standard/wallet": "^1.1.0", - "@zerodev/sdk": "5.4.36", - "viem": "^2.7.12" + "@zerodev/sdk": "5.5.7", + "viem": "2.45.3", + "zksync-sso": "0.2.0" }, "peerDependenciesMeta": { "viem": { @@ -65,6 +74,9 @@ }, "@dynamic-labs/ethereum-aa": { "optional": true + }, + "zksync-sso": { + "optional": true } }, "typesVersions": { diff --git a/packages/sei-global-wallet/src/eip6963.ts b/packages/sei-global-wallet/src/eip6963.ts index 612b03ed4..eb09aeb43 100644 --- a/packages/sei-global-wallet/src/eip6963.ts +++ b/packages/sei-global-wallet/src/eip6963.ts @@ -1,3 +1,12 @@ -import { EIP6963Emitter } from './lib/EIP6963Emitter.js'; +import { registerEIP6963Provider } from './lib/EIP6963Emitter.js'; -EIP6963Emitter(); +registerEIP6963Provider(); + +export { + EIP6963Emitter, + type EIP6963ProviderDetail, + type EIP6963ProviderInfo, + eip6963ProviderInfo, + registerEIP6963Provider, + unregisterEIP6963Provider +} from './lib/EIP6963Emitter.js'; diff --git a/packages/sei-global-wallet/src/ethereum.ts b/packages/sei-global-wallet/src/ethereum.ts index 0e0e6cf54..f1faee111 100644 --- a/packages/sei-global-wallet/src/ethereum.ts +++ b/packages/sei-global-wallet/src/ethereum.ts @@ -1 +1 @@ -export { createEIP1193Provider } from '@dynamic-labs/global-wallet-client/ethereum'; +export { createEIP1193Provider } from './lib/dynamicEthereum.js'; diff --git a/packages/sei-global-wallet/src/index.ts b/packages/sei-global-wallet/src/index.ts index 4d52d312e..b2b388e20 100644 --- a/packages/sei-global-wallet/src/index.ts +++ b/packages/sei-global-wallet/src/index.ts @@ -1,5 +1,6 @@ import Wallet from './lib/wallet.js'; -export * from '@dynamic-labs/global-wallet-client/features'; +export * from './lib/dynamicFeatures.js'; +export { Wallet }; export default Wallet; diff --git a/packages/sei-global-wallet/src/lib/EIP6963Emitter.ts b/packages/sei-global-wallet/src/lib/EIP6963Emitter.ts index 4457d4b16..cf26426c3 100644 --- a/packages/sei-global-wallet/src/lib/EIP6963Emitter.ts +++ b/packages/sei-global-wallet/src/lib/EIP6963Emitter.ts @@ -1,16 +1,66 @@ -import type { DataURIImage } from '@dynamic-labs/global-wallet-client'; -import { announceEip6963Provider, createEIP1193Provider } from '@dynamic-labs/global-wallet-client/ethereum'; import { config } from './config.js'; +import type { DataURIImage } from './dynamicClient.js'; +import { createEIP1193Provider } from './dynamicEthereum.js'; import Wallet from './wallet.js'; -export const EIP6963Emitter = () => { - announceEip6963Provider({ - info: { - icon: config.walletIcon as DataURIImage, - uuid: config.environmentId, - name: config.walletName, - rdns: config.eip6963.rdns - }, +export interface EIP6963ProviderInfo { + icon: DataURIImage; + name: string; + rdns: string; + uuid: string; +} + +export interface EIP6963ProviderDetail { + info: Readonly; + provider: ReturnType; +} + +export const eip6963ProviderInfo: Readonly = Object.freeze({ + icon: config.walletIcon as DataURIImage, + name: config.walletName, + rdns: config.eip6963.rdns, + uuid: config.eip6963.uuid +}); + +const noCleanup = () => {}; +let activeCleanup: (() => void) | undefined; + +export const registerEIP6963Provider = (): (() => void) => { + if (typeof window === 'undefined' || typeof CustomEvent === 'undefined') return noCleanup; + if (activeCleanup) return activeCleanup; + + const browserWindow = window; + const detail: EIP6963ProviderDetail = Object.freeze({ + info: eip6963ProviderInfo, provider: createEIP1193Provider(Wallet) }); + const announceProvider = () => { + browserWindow.dispatchEvent( + new CustomEvent('eip6963:announceProvider', { + detail + }) + ); + }; + + browserWindow.addEventListener('eip6963:requestProvider', announceProvider); + + let active = true; + const cleanup = () => { + if (!active) return; + active = false; + browserWindow.removeEventListener('eip6963:requestProvider', announceProvider); + if (activeCleanup === cleanup) activeCleanup = undefined; + }; + + activeCleanup = cleanup; + announceProvider(); + + return cleanup; }; + +export const unregisterEIP6963Provider = () => { + activeCleanup?.(); +}; + +// Kept for compatibility with the original internal helper name. +export const EIP6963Emitter = registerEIP6963Provider; diff --git a/packages/sei-global-wallet/src/lib/__tests__/EIP6963Emitter.spec.ts b/packages/sei-global-wallet/src/lib/__tests__/EIP6963Emitter.spec.ts index ce8267478..1cc0ee7fd 100644 --- a/packages/sei-global-wallet/src/lib/__tests__/EIP6963Emitter.spec.ts +++ b/packages/sei-global-wallet/src/lib/__tests__/EIP6963Emitter.spec.ts @@ -1,40 +1,98 @@ -import { announceEip6963Provider, createEIP1193Provider } from '@dynamic-labs/global-wallet-client/ethereum'; -import { EIP6963Emitter } from '../EIP6963Emitter'; +import { afterEach, beforeEach, describe, expect, it, jest } from 'bun:test'; +import { createEIP1193Provider } from '../dynamicEthereum'; +import { type EIP6963ProviderDetail, eip6963ProviderInfo, registerEIP6963Provider, unregisterEIP6963Provider } from '../EIP6963Emitter'; import Wallet from '../wallet'; -jest.mock('@dynamic-labs/global-wallet-client/ethereum', () => ({ - announceEip6963Provider: jest.fn(), +jest.mock('../dynamicEthereum', () => ({ createEIP1193Provider: jest.fn() })); jest.mock('../wallet', () => ({})); -jest.mock('../config', () => ({ - config: { - walletIcon: 'icon-url', - environmentId: 'env-id', - walletName: 'SEI Wallet', - eip6963: { - rdns: 'com.sei.wallet' - } - } -})); describe('EIP6963Emitter', () => { - it('should announce the provider with correct config and provider instance', () => { - const mockProvider = { foo: 'bar' }; + const originalWindow = globalThis.window; + + beforeEach(() => { + unregisterEIP6963Provider(); + Object.defineProperty(globalThis, 'window', { + configurable: true, + value: new EventTarget() + }); + jest.clearAllMocks(); + }); + + afterEach(() => { + unregisterEIP6963Provider(); + Object.defineProperty(globalThis, 'window', { + configurable: true, + value: originalWindow + }); + }); + + it('announces immediately and again for every request', () => { + const mockProvider = { foo: 'bar' } as unknown as EIP6963ProviderDetail['provider']; (createEIP1193Provider as unknown as jest.Mock).mockReturnValue(mockProvider); + const announcements: EIP6963ProviderDetail[] = []; + window.addEventListener('eip6963:announceProvider', (event) => { + announcements.push((event as CustomEvent).detail); + }); - EIP6963Emitter(); + const cleanup = registerEIP6963Provider(); expect(createEIP1193Provider).toHaveBeenCalledWith(Wallet); - expect(announceEip6963Provider).toHaveBeenCalledWith({ - info: { - icon: 'icon-url', - uuid: 'env-id', - name: 'SEI Wallet', - rdns: 'com.sei.wallet' - }, - provider: mockProvider + expect(announcements).toEqual([ + { + info: eip6963ProviderInfo, + provider: mockProvider + } + ]); + + window.dispatchEvent(new Event('eip6963:requestProvider')); + window.dispatchEvent(new Event('eip6963:requestProvider')); + + expect(announcements).toHaveLength(3); + expect(announcements[1]).toBe(announcements[0]); + expect(announcements[2]).toBe(announcements[0]); + + cleanup(); + window.dispatchEvent(new Event('eip6963:requestProvider')); + expect(announcements).toHaveLength(3); + }); + + it('keeps one active request listener per registration', () => { + const mockProvider = { foo: 'bar' } as unknown as EIP6963ProviderDetail['provider']; + (createEIP1193Provider as unknown as jest.Mock).mockReturnValue(mockProvider); + const announcements: EIP6963ProviderDetail[] = []; + window.addEventListener('eip6963:announceProvider', (event) => { + announcements.push((event as CustomEvent).detail); + }); + + const firstCleanup = registerEIP6963Provider(); + const secondCleanup = registerEIP6963Provider(); + + expect(secondCleanup).toBe(firstCleanup); + expect(createEIP1193Provider).toHaveBeenCalledTimes(1); + + window.dispatchEvent(new Event('eip6963:requestProvider')); + expect(announcements).toHaveLength(2); + }); + + it('does nothing during SSR', () => { + Object.defineProperty(globalThis, 'window', { + configurable: true, + value: undefined }); + + const cleanup = registerEIP6963Provider(); + + expect(createEIP1193Provider).not.toHaveBeenCalled(); + expect(cleanup()).toBeUndefined(); + }); + + it('exports stable provider info', () => { + expect(eip6963ProviderInfo.name).toBe('Sei Global Wallet'); + expect(eip6963ProviderInfo.rdns).toBe('io.sei.global-wallet'); + expect(eip6963ProviderInfo.uuid).toMatch(/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i); + expect(Object.isFrozen(eip6963ProviderInfo)).toBe(true); }); }); diff --git a/packages/sei-global-wallet/src/lib/__tests__/browserIntegration.spec.ts b/packages/sei-global-wallet/src/lib/__tests__/browserIntegration.spec.ts new file mode 100644 index 000000000..609dd619b --- /dev/null +++ b/packages/sei-global-wallet/src/lib/__tests__/browserIntegration.spec.ts @@ -0,0 +1,102 @@ +import { afterAll, beforeAll, describe, expect, it } from 'bun:test'; + +class MemoryStorage implements Storage { + readonly #values = new Map(); + + get length() { + return this.#values.size; + } + + clear() { + this.#values.clear(); + } + + getItem(key: string) { + return this.#values.get(key) ?? null; + } + + key(index: number) { + return [...this.#values.keys()][index] ?? null; + } + + removeItem(key: string) { + this.#values.delete(key); + } + + setItem(key: string, value: string) { + this.#values.set(key, value); + } +} + +describe('browser registrations', () => { + const originalWindow = Object.getOwnPropertyDescriptor(globalThis, 'window'); + const originalStorage = Object.getOwnPropertyDescriptor(globalThis, 'localStorage'); + const browserWindow = new EventTarget(); + + beforeAll(() => { + Object.defineProperty(globalThis, 'window', { + configurable: true, + value: browserWindow + }); + Object.defineProperty(globalThis, 'localStorage', { + configurable: true, + value: new MemoryStorage() + }); + }); + + afterAll(() => { + if (originalWindow) Object.defineProperty(globalThis, 'window', originalWindow); + else delete (globalThis as { window?: unknown }).window; + + if (originalStorage) Object.defineProperty(globalThis, 'localStorage', originalStorage); + else delete (globalThis as { localStorage?: unknown }).localStorage; + }); + + it('announces EIP-6963 immediately and on every request', async () => { + const announcements: CustomEvent[] = []; + browserWindow.addEventListener('eip6963:announceProvider', (event) => { + announcements.push(event as CustomEvent); + }); + + const eip6963 = await import('../../eip6963'); + + expect(announcements).toHaveLength(1); + expect(announcements[0].detail.info).toEqual(eip6963.eip6963ProviderInfo); + expect(typeof announcements[0].detail.provider.request).toBe('function'); + + browserWindow.dispatchEvent(new Event('eip6963:requestProvider')); + browserWindow.dispatchEvent(new Event('eip6963:requestProvider')); + expect(announcements).toHaveLength(3); + expect(announcements[1].detail).toBe(announcements[0].detail); + expect(announcements[2].detail).toBe(announcements[0].detail); + + eip6963.unregisterEIP6963Provider(); + browserWindow.dispatchEvent(new Event('eip6963:requestProvider')); + expect(announcements).toHaveLength(3); + }); + + it('registers a real Solana wallet-standard provider', async () => { + const wallets: Array<{ icon: string; name: string }> = []; + browserWindow.addEventListener('wallet-standard:register-wallet', (event) => { + (event as CustomEvent).detail({ + register: (wallet: { icon: string; name: string }) => wallets.push(wallet) + }); + }); + + await import('../../solana'); + + expect(wallets).toHaveLength(1); + expect(wallets[0].name).toBe('Sei Global Wallet'); + expect(wallets[0].icon).toMatch(/^data:image\/svg\+xml;base64,/); + + browserWindow.dispatchEvent( + new CustomEvent('wallet-standard:app-ready', { + detail: { + register: (wallet: { icon: string; name: string }) => wallets.push(wallet) + } + }) + ); + expect(wallets).toHaveLength(2); + expect(wallets[1]).toBe(wallets[0]); + }); +}); diff --git a/packages/sei-global-wallet/src/lib/__tests__/config.spec.ts b/packages/sei-global-wallet/src/lib/__tests__/config.spec.ts index e99caa42d..7c048ebc1 100644 --- a/packages/sei-global-wallet/src/lib/__tests__/config.spec.ts +++ b/packages/sei-global-wallet/src/lib/__tests__/config.spec.ts @@ -1,3 +1,5 @@ +import { describe, expect, it } from 'bun:test'; +import { createHash } from 'node:crypto'; import { config } from '../config'; describe('sei-global-wallet config', () => { @@ -7,10 +9,20 @@ describe('sei-global-wallet config', () => { expect(config.walletUrl).toBe('https://global-wallet.sei.io'); expect(config.environmentId).toBe('36b63d10-7ba6-49a3-9614-22f471b9283c'); expect(config.eip6963.rdns).toBe('io.sei.global-wallet'); + expect(config.eip6963.uuid).toBe('36b63d10-7ba6-49a3-9614-22f471b9283c'); + expect(config.eip6963.uuid).toMatch(/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i); }); - it('walletIcon is an SVG data URI', () => { + it('uses the unmodified square official Sei mark', () => { expect(typeof config.walletIcon).toBe('string'); expect(config.walletIcon).toMatch(/^data:image\/svg\+xml;base64,.+/); + + const bytes = Buffer.from(config.walletIcon.slice(config.walletIcon.indexOf(',') + 1), 'base64'); + const svg = bytes.toString('utf8'); + expect(svg.startsWith('')).toBe(true); + expect(svg).toContain('Sei mark'); + expect(svg.endsWith('\n')).toBe(true); + expect(svg).not.toContain('#9E1F19'); + expect(createHash('sha256').update(bytes).digest('hex')).toBe('e288cd08b510afbc19f1ea85c990397de2cad2077459a6833d64e26f86b761fa'); }); }); diff --git a/packages/sei-global-wallet/src/lib/__tests__/entrypoints.spec.ts b/packages/sei-global-wallet/src/lib/__tests__/entrypoints.spec.ts new file mode 100644 index 000000000..afbfeb61d --- /dev/null +++ b/packages/sei-global-wallet/src/lib/__tests__/entrypoints.spec.ts @@ -0,0 +1,22 @@ +import { describe, expect, it } from 'bun:test'; + +describe('public entrypoints', () => { + it('imports the root and every subpath during SSR', async () => { + const [root, eip6963, ethereum, solana, zerodev] = await Promise.all([ + import('../../index'), + import('../../eip6963'), + import('../../ethereum'), + import('../../solana'), + import('../../zerodev') + ]); + + expect(root.default).toBe(root.Wallet); + expect(typeof root.connect).toBe('function'); + expect(typeof eip6963.registerEIP6963Provider).toBe('function'); + expect(eip6963.eip6963ProviderInfo.name).toBe('Sei Global Wallet'); + expect(typeof ethereum.createEIP1193Provider).toBe('function'); + expect(typeof solana.createSolanaWallet).toBe('function'); + expect(typeof solana.registerSolanaStandard).toBe('function'); + expect(typeof zerodev.createKernelClient).toBe('function'); + }); +}); diff --git a/packages/sei-global-wallet/src/lib/__tests__/registerSolanaStandard.spec.ts b/packages/sei-global-wallet/src/lib/__tests__/registerSolanaStandard.spec.ts index a61960c87..c9c06ea9f 100644 --- a/packages/sei-global-wallet/src/lib/__tests__/registerSolanaStandard.spec.ts +++ b/packages/sei-global-wallet/src/lib/__tests__/registerSolanaStandard.spec.ts @@ -1,8 +1,9 @@ -import { createSolanaWallet, registerWallet } from '@dynamic-labs/global-wallet-client/solana'; +import { afterAll, beforeAll, describe, expect, it, jest } from 'bun:test'; +import { createSolanaWallet, registerWallet } from '../dynamicSolana'; import { registerSolanaStandard } from '../registerSolanaStandard'; import Wallet from '../wallet'; -jest.mock('@dynamic-labs/global-wallet-client/solana', () => ({ +jest.mock('../dynamicSolana', () => ({ createSolanaWallet: jest.fn(), registerWallet: jest.fn() })); @@ -16,11 +17,27 @@ jest.mock('../config', () => ({ })); describe('registerSolanaStandard', () => { - it('calls createSolanaWallet and registers it', () => { - const mockWalletObject = { id: 'sei' }; + const originalWindow = globalThis.window; + + beforeAll(() => { + Object.defineProperty(globalThis, 'window', { + configurable: true, + value: {} + }); + }); + + afterAll(() => { + Object.defineProperty(globalThis, 'window', { + configurable: true, + value: originalWindow + }); + }); + + it('creates and registers one wallet-standard provider', () => { + const mockWalletObject = { id: 'sei' } as unknown as ReturnType; (createSolanaWallet as unknown as jest.Mock).mockReturnValue(mockWalletObject); - registerSolanaStandard(); + const wallet = registerSolanaStandard(); expect(createSolanaWallet).toHaveBeenCalledWith( { @@ -31,5 +48,9 @@ describe('registerSolanaStandard', () => { ); expect(registerWallet).toHaveBeenCalledWith(mockWalletObject); + expect(wallet).toBe(mockWalletObject); + expect(registerSolanaStandard()).toBe(mockWalletObject); + expect(createSolanaWallet).toHaveBeenCalledTimes(1); + expect(registerWallet).toHaveBeenCalledTimes(1); }); }); diff --git a/packages/sei-global-wallet/src/lib/browserGlobal.ts b/packages/sei-global-wallet/src/lib/browserGlobal.ts new file mode 100644 index 000000000..fabf7a472 --- /dev/null +++ b/packages/sei-global-wallet/src/lib/browserGlobal.ts @@ -0,0 +1,29 @@ +import processShim from 'process/browser.js'; + +type BrowserGlobal = typeof globalThis & { + global?: typeof globalThis; + process?: typeof processShim; +}; + +const runtime = globalThis as BrowserGlobal; + +// Dynamic 4.x reads Node-style globals in browser and edge-like runtimes, but +// its own polyfills can execute later after bundling. Install only missing +// values and preserve anything the consumer already set. +if (typeof runtime.global === 'undefined') { + Object.defineProperty(runtime, 'global', { + configurable: true, + enumerable: false, + value: runtime, + writable: true + }); +} + +if (typeof runtime.process === 'undefined') { + Object.defineProperty(runtime, 'process', { + configurable: true, + enumerable: false, + value: processShim, + writable: true + }); +} diff --git a/packages/sei-global-wallet/src/lib/config.ts b/packages/sei-global-wallet/src/lib/config.ts index 20ddc1b44..71443f06a 100644 --- a/packages/sei-global-wallet/src/lib/config.ts +++ b/packages/sei-global-wallet/src/lib/config.ts @@ -1,22 +1,25 @@ -import type { DataURIImage } from '@dynamic-labs/global-wallet-client'; import type { WalletIcon } from '@wallet-standard/base'; +import type { DataURIImage } from './dynamicClient.js'; -interface EIP6963Config { +interface WalletConfig { walletName: string; walletIcon: DataURIImage | WalletIcon; walletUrl: string; environmentId: string; eip6963: { rdns: string; + uuid: string; }; } -export const config: EIP6963Config = { +export const config: WalletConfig = { // Wallet name will be seen as the Wallet name walletName: 'Sei Global Wallet', // Wallet icon will be seen as the Wallet icon + // Exact, unrecolored encoding of the official square Sei mark: + // https://github.com/sei-protocol/sei-docs/blob/8710d6078058bdf67ec704b346f75ee9883e25ea/assets/brand/logo/sei-mark.svg walletIcon: - 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjU2IiBoZWlnaHQ9Ijk2IiB2aWV3Qm94PSIwIDAgMjU2IDk2IiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8ZyBjbGlwLXBhdGg9InVybCgjY2xpcDBfMzE5MV83MzI1KSI+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNNDcuNDYzNyA5NS4wODU4QzYxLjU5OTkgOTUuMDg1OCA3NC4zMDAyIDg4Ljk1ODMgODMuMDM1OCA3OS4yMjMxQzc4Ljk3MjIgNzUuNzAzNSA3Mi44NDgyIDc1LjQ4OTcgNjguNTIyIDc4Ljk2ODVMNjcuNjk1NSA3OS42MzMyQzU5Ljc3NDQgODYuMDAyOSA0OC4yMzI0IDg1LjA2MjIgNDEuNDU1IDc3LjQ5NDZDMzcuNzU4NiA3My4zNjcxIDMxLjQyODEgNzIuOTQ1OCAyNy4yMTM2IDc2LjU0NjZMMTcuNjg0NSA4NC42ODc5QzI1Ljg0NjEgOTEuMTk0OSAzNi4xOTg5IDk1LjA4NTggNDcuNDYzNyA5NS4wODU4Wk02Mi45MzE0IDcyLjA2MzlDNzAuNDc2MSA2NS45OTY3IDgxLjA4MDkgNjYuMjE0NCA4OC4zMzcyIDcyLjA3NDJDOTIuNjc0NSA2NC45MTIzIDk1LjE2OTkgNTYuNTE4MSA5NS4xNjk5IDQ3LjU0MjhDOTUuMTY5OSAzNy41Njk5IDkyLjA4ODkgMjguMzE0MyA4Ni44MjMzIDIwLjY2OTdDODMuNDI5IDE5Ljk0OTMgNzkuNzQ5NyAyMC43OTA3IDc2Ljk1NjggMjMuMjU3Mkw3Ni4xNjE5IDIzLjk1OTJDNjguNTQ0MSAzMC42ODY2IDU2Ljk3MSAzMC4yNzc3IDQ5Ljg1MDMgMjMuMDI5OUM0NS45NjY2IDE5LjA3NjkgMzkuNjIzNCAxOC45NDcxIDM1LjU4MDIgMjIuNzM3OUwyNC40OTEyIDMzLjEzNDZMMTguMzkwOCAyNi42NzI3TDI5LjQ4IDE2LjI3NTlDMzcuMDUzOCA5LjE3NDk0IDQ4LjkzNjUgOS40MTgxIDU2LjIxMTUgMTYuODIzQzYwLjAxMjcgMjAuNjkyMiA2Ni4xOTA5IDIwLjkxMDQgNzAuMjU3NSAxNy4zMTkxTDcxLjA1MjMgMTYuNjE3MUM3My41MjA3IDE0LjQzNzEgNzYuMzc2OCAxMi45Njc1IDc5LjM2NyAxMi4xOTQ2QzcwLjkxNTIgNC42MTM2MiA1OS43MzAxIDAgNDcuNDYzNyAwQzIzLjI0NjEgMCAzLjI0MzMyIDE3Ljk4MzQgMC4xNjc1MzYgNDEuMjgxMUM3LjUyMzM3IDM3Ljc2MzQgMTYuNTk2NyAzOS4xMTcgMjIuNTk0NCA0NS4yMzc4QzI2LjM4MDcgNDkuMTAxOSAzMi40NzczIDQ5LjUwOTcgMzYuNzQ3OSA0Ni4xODQ3TDQyLjk0ODEgNDEuMzU3NUM1MC43NCAzNS4yOTA4IDYxLjc1NTEgMzUuNTg0NCA2OS4yMTA1IDQyLjA1NzlMODEuMjgxNSA1Mi41Mzg0TDc1LjQzMzMgNTkuMjI3OEw2My4zNjI1IDQ4Ljc0NzFDNTkuMTIzMSA0NS4wNjYzIDUyLjg1OTggNDQuODk5MiA0OC40Mjg3IDQ4LjM0OUw0Mi4yMjg4IDUzLjE3NjFDMzQuMzgyNSA1OS4yODUgMjMuMTgxMyA1OC41MzU3IDE2LjIyNSA1MS40MzYzQzEyLjE3OTggNDcuMzA4MSA1LjU2Mzg4IDQ3LjE2NCAxLjM0MTY5IDUxLjExMjRMMCA1Mi4zNjY5QzEuMDA0MDkgNjIuMjk3IDUuMDc0MzMgNzEuMzI1MSAxMS4yNTI5IDc4LjQ5NjhMMjEuNDE5MiA2OS44MTA5QzI5LjMxMzkgNjMuMDY1OCA0MS4xNzI2IDYzLjg1NTMgNDguMDk3IDcxLjU4NjlDNTEuNzE1IDc1LjYyNjggNTcuODc2MyA3Ni4xMjg5IDYyLjEwNDkgNzIuNzI4NUw2Mi45MzE0IDcyLjA2MzlaIiBmaWxsPSIjOUUxRjE5Ii8+CjxwYXRoIGQ9Ik0xMjkuNTMzIDYyLjc5MDlDMTI5LjUzMyA3Mi43Mzg4IDEzNy4zNjkgNzkuMjYzOSAxNDkuNzEyIDc5LjI2MzlDMTYyLjE2NCA3OS4yNjM5IDE3MC43NSA3Mi45NTI4IDE3MC43NSA2My4wMDQ3QzE3MC43NSA1NS4xOTU5IDE2Ni4zNDkgNTEuMTMxMiAxNTcuNDQxIDQ4Ljk5MThMMTQ4LjIxIDQ2Ljc0NTNDMTQzLjA1NyA0NS40NjE4IDE0MC40ODIgNDMuMTA4NSAxNDAuNDgyIDM5LjU3ODZDMTQwLjQ4MiAzNC43NjQ5IDE0NC4wMjMgMzEuOTgzOCAxNTAuMzU2IDMxLjk4MzhDMTU2LjQ3NSAzMS45ODM4IDE2MC4wMTcgMzUuMjk5NyAxNjAuMjMyIDQwLjU0MTJIMTY5Ljg5M0MxNjkuNjc3IDMwLjU5MzEgMTYyLjE2NCAyNC4xNzUgMTUwLjY3OCAyNC4xNzVDMTM5LjA4NSAyNC4xNzUgMTMwLjkyOSAzMC4yNzIxIDEzMC45MjkgMzkuODk5M0MxMzAuOTI5IDQ3LjYwMTIgMTM1LjMzIDUyLjIwMDkgMTQ0LjY2NyA1NC40NDcxTDE1My44OTkgNTYuNTg2NUMxNTkuMzczIDU3Ljk3NzIgMTYxLjA5IDYwLjExNjUgMTYxLjA5IDYzLjY0NjZDMTYxLjA5IDY4LjQ2MDEgMTU3LjAxMSA3MS4zNDgzIDE0OS45MjcgNzEuMzQ4M0MxNDMuMjcyIDcxLjM0ODMgMTM5LjE5NCA2OC4xMzkyIDEzOS4xOTQgNjIuNzkwOUgxMjkuNTMzWiIgZmlsbD0iIzlFMUYxOSIvPgo8cGF0aCBkPSJNMjA2LjczMiA3OS4yNjM5QzIxOS43MjEgNzkuMjYzOSAyMjguNTIyIDcyLjk1MjggMjMxLjA5OCA2MS43MjEySDIyMS42NTNDMjE5LjkzNiA2Ny43MTEyIDIxNC43ODQgNzAuOTIwMyAyMDYuOTQ3IDcwLjkyMDNDMTk2Ljk2NCA3MC45MjAzIDE5MS4xNjkgNjQuODIzIDE5MC40MTggNTMuODA1NEwyMzAuOTkxIDUzLjY5ODNWNDkuOTU0NUMyMzAuOTkxIDM0LjQ0NCAyMjEuMjI0IDI0LjE3NSAyMDYuMzA0IDI0LjE3NUMxOTEuMDYyIDI0LjE3NSAxODAuNjUgMzUuNTEzNyAxODAuNjUgNTEuODhDMTgwLjY1IDY4LjEzOTIgMTkxLjI3NyA3OS4yNjM5IDIwNi43MzIgNzkuMjYzOVpNMjA2LjMwNCAzMi42MjU1QzIxNS4yMTMgMzIuNjI1NSAyMjAuOTAyIDM4LjQwMTkgMjIwLjkwMiA0Ny4wNjYzSDE5MC42MzNDMTkxLjkyMSAzNy44NjcgMTk3LjUwMiAzMi42MjU1IDIwNi4zMDQgMzIuNjI1NVoiIGZpbGw9IiM5RTFGMTkiLz4KPHBhdGggZD0iTTI0OS4zNDUgMTMuMjY0MkMyNTIuOTk0IDEzLjI2NDIgMjU2IDEwLjI2OSAyNTYgNi42MzIwN0MyNTYgMi44ODgxNyAyNTIuOTk0IDAgMjQ5LjM0NSAwQzI0NS42OTUgMCAyNDIuNjg5IDIuODg4MTcgMjQyLjY4OSA2LjYzMjA3QzI0Mi42ODkgMTAuMjY5IDI0NS42OTUgMTMuMjY0MiAyNDkuMzQ1IDEzLjI2NDJaTTI0NC40MDggNzcuOTgwM0gyNTQuNDk3VjI1LjY3MjVIMjQ0LjQwOFY3Ny45ODAzWiIgZmlsbD0iIzlFMUYxOSIvPgo8L2c+CjxkZWZzPgo8Y2xpcFBhdGggaWQ9ImNsaXAwXzMxOTFfNzMyNSI+CjxyZWN0IHdpZHRoPSIyNTYiIGhlaWdodD0iOTYiIGZpbGw9IndoaXRlIi8+CjwvY2xpcFBhdGg+CjwvZGVmcz4KPC9zdmc+Cg==', + 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNDAiIGhlaWdodD0iMjQwIiB2aWV3Qm94PSIwIDAgMjMuOTk2NSAyMy45OTY1IiBmaWxsPSIjMDAwMDAwIj48dGl0bGU+U2VpIG1hcms8L3RpdGxlPjxwYXRoIGQ9Ik0xMS45OTY5IDIzLjk5NjVIMTEuOTk2NUwxMS45OTY3IDIzLjk5NjVMMTEuOTk2OSAyMy45OTY1WiIvPjxwYXRoIGQ9Ik0xNi4wODUgMTkuNTI1NkMxNi44MDYxIDE4Ljg2ODkgMTcuOTA5MiAxOC44NjkgMTguNjMwMyAxOS41MjU4TDE4LjYzMDUgMTkuNTI1OUwyMC4wOTEgMjAuODU1OEMxNy45NTcgMjIuODA2NSAxNS4xMTU4IDIzLjk5NjUgMTEuOTk2NyAyMy45OTY1QzguODg4MjQgMjMuOTk2NCA2LjA1NTkxIDIyLjgxNDcgMy45MjQ0OCAyMC44NzZMNS40MDcyIDE5LjUyNTlMNS40MDczNCAxOS41MjU4QzYuMTI4NDQgMTguODY5IDcuMjMxNDcgMTguODY4OSA3Ljk1MjY1IDE5LjUyNTZMOS4yNTA4OCAyMC43MDg3TDkuMjUxMDkgMjAuNzA4OUMxMC44MTk1IDIyLjEzNzQgMTMuMjE4MiAyMi4xMzc0IDE0Ljc4NjYgMjAuNzA4OUwxNC43ODY4IDIwLjcwODdMMTYuMDg1IDE5LjUyNTZMMTYuMDg1IDE5LjUyNTZaIi8+PHBhdGggZD0iTTExLjk5NjUgMEMxNS4xMjE0IDAgMTcuOTY3MiAxLjE5NDIxIDIwLjEwMjUgMy4xNTEwNUMyMC4wNDEyIDMuMjAwNzUgMTkuOTgxIDMuMjUyNDUgMTkuOTIyIDMuMzA2MTlMMTkuOTIxOCAzLjMwNjM2TDE4LjYyMzYgNC40ODk0NEMxNy45MDI1IDUuMTQ2MDUgMTYuNzk5NiA1LjE0NjA1IDE2LjA3ODUgNC40ODk0NEwxNC43ODAzIDMuMzA2MzZMMTQuNzggMy4zMDYxOUwxNC43NDMxIDMuMjcyOTZDMTMuMTc0MiAxLjg3NzcyIDEwLjgwMDcgMS44ODg4MyA5LjI0NDU0IDMuMzA2MjJMNS45MjU2NiA2LjMyODMyTDcuNDIwMzggNy45NjkzOUwxMC43Mzk0IDQuOTQ3MTVMMTAuNzM5NSA0Ljk0NzA0QzExLjQ2MDcgNC4yOTAyNSAxMi41NjM3IDQuMjkwMTYgMTMuMjg0OSA0Ljk0NjgzTDE0LjU4MzEgNi4xMjk5MUwxNC41ODMzIDYuMTMwMTJDMTYuMTUxNyA3LjU1ODY2IDE4LjU1MDQgNy41NTg2NiAyMC4xMTg4IDYuMTMwMTJMMjAuMTE5IDYuMTI5OTRMMjEuNDE3MiA0Ljk0Njg3TDIxLjQxNzIgNC45NDY4M0MyMS40NzUzIDQuODkzOTEgMjEuNTM1OSA0Ljg0NTMgMjEuNTk4NiA0LjgwMDkxQzIzLjEwNDMgNi44MDU5MiAyMy45OTY1IDkuMjk3OSAyMy45OTY1IDExLjk5ODNDMjMuOTk2NSAxNC43MDY5IDIzLjA5ODggMTcuMjA1OCAyMS41ODQ3IDE5LjIxMzlMMjAuMTI1MyAxNy44ODVMMjAuMTI1MyAxNy44ODQ5QzE4LjU1NjkgMTYuNDU2NCAxNi4xNTgyIDE2LjQ1NjQgMTQuNTg5OCAxNy44ODQ5TDE0LjU4OTYgMTcuODg1MUwxMy4yOTE0IDE5LjA2ODJDMTIuNTcwMyAxOS43MjQ4IDExLjQ2NzQgMTkuNzI0OCAxMC43NDYzIDE5LjA2ODJMOS40NDgwNSAxNy44ODUxTDkuNDQ3ODQgMTcuODg0OUw5LjQxMDkyIDE3Ljg1MTdDNy44NDIgMTYuNDU2NSA1LjQ2ODQ5IDE2LjQ2NzYgMy45MTIzMyAxNy44ODVMMi40MjY2NCAxOS4yMzc4QzEuMzgxMjcgMTcuODU4NCAwLjYyNzM2NSAxNi4yNDYxIDAuMjU2NTM2IDE0LjQ5MjRMMi43MzQ1OCAxMi4yMzZMMi43MzQ3MiAxMi4yMzU5QzMuNDU1ODYgMTEuNTc5IDQuNTU4NjEgMTEuNTc5IDUuMjc5NzggMTIuMjM1OEw2LjU3ODM3IDEzLjQxODhMNi41Nzg0NyAxMy40MTg5QzguMTQ2ODEgMTQuODQ3NCAxMC41NDU1IDE0Ljg0NzYgMTIuMTEzNyAxMy40MTg4TDEzLjQxMjIgMTIuMjM1OEMxNC4xMzM0IDExLjU3OSAxNS4yMzY1IDExLjU3OSAxNS45NTc3IDEyLjIzNTlMMTUuOTU3OCAxMi4yMzZMMTkuMjc2OSAxNS4yNTgyTDIwLjc3MTYgMTMuNjE3MUwxNy40NTI3IDEwLjU5NUwxNy40NTI3IDEwLjU5NUMxNS44ODQzIDkuMTY2NDYgMTMuNDg1NiA5LjE2NjQ2IDExLjkxNzIgMTAuNTk1TDExLjkxNzEgMTAuNTk1MUwxMC42MTg1IDExLjc3ODJMMTAuNjE4NSAxMS43NzgyQzkuODk3NzkgMTIuNDM0OCA4Ljc5NDc2IDEyLjQzNSA4LjA3MzUyIDExLjc3ODJMNi43NzQ5MyAxMC41OTUxTDYuNzc0ODYgMTAuNTk1TDYuNzM3OTUgMTAuNTYxOEM1LjE2OTAzIDkuMTY2NTQgMi43OTU4NyA5LjE3NzY1IDEuMjM5NzEgMTAuNTk1TDAgMTEuNzIzOUMwLjE0NTg3NiA1LjIyNDM4IDUuNDYwNzEgNy4wNzkxM2UtMDYgMTEuOTk2NSAwWiIvPjwvc3ZnPg==', // URL of your wallet domain (e.g. https://dynamic.example.com) walletUrl: 'https://global-wallet.sei.io', // Environment ID of your wallet (e.g. 1234567890) @@ -24,6 +27,12 @@ export const config: EIP6963Config = { // EIP6963 configuration eip6963: { // RDNS of your wallet (e.g. com.example.wallet) - rdns: 'io.sei.global-wallet' + rdns: 'io.sei.global-wallet', + // Stable UUIDv4 for the EIP-6963 provider identity. + uuid: '36b63d10-7ba6-49a3-9614-22f471b9283c' } }; + +// The pinned source ends in `\n`; preserve that terminal byte in the +// base64 data URI instead of relying on editor treatment of a multiline asset. +config.walletIcon = `${config.walletIcon.slice(0, -2)}o=` as DataURIImage; diff --git a/packages/sei-global-wallet/src/lib/dynamicClient.ts b/packages/sei-global-wallet/src/lib/dynamicClient.ts new file mode 100644 index 000000000..e5d122ccd --- /dev/null +++ b/packages/sei-global-wallet/src/lib/dynamicClient.ts @@ -0,0 +1,7 @@ +import './browserGlobal.js'; + +export { + createGlobalWalletClient, + type DataURIImage, + type GlobalWalletClient +} from '@dynamic-labs/global-wallet-client'; diff --git a/packages/sei-global-wallet/src/lib/dynamicEthereum.ts b/packages/sei-global-wallet/src/lib/dynamicEthereum.ts new file mode 100644 index 000000000..11a624daa --- /dev/null +++ b/packages/sei-global-wallet/src/lib/dynamicEthereum.ts @@ -0,0 +1,3 @@ +import './browserGlobal.js'; + +export { createEIP1193Provider } from '@dynamic-labs/global-wallet-client/ethereum'; diff --git a/packages/sei-global-wallet/src/lib/dynamicFeatures.ts b/packages/sei-global-wallet/src/lib/dynamicFeatures.ts new file mode 100644 index 000000000..e95c98f26 --- /dev/null +++ b/packages/sei-global-wallet/src/lib/dynamicFeatures.ts @@ -0,0 +1,3 @@ +import './browserGlobal.js'; + +export * from '@dynamic-labs/global-wallet-client/features'; diff --git a/packages/sei-global-wallet/src/lib/dynamicSolana.ts b/packages/sei-global-wallet/src/lib/dynamicSolana.ts new file mode 100644 index 000000000..516314ee9 --- /dev/null +++ b/packages/sei-global-wallet/src/lib/dynamicSolana.ts @@ -0,0 +1,3 @@ +import './browserGlobal.js'; + +export { createSolanaWallet, registerWallet } from '@dynamic-labs/global-wallet-client/solana'; diff --git a/packages/sei-global-wallet/src/lib/dynamicZerodev.ts b/packages/sei-global-wallet/src/lib/dynamicZerodev.ts new file mode 100644 index 000000000..00e4adb5e --- /dev/null +++ b/packages/sei-global-wallet/src/lib/dynamicZerodev.ts @@ -0,0 +1,3 @@ +import './browserGlobal.js'; + +export { createKernelClient } from '@dynamic-labs/global-wallet-client/zerodev'; diff --git a/packages/sei-global-wallet/src/lib/registerSolanaStandard.ts b/packages/sei-global-wallet/src/lib/registerSolanaStandard.ts index d4652fafd..e21921aca 100644 --- a/packages/sei-global-wallet/src/lib/registerSolanaStandard.ts +++ b/packages/sei-global-wallet/src/lib/registerSolanaStandard.ts @@ -1,16 +1,23 @@ -import { createSolanaWallet, registerWallet } from '@dynamic-labs/global-wallet-client/solana'; import type { WalletIcon } from '@wallet-standard/base'; import { config } from './config.js'; +import { createSolanaWallet, registerWallet } from './dynamicSolana.js'; import Wallet from './wallet.js'; +let registeredWallet: ReturnType | undefined; + export const registerSolanaStandard = () => { - registerWallet( - createSolanaWallet( - { - icon: config.walletIcon as WalletIcon, - name: config.walletName - }, - Wallet - ) + if (typeof window === 'undefined') return undefined; + if (registeredWallet) return registeredWallet; + + const wallet = createSolanaWallet( + { + icon: config.walletIcon as WalletIcon, + name: config.walletName + }, + Wallet ); + registerWallet(wallet); + registeredWallet = wallet; + + return wallet; }; diff --git a/packages/sei-global-wallet/src/lib/wallet.ts b/packages/sei-global-wallet/src/lib/wallet.ts index ebc142a56..9d74dd08b 100644 --- a/packages/sei-global-wallet/src/lib/wallet.ts +++ b/packages/sei-global-wallet/src/lib/wallet.ts @@ -1,5 +1,5 @@ -import { createGlobalWalletClient, type GlobalWalletClient } from '@dynamic-labs/global-wallet-client'; import { config } from './config.js'; +import { createGlobalWalletClient, type GlobalWalletClient } from './dynamicClient.js'; const Wallet: GlobalWalletClient = createGlobalWalletClient({ environmentId: config.environmentId, diff --git a/packages/sei-global-wallet/src/solana.ts b/packages/sei-global-wallet/src/solana.ts index d76c11b5c..95d09734a 100644 --- a/packages/sei-global-wallet/src/solana.ts +++ b/packages/sei-global-wallet/src/solana.ts @@ -2,4 +2,5 @@ import { registerSolanaStandard } from './lib/registerSolanaStandard.js'; registerSolanaStandard(); -export { createSolanaWallet } from '@dynamic-labs/global-wallet-client/solana'; +export { createSolanaWallet } from './lib/dynamicSolana.js'; +export { registerSolanaStandard }; diff --git a/packages/sei-global-wallet/src/zerodev.ts b/packages/sei-global-wallet/src/zerodev.ts index 70a02d3fd..0d1596bf2 100644 --- a/packages/sei-global-wallet/src/zerodev.ts +++ b/packages/sei-global-wallet/src/zerodev.ts @@ -1 +1 @@ -export { createKernelClient } from '@dynamic-labs/global-wallet-client/zerodev'; +export { createKernelClient } from './lib/dynamicZerodev.js'; diff --git a/packages/sei-global-wallet/tsconfig.json b/packages/sei-global-wallet/tsconfig.json index 2bc744cbf..ccc04c8a4 100644 --- a/packages/sei-global-wallet/tsconfig.json +++ b/packages/sei-global-wallet/tsconfig.json @@ -7,6 +7,7 @@ "rootDir": "./src", "module": "NodeNext", "moduleResolution": "NodeNext", - "declaration": true + "declaration": true, + "lib": ["ES2022", "DOM"] } } diff --git a/scripts/check-sei-global-wallet.ts b/scripts/check-sei-global-wallet.ts new file mode 100644 index 000000000..7910ff354 --- /dev/null +++ b/scripts/check-sei-global-wallet.ts @@ -0,0 +1,694 @@ +import assert from 'node:assert/strict'; +import { webcrypto } from 'node:crypto'; +import { mkdir, mkdtemp, readdir, readFile, rm, writeFile } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import { dirname, join, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import vm from 'node:vm'; + +interface ProcessResult { + exitCode: number; + stderr: string; + stdout: string; +} + +interface AuditReport { + metadata?: { + vulnerabilities?: { + total?: number; + }; + }; + vulnerabilities?: Record; +} + +interface PackResult { + filename: string; + files: Array<{ path: string }>; +} + +interface PackageLock { + packages: Record; version?: string }>; +} + +const root = resolve(dirname(fileURLToPath(import.meta.url)), '..'); +const packageDir = join(root, 'packages/sei-global-wallet'); +const temporaryRoot = await mkdtemp(join(tmpdir(), 'sei-global-wallet-release-')); +const fastCheck = process.env.SEI_GLOBAL_WALLET_FAST_CHECK === '1'; +const acceptedBunAdvisories = ['GHSA-378v-28hj-76wf', 'GHSA-58qx-3vcg-4xpx', 'GHSA-96hv-2xvq-fx4p'] as const; + +const run = async (command: string[], cwd: string, allowFailure = false): Promise => { + const child = Bun.spawn(command, { + cwd, + env: process.env, + stderr: 'pipe', + stdout: 'pipe' + }); + const [stdout, stderr, exitCode] = await Promise.all([new Response(child.stdout).text(), new Response(child.stderr).text(), child.exited]); + + if (!allowFailure && exitCode !== 0) { + throw new Error(`${command.join(' ')} failed in ${cwd}\n${stderr}${stdout}`); + } + + return { exitCode, stderr, stdout }; +}; + +const parseJsonOutput = (output: string): T => { + const plain = output; + const objectStart = plain.indexOf('{'); + const arrayStart = plain.indexOf('['); + const start = objectStart === -1 ? arrayStart : arrayStart === -1 ? objectStart : Math.min(objectStart, arrayStart); + const end = Math.max(plain.lastIndexOf('}'), plain.lastIndexOf(']')); + assert(start >= 0 && end >= start, `Expected JSON output, received:\n${plain}`); + return JSON.parse(plain.slice(start, end + 1)) as T; +}; + +const writeJson = (path: string, value: unknown) => writeFile(path, `${JSON.stringify(value, null, 2)}\n`); + +const baseSafeOverrides = { + axios: '1.18.0', + uuid: '11.1.1' +}; +const npmRuntimeOverrides = { + ...baseSafeOverrides, + viem: { + ws: '8.21.0' + } +}; +const npmSafeOverrides = { + ...npmRuntimeOverrides, + 'ethjs-unit': { + 'bn.js': '4.12.5' + }, + 'number-to-bn': { + 'bn.js': '4.12.5' + } +}; + +const walletOnlyManifest = (tarball: string, overrides?: Record) => ({ + name: 'sei-global-wallet-audit-consumer', + private: true, + type: 'module', + dependencies: { + '@sei-js/sei-global-wallet': `file:${tarball}` + }, + ...(overrides ? { overrides } : {}) +}); + +const fullConsumerManifest = (tarball: string, packageManager: 'bun' | 'npm') => ({ + name: 'sei-global-wallet-full-consumer', + private: true, + type: 'module', + dependencies: { + '@dynamic-labs/ethereum-aa': '4.96.3', + '@sei-js/sei-global-wallet': `file:${tarball}`, + '@solana/wallet-standard-features': '^1.2.0', + '@solana/web3.js': '1.98.1', + '@wallet-standard/base': '^1.0.1', + '@wallet-standard/features': '^1.0.3', + '@wallet-standard/wallet': '^1.1.0', + '@zerodev/sdk': '5.5.7', + 'ethjs-unit': '0.1.6', + 'number-to-bn': '1.7.0', + viem: '2.45.3', + 'zksync-sso': '0.2.0' + }, + devDependencies: { + esbuild: '0.28.2', + typescript: '5.9.3', + vite: '8.2.2' + }, + overrides: packageManager === 'npm' ? npmSafeOverrides : baseSafeOverrides +}); + +const setupConsumerFiles = async (consumerDir: string) => { + await writeFile( + join(consumerDir, 'check-ssr.mjs'), + `import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +const [root, eip6963, ethereum, solana, zerodev] = await Promise.all([ + import('@sei-js/sei-global-wallet'), + import('@sei-js/sei-global-wallet/eip6963'), + import('@sei-js/sei-global-wallet/ethereum'), + import('@sei-js/sei-global-wallet/solana'), + import('@sei-js/sei-global-wallet/zerodev') +]); +assert.equal(root.default, root.Wallet); +assert.equal(typeof root.connect, 'function'); +assert.equal(typeof eip6963.registerEIP6963Provider, 'function'); +assert.equal(typeof ethereum.createEIP1193Provider, 'function'); +assert.equal(typeof solana.createSolanaWallet, 'function'); +assert.equal(typeof solana.registerSolanaStandard, 'function'); +assert.equal(typeof zerodev.createKernelClient, 'function'); +const iconBytes = Buffer.from(eip6963.eip6963ProviderInfo.icon.split(',')[1], 'base64'); +assert.equal(iconBytes.at(-1), 10); +assert.equal(createHash('sha256').update(iconBytes).digest('hex'), 'e288cd08b510afbc19f1ea85c990397de2cad2077459a6833d64e26f86b761fa'); +console.log('SSR entrypoints OK'); +` + ); + await writeFile( + join(consumerDir, 'check-edge-native.mjs'), + `import assert from 'node:assert/strict'; + +Reflect.deleteProperty(globalThis, 'global'); +Reflect.deleteProperty(globalThis, 'process'); +const [root, eip6963, ethereum, solana, zerodev] = await Promise.all([ + import('@sei-js/sei-global-wallet'), + import('@sei-js/sei-global-wallet/eip6963'), + import('@sei-js/sei-global-wallet/ethereum'), + import('@sei-js/sei-global-wallet/solana'), + import('@sei-js/sei-global-wallet/zerodev') +]); +assert.equal(globalThis.global, globalThis); +assert.equal(globalThis.process?.browser, true); +assert.equal(root.default, root.Wallet); +assert.equal(typeof eip6963.registerEIP6963Provider, 'function'); +assert.equal(typeof ethereum.createEIP1193Provider, 'function'); +assert.equal(typeof solana.createSolanaWallet, 'function'); +assert.equal(typeof zerodev.createKernelClient, 'function'); +` + ); + await writeFile( + join(consumerDir, 'check-local-aa.mjs'), + `import assert from 'node:assert/strict'; +import ethjsUnit from 'ethjs-unit'; +import numberToBN from 'number-to-bn'; +import { getEcdsaValidator, PaymasterTypeEnum } from '@dynamic-labs/ethereum-aa'; +import { Connection, PublicKey } from '@solana/web3.js'; +import { KernelEIP1193Provider } from '@zerodev/sdk/providers'; + +const converted = numberToBN('0x2a'); +assert.equal(converted.constructor.wordSize, 26); +assert.equal(converted.toString(10), '42'); +assert.equal(ethjsUnit.toWei('1', 'ether').toString(10), '1000000000000000000'); +assert.equal(PaymasterTypeEnum.NONE, 'NONE'); +assert.equal(typeof getEcdsaValidator(), 'function'); +const publicKey = new PublicKey('11111111111111111111111111111111'); +assert.equal(publicKey.toBase58(), '11111111111111111111111111111111'); +const connection = new Connection('http://127.0.0.1:8899', 'confirmed'); +assert.equal(connection.rpcEndpoint, 'http://127.0.0.1:8899'); + +const address = '0x0000000000000000000000000000000000000042'; +const kernelClient = { + account: { address }, + transport: { + request() { + throw new Error('network transport must not be called'); + } + } +}; +const provider = new KernelEIP1193Provider(kernelClient); +assert.deepEqual(await provider.request({ method: 'eth_accounts' }), [address]); +let emitted = false; +provider.on('accountsChanged', () => { + emitted = true; +}); +provider.emit('accountsChanged', [address]); +assert.equal(emitted, true); +` + ); + await writeFile( + join(consumerDir, 'browser-setup.mjs'), + `globalThis.__eipAnnouncements = []; +globalThis.__solanaWallets = []; +window.addEventListener('eip6963:announceProvider', (event) => { + globalThis.__eipAnnouncements.push(event.detail); +}); +window.addEventListener('wallet-standard:register-wallet', (event) => { + event.detail({ + register(wallet) { + globalThis.__solanaWallets.push(wallet); + } + }); +}); +` + ); + await writeFile( + join(consumerDir, 'browser-entry.mjs'), + `import './browser-setup.mjs'; +import Wallet, { connect } from '@sei-js/sei-global-wallet'; +import { eip6963ProviderInfo } from '@sei-js/sei-global-wallet/eip6963'; +import { createEIP1193Provider } from '@sei-js/sei-global-wallet/ethereum'; +import { createSolanaWallet } from '@sei-js/sei-global-wallet/solana'; + +window.dispatchEvent(new Event('eip6963:requestProvider')); +window.dispatchEvent(new Event('eip6963:requestProvider')); +globalThis.__walletCheck = { + announcements: globalThis.__eipAnnouncements.length, + globalReady: global === globalThis, + icon: eip6963ProviderInfo.icon, + name: eip6963ProviderInfo.name, + root: typeof Wallet === 'object' && typeof connect === 'function', + solanaRegistrations: globalThis.__solanaWallets.length, + subpaths: + typeof createEIP1193Provider === 'function' && + typeof createSolanaWallet === 'function' +}; +` + ); + await writeFile( + join(consumerDir, 'browser-esbuild-entry.mjs'), + `import './browser-entry.mjs'; +import { createKernelClient } from '@sei-js/sei-global-wallet/zerodev'; +import { KernelEIP1193Provider } from '@zerodev/sdk/providers'; + +const address = '0x0000000000000000000000000000000000000042'; +const provider = new KernelEIP1193Provider({ + account: { address }, + transport: { + request() { + throw new Error('browser check must not use the network'); + } + } +}); +const publicExportOperation = createKernelClient({ wallet: {} }).then( + () => false, + (error) => error instanceof Error && error.message === 'Client not present' +); +const providerOperation = provider + .request({ method: 'eth_accounts' }) + .then((accounts) => accounts.length === 1 && accounts[0] === address); +globalThis.__walletCheck.zerodev = Promise.all([publicExportOperation, providerOperation]).then((checks) => checks.every(Boolean)); +` + ); + await writeFile( + join(consumerDir, 'edge-entry.mjs'), + `import Wallet, { connect } from '@sei-js/sei-global-wallet'; +import { registerEIP6963Provider } from '@sei-js/sei-global-wallet/eip6963'; +import { createEIP1193Provider } from '@sei-js/sei-global-wallet/ethereum'; +import { createSolanaWallet } from '@sei-js/sei-global-wallet/solana'; +import { createKernelClient } from '@sei-js/sei-global-wallet/zerodev'; + +globalThis.__edgeCheck = { + aliases: global === globalThis && process.browser === true, + entrypoints: + typeof Wallet === 'object' && + typeof connect === 'function' && + typeof registerEIP6963Provider === 'function' && + typeof createEIP1193Provider === 'function' && + typeof createSolanaWallet === 'function' && + typeof createKernelClient === 'function' +}; +` + ); + await writeFile( + join(consumerDir, 'typecheck.ts'), + `import Wallet, { connect } from '@sei-js/sei-global-wallet'; +import { + type EIP6963ProviderDetail, + eip6963ProviderInfo, + registerEIP6963Provider +} from '@sei-js/sei-global-wallet/eip6963'; +import { createEIP1193Provider } from '@sei-js/sei-global-wallet/ethereum'; +import { createSolanaWallet, registerSolanaStandard } from '@sei-js/sei-global-wallet/solana'; +import { createKernelClient } from '@sei-js/sei-global-wallet/zerodev'; + +const detail: EIP6963ProviderDetail | undefined = undefined; +void [Wallet, connect, detail, eip6963ProviderInfo, registerEIP6963Provider, createEIP1193Provider, createSolanaWallet, registerSolanaStandard, createKernelClient]; +` + ); + await writeJson(join(consumerDir, 'tsconfig.json'), { + compilerOptions: { + lib: ['ES2022', 'DOM'], + module: 'ESNext', + moduleResolution: 'Bundler', + noEmit: true, + skipLibCheck: true, + strict: true, + target: 'ES2022' + }, + files: ['typecheck.ts'] + }); + await writeFile( + join(consumerDir, 'vite.config.mjs'), + `import { defineConfig } from 'vite'; +import { fileURLToPath } from 'node:url'; + +export default defineConfig({ + build: { + emptyOutDir: true, + lib: { + entry: fileURLToPath(new URL('./browser-esbuild-entry.mjs', import.meta.url)), + fileName: 'wallet', + formats: ['iife'], + name: 'SeiWalletConsumerCheck' + }, + minify: false, + outDir: 'vite-dist' + } +}); +` + ); +}; + +const makeStorage = (): Storage => { + const values = new Map(); + return { + get length() { + return values.size; + }, + clear: () => values.clear(), + getItem: (key) => values.get(key) ?? null, + key: (index) => [...values.keys()][index] ?? null, + removeItem: (key) => values.delete(key), + setItem: (key, value) => values.set(key, String(value)) + }; +}; + +const runBrowserBundle = async (bundlePath: string, expectZeroDev: boolean) => { + const eventTarget = new EventTarget(); + const storage = makeStorage(); + const context: Record = { + AbortController, + Blob, + CustomEvent, + Event, + EventTarget, + MessageChannel, + TextDecoder, + TextEncoder, + URL, + URLSearchParams, + addEventListener: eventTarget.addEventListener.bind(eventTarget), + atob, + btoa, + clearInterval, + clearTimeout, + console: { + ...console, + debug: () => {}, + error: () => {} + }, + crypto: webcrypto, + dispatchEvent: eventTarget.dispatchEvent.bind(eventTarget), + fetch, + localStorage: storage, + navigator: {}, + performance, + queueMicrotask, + removeEventListener: eventTarget.removeEventListener.bind(eventTarget), + sessionStorage: makeStorage(), + setInterval, + setTimeout, + structuredClone + }; + context.globalThis = context; + context.self = context; + context.window = context; + + const bundle = await readFile(bundlePath, 'utf8'); + assert(!bundle.includes('node:worker_threads'), `${bundlePath} contains a node:worker_threads browser runtime path`); + assert(!bundle.includes('"worker_threads"'), `${bundlePath} contains a worker_threads browser runtime path`); + try { + vm.runInNewContext(bundle, context, { + filename: bundlePath, + timeout: 10_000 + }); + } catch (error) { + const message = + typeof error === 'object' && error && 'stack' in error && typeof error.stack === 'string' + ? error.stack + : error instanceof Error + ? error.message + : String(error); + const line = Number(message.match(/:(\d+):\d+/)?.[1]); + const lines = bundle.split('\n'); + const nearbySource = Number.isFinite(line) ? lines.slice(Math.max(0, line - 4), line + 3).join('\n') : ''; + const shimLine = lines.findIndex((sourceLine) => sourceLine.includes('Dynamic 4.x reads')); + const shimSource = shimLine >= 0 ? lines.slice(shimLine, shimLine + 28).join('\n') : 'browser shim not found'; + throw new Error(`${message}\n${nearbySource}\n--- browser shim (line ${shimLine + 1}) ---\n${shimSource}`); + } + + const result = context.__walletCheck as { + announcements: number; + globalReady: boolean; + icon: string; + name: string; + root: boolean; + solanaRegistrations: number; + subpaths: boolean; + zerodev?: boolean | Promise; + }; + assert(result, `Browser bundle did not produce a result: ${bundlePath}`); + assert.equal(result.globalReady, true); + assert.equal(result.root, true); + assert.equal(result.subpaths, true); + if (expectZeroDev) assert.equal(await result.zerodev, true); + assert.equal(result.announcements, 3); + assert.equal(result.solanaRegistrations, 1); + assert.equal(result.name, 'Sei Global Wallet'); + assert.match(result.icon, /^data:image\/svg\+xml;base64,/); +}; + +const runEdgeBundle = async (bundlePath: string) => { + const context: Record = { + AbortController, + Blob, + CustomEvent, + Event, + EventTarget, + MessageChannel, + TextDecoder, + TextEncoder, + URL, + URLSearchParams, + atob, + btoa, + clearInterval, + clearTimeout, + console, + crypto: webcrypto, + fetch, + performance, + queueMicrotask, + setInterval, + setTimeout, + structuredClone + }; + context.globalThis = context; + context.self = context; + + const bundle = await readFile(bundlePath, 'utf8'); + assert(!bundle.includes('node:worker_threads'), `${bundlePath} contains a node:worker_threads edge runtime path`); + assert(!bundle.includes('"worker_threads"'), `${bundlePath} contains a worker_threads edge runtime path`); + vm.runInNewContext(bundle, context, { + filename: bundlePath, + timeout: 10_000 + }); + assert.deepEqual(context.__edgeCheck, { + aliases: true, + entrypoints: true + }); +}; + +const assertAuditClean = (report: AuditReport, label: string) => { + assert.equal(report.metadata?.vulnerabilities?.total ?? Object.keys(report.vulnerabilities ?? {}).length, 0, `${label} audit was not clean`); +}; + +const assertAcceptedBunAudit = (result: ProcessResult) => { + assert.notEqual(result.exitCode, 0, 'Bun AA consumer audit unexpectedly reported a clean dependency tree'); + const report = parseJsonOutput>>(result.stdout); + assert.deepEqual(Object.keys(report).sort(), ['bn.js', 'ws']); + assert.equal(report['bn.js']?.length, 1); + assert.equal(report['bn.js']?.[0]?.severity, 'moderate'); + assert.equal(report['bn.js']?.[0]?.url, 'https://github.com/advisories/GHSA-378v-28hj-76wf'); + assert.equal(report.ws?.length, 2); + assert.deepEqual( + report.ws?.map(({ severity, url }) => ({ severity, url })).sort((a, b) => (a.url ?? '').localeCompare(b.url ?? '')), + [ + { + severity: 'moderate', + url: 'https://github.com/advisories/GHSA-58qx-3vcg-4xpx' + }, + { + severity: 'high', + url: 'https://github.com/advisories/GHSA-96hv-2xvq-fx4p' + } + ] + ); + const serialized = JSON.stringify(report); + const advisories = [...new Set(serialized.match(/GHSA-[a-z0-9-]+/gi) ?? [])].sort(); + assert.deepEqual(advisories, [...acceptedBunAdvisories].sort()); + assert.doesNotMatch(serialized, /axios|uuid/i); +}; + +const assertNpmDynamicGraph = (lock: PackageLock) => { + assert.equal(lock.packages['node_modules/@dynamic-labs/global-wallet-client']?.version, '4.96.3'); + assert.equal(lock.packages['node_modules/@dynamic-labs/ethereum-aa']?.version, '4.96.3'); + + const stale = Object.entries(lock.packages).filter( + ([location, metadata]) => location.includes('/node_modules/@dynamic-labs/') && metadata.version === '4.96.1' + ); + assert.deepEqual(stale, [], `Unexpected stale Dynamic 4.96.1 npm resolutions: ${stale.map(([location]) => location).join(', ')}`); +}; + +const assertBunDynamicGraph = (lockText: string) => { + assert.match(lockText, /"@dynamic-labs\/global-wallet-client": \["@dynamic-labs\/global-wallet-client@4\.96\.3"/); + assert.match(lockText, /"@dynamic-labs\/ethereum-aa": \["@dynamic-labs\/ethereum-aa@4\.96\.3"/); + assert.doesNotMatch(lockText, /@dynamic-labs\/[^"]+@4\.96\.1/, 'Bun lockfile retained a stale Dynamic 4.96.1 resolution'); +}; + +const assertBrowserMetafile = async (metafilePath: string, lock: PackageLock) => { + const metafile = JSON.parse(await readFile(metafilePath, 'utf8')) as { + inputs: Record; + outputs: Record }>; + }; + const inputs = Object.keys(metafile.inputs); + assert(inputs.some((path) => path.includes('node_modules/@dynamic-labs/global-wallet-client/'))); + const resolvedDynamicInputs = new Map(); + for (const path of inputs) { + const normalizedPath = path.replaceAll('\\', '/'); + const marker = 'node_modules/@dynamic-labs/'; + const packageMarker = normalizedPath.lastIndexOf(marker); + if (packageMarker === -1) continue; + + const packageStart = packageMarker + 'node_modules/'.length; + const packageName = normalizedPath.slice(packageStart).split('/').slice(0, 2).join('/'); + const lockStart = normalizedPath.indexOf('node_modules/'); + const lockLocation = normalizedPath.slice(lockStart, packageStart + packageName.length); + const version = lock.packages[lockLocation]?.version; + assert(version, `Metafile input did not resolve to its nearest npm lock installation: ${path} -> ${lockLocation}`); + assert.notEqual(version, '4.96.1', `Unexpected stale Dynamic runtime in bundle: ${path} -> ${lockLocation}@${version}`); + resolvedDynamicInputs.set(lockLocation, version); + } + assert.equal(resolvedDynamicInputs.get('node_modules/@dynamic-labs/global-wallet-client'), '4.96.3'); + const runtimeImports = Object.values(metafile.outputs).flatMap((output) => output.imports ?? []); + assert(!runtimeImports.some(({ path }) => path === 'node:worker_threads' || path === 'worker_threads')); +}; + +try { + await run(['bun', 'run', '--cwd', packageDir, 'build'], root); + const pack = await run(['npm', 'pack', '--json', '--pack-destination', temporaryRoot], packageDir); + const [packResult] = parseJsonOutput(pack.stdout); + assert(packResult, 'npm pack returned no package'); + const packedPaths = packResult.files.map(({ path }) => path); + for (const entrypoint of ['index', 'eip6963', 'ethereum', 'solana', 'zerodev']) { + assert(packedPaths.includes(`dist/${entrypoint}.js`), `Missing dist/${entrypoint}.js`); + assert(packedPaths.includes(`dist/${entrypoint}.d.ts`), `Missing dist/${entrypoint}.d.ts`); + } + assert(packedPaths.every((path) => path.startsWith('dist/') || ['LICENSE', 'README.md', 'package.json'].includes(path))); + assert(!packedPaths.some((path) => path.includes('__tests__') || path.startsWith('src/'))); + const tarball = join(temporaryRoot, packResult.filename); + + if (!fastCheck) { + const unwaivedDir = join(temporaryRoot, 'npm-unwaived'); + await mkdir(unwaivedDir); + await writeJson(join(unwaivedDir, 'package.json'), walletOnlyManifest(tarball)); + await run(['npm', 'install', '--no-audit', '--no-fund'], unwaivedDir); + const unwaivedLock = JSON.parse(await readFile(join(unwaivedDir, 'package-lock.json'), 'utf8')) as { + packages: Record; + }; + const lockedVersions = (name: string) => + Object.entries(unwaivedLock.packages) + .filter(([location]) => location === `node_modules/${name}` || location.endsWith(`/node_modules/${name}`)) + .map(([, metadata]) => metadata.version); + assert(lockedVersions('axios').includes('1.16.0')); + assert(lockedVersions('uuid').includes('11.1.0')); + const unwaivedAuditResult = await run(['npm', 'audit', '--json'], unwaivedDir, true); + const unwaivedAudit = parseJsonOutput(unwaivedAuditResult.stdout); + assert(unwaivedAudit.vulnerabilities?.axios, 'Unwaived npm audit did not expose vulnerable axios'); + assert(unwaivedAudit.vulnerabilities?.uuid, 'Unwaived npm audit did not expose vulnerable uuid'); + + const waivedDir = join(temporaryRoot, 'npm-waived'); + await mkdir(waivedDir); + await writeJson(join(waivedDir, 'package.json'), walletOnlyManifest(tarball, npmRuntimeOverrides)); + await run(['npm', 'install', '--no-audit', '--no-fund'], waivedDir); + await run( + [ + 'node', + '--input-type=module', + '--eval', + "await Promise.all([import('@sei-js/sei-global-wallet'), import('@sei-js/sei-global-wallet/eip6963'), import('@sei-js/sei-global-wallet/ethereum')]);" + ], + waivedDir + ); + const waivedAudit = parseJsonOutput((await run(['npm', 'audit', '--json'], waivedDir)).stdout); + assertAuditClean(waivedAudit, 'Waived npm consumer'); + } + + const npmConsumerDir = join(temporaryRoot, 'npm-full'); + await mkdir(npmConsumerDir); + await writeJson(join(npmConsumerDir, 'package.json'), fullConsumerManifest(tarball, 'npm')); + await setupConsumerFiles(npmConsumerDir); + await run(['npm', 'install', '--no-audit', '--no-fund'], npmConsumerDir); + const npmLock = JSON.parse(await readFile(join(npmConsumerDir, 'package-lock.json'), 'utf8')) as PackageLock; + assertNpmDynamicGraph(npmLock); + assert.equal(npmLock.packages['node_modules/ethjs-unit/node_modules/bn.js']?.version, '4.12.5'); + assert.equal(npmLock.packages['node_modules/number-to-bn/node_modules/bn.js']?.version, '4.12.5'); + assert.equal(npmLock.packages['node_modules/bn.js']?.version, '5.2.5'); + assert.equal(npmLock.packages['node_modules/ws']?.version, '8.21.0'); + assert.equal(npmLock.packages['node_modules/viem']?.dependencies?.ws, '8.18.3'); + assert.equal(npmLock.packages['node_modules/jayson']?.dependencies?.ws, '^7.5.10'); + assert.equal(npmLock.packages['node_modules/jayson/node_modules/ws']?.version, '7.5.13'); + await run(['node', 'check-ssr.mjs'], npmConsumerDir); + await run(['node', 'check-edge-native.mjs'], npmConsumerDir); + await run(['node', 'check-local-aa.mjs'], npmConsumerDir); + await run(['npx', '--no-install', 'tsc', '--project', 'tsconfig.json'], npmConsumerDir); + await run( + [ + 'npx', + '--no-install', + 'esbuild', + 'browser-esbuild-entry.mjs', + '--bundle', + '--format=iife', + '--platform=browser', + '--outfile=browser-esbuild.js', + '--metafile=browser-meta.json' + ], + npmConsumerDir + ); + await assertBrowserMetafile(join(npmConsumerDir, 'browser-meta.json'), npmLock); + await runBrowserBundle(join(npmConsumerDir, 'browser-esbuild.js'), true); + await run( + [ + 'npx', + '--no-install', + 'esbuild', + 'edge-entry.mjs', + '--bundle', + '--format=iife', + '--platform=browser', + '--outfile=edge-esbuild.js', + '--metafile=edge-meta.json' + ], + npmConsumerDir + ); + await assertBrowserMetafile(join(npmConsumerDir, 'edge-meta.json'), npmLock); + await runEdgeBundle(join(npmConsumerDir, 'edge-esbuild.js')); + const viteBuild = await run(['npx', '--no-install', 'vite', 'build'], npmConsumerDir); + assert.doesNotMatch( + viteBuild.stderr, + /(?:node:)?worker_threads.*externaliz|externaliz.*(?:node:)?worker_threads/i, + `Vite externalized worker_threads:\n${viteBuild.stderr}` + ); + const viteFiles = (await readdir(join(npmConsumerDir, 'vite-dist'))).filter((path) => path.endsWith('.js')); + assert.equal(viteFiles.length, 1, `Expected one Vite bundle, found: ${viteFiles.join(', ')}`); + await runBrowserBundle(join(npmConsumerDir, 'vite-dist', viteFiles[0]), true); + assertAuditClean(parseJsonOutput((await run(['npm', 'audit', '--json'], npmConsumerDir)).stdout), 'Full npm consumer'); + + if (!fastCheck) { + const bunConsumerDir = join(temporaryRoot, 'bun-full'); + await mkdir(bunConsumerDir); + await writeJson(join(bunConsumerDir, 'package.json'), fullConsumerManifest(tarball, 'bun')); + await setupConsumerFiles(bunConsumerDir); + await run(['bun', 'install'], bunConsumerDir); + const bunLock = await readFile(join(bunConsumerDir, 'bun.lock'), 'utf8'); + assertBunDynamicGraph(bunLock); + assert.match(bunLock, /"bn\.js": \["bn\.js@5\.2\.5"/); + assert.match(bunLock, /"ethjs-unit\/bn\.js": \["bn\.js@4\.11\.6"/); + assert.match(bunLock, /"number-to-bn\/bn\.js": \["bn\.js@4\.11\.6"/); + assert.match(bunLock, /"jayson\/ws": \["ws@7\.5\.13"/); + assert.match(bunLock, /"ws": \["ws@8\.18\.3"/); + await run(['bun', 'check-ssr.mjs'], bunConsumerDir); + await run(['bun', 'check-local-aa.mjs'], bunConsumerDir); + assertAcceptedBunAudit(await run(['bun', 'audit', '--json'], bunConsumerDir, true)); + } + + console.log( + fastCheck + ? 'Sei Global Wallet fast npm consumer checks passed.' + : `Sei Global Wallet consumer checks passed: npm scoped patched bn.js/ws8 while preserving Solana bn5/Jayson ws7 with a clean audit; Bun preserved compatible majors and accepted exactly ${acceptedBunAdvisories.join(', ')}.` + ); +} finally { + await rm(temporaryRoot, { force: true, recursive: true }); +} From d6c004e3ab24c99b943aeb1eb52a895e31269d1e Mon Sep 17 00:00:00 2001 From: alexander-sei Date: Sun, 23 Aug 2026 01:14:05 +0200 Subject: [PATCH 2/4] fix(sei-global-wallet): unbreak CI typecheck and coverage Keep the optional ZeroDev entrypoint out of workspace tests so typecheck no longer loads the AA type graph, and scan hoisted Dynamic 4.96.1 copies in npm lockfiles. Co-authored-by: Cursor --- .../src/lib/__tests__/entrypoints.spec.ts | 19 ++++++++++---- scripts/check-sei-global-wallet.ts | 5 ++-- scripts/dynamic-package-lock.test.ts | 26 +++++++++++++++++++ scripts/dynamic-package-lock.ts | 8 ++++++ 4 files changed, 50 insertions(+), 8 deletions(-) create mode 100644 scripts/dynamic-package-lock.test.ts create mode 100644 scripts/dynamic-package-lock.ts diff --git a/packages/sei-global-wallet/src/lib/__tests__/entrypoints.spec.ts b/packages/sei-global-wallet/src/lib/__tests__/entrypoints.spec.ts index afbfeb61d..eeb4c68f2 100644 --- a/packages/sei-global-wallet/src/lib/__tests__/entrypoints.spec.ts +++ b/packages/sei-global-wallet/src/lib/__tests__/entrypoints.spec.ts @@ -1,13 +1,13 @@ import { describe, expect, it } from 'bun:test'; +import packageJson from '../../../package.json'; describe('public entrypoints', () => { - it('imports the root and every subpath during SSR', async () => { - const [root, eip6963, ethereum, solana, zerodev] = await Promise.all([ + it('imports the root and every non-AA subpath during SSR', async () => { + const [root, eip6963, ethereum, solana] = await Promise.all([ import('../../index'), import('../../eip6963'), import('../../ethereum'), - import('../../solana'), - import('../../zerodev') + import('../../solana') ]); expect(root.default).toBe(root.Wallet); @@ -17,6 +17,15 @@ describe('public entrypoints', () => { expect(typeof ethereum.createEIP1193Provider).toBe('function'); expect(typeof solana.createSolanaWallet).toBe('function'); expect(typeof solana.registerSolanaStandard).toBe('function'); - expect(typeof zerodev.createKernelClient).toBe('function'); + }); + + it('keeps the optional zerodev export for consumers that install Dynamic AA', () => { + expect(packageJson.exports['./zerodev']).toEqual({ + types: './dist/zerodev.d.ts', + import: './dist/zerodev.js', + default: './dist/zerodev.js' + }); + expect(packageJson.peerDependencies['@dynamic-labs/ethereum-aa']).toBe('4.96.3'); + expect(packageJson.peerDependenciesMeta['@dynamic-labs/ethereum-aa']).toEqual({ optional: true }); }); }); diff --git a/scripts/check-sei-global-wallet.ts b/scripts/check-sei-global-wallet.ts index 7910ff354..ea58bcb4b 100644 --- a/scripts/check-sei-global-wallet.ts +++ b/scripts/check-sei-global-wallet.ts @@ -5,6 +5,7 @@ import { tmpdir } from 'node:os'; import { dirname, join, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; import vm from 'node:vm'; +import { findStaleDynamicPackages } from './dynamic-package-lock.js'; interface ProcessResult { exitCode: number; @@ -515,9 +516,7 @@ const assertNpmDynamicGraph = (lock: PackageLock) => { assert.equal(lock.packages['node_modules/@dynamic-labs/global-wallet-client']?.version, '4.96.3'); assert.equal(lock.packages['node_modules/@dynamic-labs/ethereum-aa']?.version, '4.96.3'); - const stale = Object.entries(lock.packages).filter( - ([location, metadata]) => location.includes('/node_modules/@dynamic-labs/') && metadata.version === '4.96.1' - ); + const stale = findStaleDynamicPackages(lock.packages); assert.deepEqual(stale, [], `Unexpected stale Dynamic 4.96.1 npm resolutions: ${stale.map(([location]) => location).join(', ')}`); }; diff --git a/scripts/dynamic-package-lock.test.ts b/scripts/dynamic-package-lock.test.ts new file mode 100644 index 000000000..a9fec5c7b --- /dev/null +++ b/scripts/dynamic-package-lock.test.ts @@ -0,0 +1,26 @@ +import { describe, expect, test } from 'bun:test'; +import { findStaleDynamicPackages, isDynamicLabsLockLocation, STALE_DYNAMIC_VERSION } from './dynamic-package-lock.js'; + +describe('dynamic package lock locations', () => { + test('matches hoisted and nested Dynamic packages', () => { + expect(isDynamicLabsLockLocation('node_modules/@dynamic-labs/logger')).toBe(true); + expect(isDynamicLabsLockLocation('node_modules/@dynamic-labs/global-wallet-client')).toBe(true); + expect(isDynamicLabsLockLocation('node_modules/foo/node_modules/@dynamic-labs/logger')).toBe(true); + expect(isDynamicLabsLockLocation('node_modules/@dynamic-labs')).toBe(false); + expect(isDynamicLabsLockLocation('node_modules/axios')).toBe(false); + }); + + test('rejects stale 4.96.1 copies at the top level and when nested', () => { + const stale = findStaleDynamicPackages({ + 'node_modules/@dynamic-labs/logger': { version: STALE_DYNAMIC_VERSION }, + 'node_modules/@dynamic-labs/global-wallet-client': { version: '4.96.3' }, + 'node_modules/viem/node_modules/@dynamic-labs/message-transport': { version: STALE_DYNAMIC_VERSION }, + 'node_modules/axios': { version: STALE_DYNAMIC_VERSION } + }); + + expect(stale.map(([location]) => location).sort()).toEqual([ + 'node_modules/@dynamic-labs/logger', + 'node_modules/viem/node_modules/@dynamic-labs/message-transport' + ]); + }); +}); diff --git a/scripts/dynamic-package-lock.ts b/scripts/dynamic-package-lock.ts new file mode 100644 index 000000000..6c446945d --- /dev/null +++ b/scripts/dynamic-package-lock.ts @@ -0,0 +1,8 @@ +export const STALE_DYNAMIC_VERSION = '4.96.1'; + +const DYNAMIC_PACKAGE_LOCATION = /(?:^|\/)node_modules\/@dynamic-labs\//; + +export const isDynamicLabsLockLocation = (location: string) => DYNAMIC_PACKAGE_LOCATION.test(location); + +export const findStaleDynamicPackages = (packages: Record, staleVersion = STALE_DYNAMIC_VERSION) => + Object.entries(packages).filter(([location, metadata]) => isDynamicLabsLockLocation(location) && metadata.version === staleVersion); From 8428369722ffe5a7487be9c0db1b94f1d6b912dc Mon Sep 17 00:00:00 2001 From: alexander-sei Date: Sun, 23 Aug 2026 02:40:32 +0200 Subject: [PATCH 3/4] Harden Sei Global Wallet release compatibility This release widens optional peer ranges and keeps compatible installs working without narrowing the contract, while preserving direct wallet-standard resolution and required transient runtime shims. It installs missing browser globals before Dynamic loads, adds EIP-6963 cleanup and provider metadata safeguards, and expands the release smoke checks to cover clean consumer installs, SSR, browser bundles, dependency graphs, and package contents. The patch also updates the README and changeset to document the temporary consumer override waiver and the verified Dynamic peer matrix. --- .../fix-global-wallet-release-blockers.md | 50 +--- .github/workflows/sei-global-wallet-smoke.yml | 21 +- bun.lock | 13 +- packages/sei-global-wallet/README.md | 60 +++-- packages/sei-global-wallet/package.json | 15 +- .../src/lib/EIP6963Emitter.ts | 2 +- .../__tests__/browserGlobal.preserve.spec.ts | 34 +++ .../src/lib/__tests__/browserGlobal.spec.ts | 31 +++ .../src/lib/__tests__/entrypoints.spec.ts | 28 ++- .../src/lib/browserGlobal.ts | 28 ++- packages/sei-global-wallet/src/lib/config.ts | 15 +- scripts/check-sei-global-wallet.ts | 233 ++++++++++++++---- scripts/dynamic-package-lock.test.ts | 87 +++++-- scripts/dynamic-package-lock.ts | 43 +++- 14 files changed, 492 insertions(+), 168 deletions(-) create mode 100644 packages/sei-global-wallet/src/lib/__tests__/browserGlobal.preserve.spec.ts create mode 100644 packages/sei-global-wallet/src/lib/__tests__/browserGlobal.spec.ts diff --git a/.changeset/fix-global-wallet-release-blockers.md b/.changeset/fix-global-wallet-release-blockers.md index 1730099e4..f94865bd9 100644 --- a/.changeset/fix-global-wallet-release-blockers.md +++ b/.changeset/fix-global-wallet-release-blockers.md @@ -1,48 +1,18 @@ --- -"@sei-js/sei-global-wallet": patch +'@sei-js/sei-global-wallet': minor --- -Fix the Sei Global Wallet browser, peer-dependency, EIP-6963, and packaging release blockers. +Harden Sei Global Wallet browser, EIP-6963, and packaging behavior without changing what existing installs resolve. -- Pin `@dynamic-labs/global-wallet-client` to the audited 4.96.3 release and mirror its optional peer contract, including exact Dynamic AA, Solana web3, ZeroDev, and zkSync SSO versions plus the compatible Viem floor and wallet-standard ranges. -- Initialize Dynamic's required globals before loading its modules in browsers and edge-like SSR runtimes, without consumer bundler configuration and without replacing consumer-defined values. +New exports: `registerEIP6963Provider`, `unregisterEIP6963Provider`, `eip6963ProviderInfo`, and `registerSolanaStandard`. + +- Raise `@dynamic-labs/global-wallet-client` to `^4.96.3`, so applications inherit Dynamic's transitive fixes without waiting for a release here. +- Initialize Dynamic's required `global` and `process` aliases before loading its modules in browsers and edge-like SSR runtimes, without consumer bundler configuration and without replacing consumer-defined values. `process.env.NODE_ENV` defaults to `production` so libraries loaded afterwards do not take a development branch inside a production bundle. - Dispatch the initial EIP-6963 announcement, re-announce on every provider request, expose cleanup helpers, use stable UUIDv4 provider metadata, and replace the non-square wordmark with the unmodified square black mark from the official Sei brand kit. +- Keep the root, `./eip6963`, and `./ethereum` entrypoints resolvable with no optional peer installed, including for types. - Verify real npm and Bun consumers, all five entrypoints, EIP-6963 and Solana registration, ZeroDev resolution, esbuild and Vite browser runtimes, SSR imports, types, audits, and package contents. -> [!WARNING] -> This release has a temporary consumer security waiver. Dynamic 4.96.3 transitively pins vulnerable `axios@1.16.0` and `uuid@11.1.0`, and dependency overrides in a library do not propagate. - -Complete npm root overrides without optional AA: - -```json -{ - "overrides": { - "axios": "1.18.0", - "uuid": "11.1.1", - "viem": { - "ws": "8.21.0" - } - } -} -``` - -Complete Bun root overrides without optional AA: - -```json -{ - "overrides": { - "axios": "1.18.0", - "uuid": "11.1.1" - } -} -``` +Every optional peer range stays a superset of the 1.4.1 contract, and `@wallet-standard/wallet` stays a direct dependency, so no existing install changes how it resolves. The `events` dependency is present so bundlers can resolve the bare `events` specifier that `@zerodev/sdk` imports; browser builds of the `./zerodev` path fail without it. Dynamic 4.96.3's own peer contract is the version set this release is verified against; it is documented under [Optional peer versions](https://github.com/sei-protocol/sei-js/blob/main/packages/sei-global-wallet/README.md#optional-peer-versions) as guidance rather than enforced through narrowed ranges. -The high-severity Axios issue applies to the Node HTTP adapter and requires a prerequisite prototype-pollution/interceptor pattern; browser wallet paths avoid that adapter. The UUID issue applies to v3/v5/v6 buffer APIs, while Dynamic's observed usage is v4. Those constraints reduce exploitability but do not remove the audit findings or the root-override requirement. - -Consumers enabling the optional ZeroDev / Dynamic AA path should use npm's package-scoped overrides to replace the exact vulnerable `bn.js@4.11.6` copies beneath `ethjs-unit` and `number-to-bn` with major-compatible `bn.js@4.12.5` (the GHSA fix floor is 4.12.3). This coexists with Solana's `bn.js@5.2.5` and produces a clean npm audit. - -Bun 1.3.14 does not support those scoped overrides. Bun consumers must not globally downgrade bn.js or upgrade ws because that breaks Solana/borsh bn5 or Jayson ws7 contracts. With the safe Axios/UUID overrides, a Bun consumer enabling AA retains the documented bn.js and Viem ws advisories as part of this explicit waiver. - -The ZeroDev browser path pins `viem@2.45.3` to avoid the `node:worker_threads` Vite externalization introduced by the previously tested Viem 2.55.19/Ox Tempo graph. npm scopes Viem's ws8 subtree to patched `ws@8.21.0` while preserving Jayson `ws@7.5.13` from its ws7 range. Bun preserves Viem `ws@8.18.3` and Jayson ws7 and accepts exactly GHSA-378v-28hj-76wf, GHSA-58qx-3vcg-4xpx, and GHSA-96hv-2xvq-fx4p. Browser checks invoke the released `./zerodev` export in both esbuild and Vite and reject worker externalization warnings. - -Dynamic's direct wallet/AA graph is 4.96.3. Regenerating the Bun lockfile proved the previous nested Dynamic 4.96.1 logger/message-transport subtree was stale rather than required by `@dynamic-labs-wallet/browser-wallet-client@1.0.92`'s compatible ranges. Clean npm/Bun graph and browser-metafile checks now reject any remaining Dynamic 4.96.1 runtime. +> [!WARNING] +> This release carries a temporary consumer security waiver: Dynamic transitively pins vulnerable `axios` and `uuid`, and dependency overrides in a library do not propagate to applications. See [Required consumer overrides](https://github.com/sei-protocol/sei-js/blob/main/packages/sei-global-wallet/README.md#required-consumer-overrides) for the exact override blocks and the accepted advisory set. diff --git a/.github/workflows/sei-global-wallet-smoke.yml b/.github/workflows/sei-global-wallet-smoke.yml index 31a805e79..ff7169dd3 100644 --- a/.github/workflows/sei-global-wallet-smoke.yml +++ b/.github/workflows/sei-global-wallet-smoke.yml @@ -9,13 +9,32 @@ on: - 'package.json' - 'packages/sei-global-wallet/**' - 'scripts/check-sei-global-wallet.ts' + - 'scripts/dynamic-package-lock*' - 'tsconfig.base.json' - 'tsconfig.test.json' + # The publishing commit is the merge of the generated "Version Packages" pull + # request, so a pull_request-only trigger never gates the release itself. + push: + branches: [main] + paths: + - '.changeset/**' + - '.github/workflows/sei-global-wallet-smoke.yml' + - 'bun.lock' + - 'package.json' + - 'packages/sei-global-wallet/**' + - 'scripts/check-sei-global-wallet.ts' + - 'scripts/dynamic-package-lock*' + - 'tsconfig.base.json' + - 'tsconfig.test.json' + # Consumer installs resolve live registry and advisory data, which drifts + # without any change in this repository. + schedule: + - cron: '17 6 * * *' workflow_dispatch: concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true + cancel-in-progress: ${{ github.event_name == 'pull_request' }} permissions: contents: read diff --git a/bun.lock b/bun.lock index 638fa75d2..58cf19f59 100644 --- a/bun.lock +++ b/bun.lock @@ -76,7 +76,8 @@ "name": "@sei-js/sei-global-wallet", "version": "1.4.1", "dependencies": { - "@dynamic-labs/global-wallet-client": "4.96.3", + "@dynamic-labs/global-wallet-client": "^4.96.3", + "@wallet-standard/wallet": "^1.1.0", "events": "3.3.0", "process": "0.11.10", }, @@ -92,15 +93,14 @@ "zksync-sso": "0.2.0", }, "peerDependencies": { - "@dynamic-labs/ethereum-aa": "4.96.3", + "@dynamic-labs/ethereum-aa": "^4.15.0", "@solana/wallet-standard-features": "^1.2.0", - "@solana/web3.js": "1.98.1", + "@solana/web3.js": "^1.92.1", "@wallet-standard/base": "^1.0.1", "@wallet-standard/features": "^1.0.3", "@wallet-standard/wallet": "^1.1.0", - "@zerodev/sdk": "5.5.7", - "viem": "2.45.3", - "zksync-sso": "0.2.0", + "@zerodev/sdk": "^5.4.36", + "viem": "^2.7.12", }, "optionalPeers": [ "@dynamic-labs/ethereum-aa", @@ -111,7 +111,6 @@ "@wallet-standard/wallet", "@zerodev/sdk", "viem", - "zksync-sso", ], }, }, diff --git a/packages/sei-global-wallet/README.md b/packages/sei-global-wallet/README.md index a792132f5..474286a6e 100644 --- a/packages/sei-global-wallet/README.md +++ b/packages/sei-global-wallet/README.md @@ -14,8 +14,8 @@ > [!WARNING] -> **Temporary consumer security waiver:** Dynamic Global Wallet Client 4.96.3 transitively pins vulnerable `axios@1.16.0` and `uuid@11.1.0`. -> Dependency overrides are root-only in both npm and Bun; this package cannot propagate them to your application. Add the overrides below before installing. +> **Temporary consumer security waiver:** Dynamic Global Wallet Client transitively pins vulnerable `axios` and `uuid` as of 4.96.3, the current floor. +> Dependency overrides are root-only in both npm and Bun; this package cannot propagate them to your application. Add the overrides below before installing, and drop them once your install resolves a Dynamic release that corrects those pins. ## Required consumer overrides @@ -80,7 +80,7 @@ Bun 1.3.14 does not support nested overrides. Do **not** globally override `bn.j For npm, scoped `bn.js@4.12.5` stays on the legacy dependencies' expected major while Solana resolves `bn.js@5.2.5`. Scoped `ws@8.21.0` patches Viem's ws8 subtree while Jayson resolves `ws@7.5.13` from its `^7.5.10` range. The result is audit-clean. -The browser path is temporarily pinned to `viem@2.45.3`: the previously tested 2.55.19 pulls Ox Tempo's `node:worker_threads` path into Vite resolution, while 2.45.3 predates that path. +The verifier builds its browser consumer against `viem@2.45.3`, because the previously tested 2.55.19 pulls Ox Tempo's `node:worker_threads` path into Vite resolution while 2.45.3 predates it. That is a property of the verifier's own bundle, not a constraint on applications: the published `viem` peer range stays `^2.7.12`. If your bundler externalizes `node:worker_threads` on a newer Viem, configure it in your application rather than downgrading. For Bun, scoped overrides are unavailable. The selected waiver therefore accepts exactly these unresolved optional-AA advisories while preserving compatible majors: @@ -88,7 +88,7 @@ For Bun, scoped overrides are unavailable. The selected waiver therefore accepts - `GHSA-58qx-3vcg-4xpx` on Viem's `ws@8.18.3` — moderate, CVSS 4.4. - `GHSA-96hv-2xvq-fx4p` on Viem's `ws@8.18.3` — high, CVSS 7.5. -Jayson remains on `ws@7.5.13`; globally forcing ws8 would violate that major contract. The verifier rejects every advisory outside this exact Bun set. +Jayson remains on `ws@7.5.13`; globally forcing ws8 would violate that major contract. The verifier fails on any advisory outside this set, and reports rather than fails when one of them stops being reported, so an upstream fix or a withdrawn advisory never turns an unrelated pull request red. ## Quick start @@ -114,23 +114,47 @@ The entrypoint dispatches the required initial `eip6963:announceProvider` event - `@sei-js/sei-global-wallet/solana` registers the wallet-standard provider and exports `createSolanaWallet` and `registerSolanaStandard`. - `@sei-js/sei-global-wallet/zerodev` exports `createKernelClient`. -All entrypoints are ESM-only. The package installs missing `global` and `process` aliases before loading Dynamic code in browsers and edge-like SSR runtimes, while preserving consumer-defined values. Consumers do not need Vite, esbuild, or other bundler shims. +All entrypoints are ESM-only. Consumers do not need Vite, esbuild, or other bundler shims. + +### Globals installed on import + +Dynamic 4.x reads Node-style globals, so importing any entrypoint of this package defines them on `globalThis` when they are absent: + +- `globalThis.global`, aliased to `globalThis`. +- `globalThis.process`, set to the `process/browser.js` shim with `env.NODE_ENV` set to `production`. + +Both are `configurable` and `writable`, and neither is installed when the consumer or runtime already defines it. `NODE_ENV` is set because the browser shim ships an empty `env`, and libraries that branch on `process.env.NODE_ENV !== 'production'` would otherwise take their development path inside a production bundle. These are true globals, so every library loaded afterwards observes them; if your application needs different values, define `global` and `process` before importing this package and they will be left alone. ## Optional peer versions -The package mirrors Dynamic 4.96.3's optional peer contract. Install only the peers needed by the subpaths your application uses: +Install only the peers needed by the subpaths your application uses. The declared ranges stay deliberately wide, because an optional peer still fails `npm install` with `ERESOLVE` once your application has the package at a version outside the range. The **verified** column is Dynamic 4.96.3's own peer contract, which is the set this package's release checks run against. + +| Peer | Declared range | Verified against | Needed by | +| --- | --- | --- | --- | +| `viem` | `^2.7.12` | `2.45.3` | `./zerodev`, Dynamic AA | +| `@dynamic-labs/ethereum-aa` | `^4.15.0` | `4.96.3` | `./zerodev` | +| `@zerodev/sdk` | `^5.4.36` | `5.5.7` | `./zerodev` | +| `@solana/web3.js` | `^1.92.1` | `1.98.1` | `./solana` | +| `@solana/wallet-standard-features` | `^1.2.0` | `^1.2.0` | `./solana` | +| `@wallet-standard/base` | `^1.0.1` | `^1.0.1` | `./solana` | +| `@wallet-standard/features` | `^1.0.3` | `^1.0.3` | `./solana` | +| `@wallet-standard/wallet` | `^1.1.0` | `^1.1.0` | `./solana` | -- `@dynamic-labs/ethereum-aa@4.96.3` -- `@solana/web3.js@1.98.1` -- `@solana/wallet-standard-features@^1.2.0` -- `@wallet-standard/base@^1.0.1` -- `@wallet-standard/features@^1.0.3` -- `@wallet-standard/wallet@^1.1.0` -- `@zerodev/sdk@5.5.7` -- `viem@2.45.3` -- `zksync-sso@0.2.0` +> [!NOTE] +> Dynamic 4.96.3 pins several of these exactly for itself, so a version outside the verified column can still be rejected by Dynamic's own peer contract during install, and is not covered by this package's checks. Prefer the verified versions; the wide ranges exist so that upgrading this package never breaks an install on its own. +> +> Dynamic also declares an optional `zksync-sso@0.2.0` peer for its zkSync path. This package does not redeclare it, so npm surfaces that requirement from Dynamic directly. -Dynamic's direct wallet and AA packages resolve to 4.96.3. A full Bun lockfile regeneration showed that the previous isolated Dynamic 4.96.1 subtree beneath `@dynamic-labs-wallet/browser-wallet-client@1.0.92` was stale: its `^4.81.0` ranges resolve compatibly without 4.96.1. Clean npm and Bun graphs now contain no Dynamic 4.96.1 packages, and browser metafile checks reject their return as direct runtime code. +Two dependencies exist for transitive resolution rather than for this package's own source, so neither is removable despite nothing here importing them: + +- `@wallet-standard/wallet`, because Dynamic's `./solana` module imports it, so `@sei-js/sei-global-wallet/solana` needs it present at runtime. +- `events`, because `@zerodev/sdk` imports the bare `events` specifier. Bundling the `./zerodev` path for the browser fails with `Could not resolve "events"` unless that polyfill is in the tree. + +The root, `./eip6963`, and `./ethereum` entrypoints need no optional peer at all, including for type resolution. The release verifier typechecks them with `skipLibCheck: false` in a consumer that installs nothing but this package, so a published declaration that referenced a type from an uninstalled peer would fail the check. + +`@dynamic-labs/global-wallet-client` is a `^4.96.3` dependency rather than an exact pin, so applications inherit Dynamic's transitive fixes without waiting for a release here. This repository's lockfile pins the exact version it tests. + +A full Bun lockfile regeneration showed that the previous isolated Dynamic 4.96.1 subtree beneath `@dynamic-labs-wallet/browser-wallet-client@1.0.92` was stale: its `^4.81.0` ranges resolve compatibly without it. The verifier now asserts that no `@dynamic-labs/*` package resolves to more than one version, in npm and Bun graphs and in browser bundles, which stays meaningful across Dynamic upgrades. ## Brand asset @@ -141,4 +165,6 @@ The pinned source includes its terminal newline and has SHA-256 `e288cd08b510afb ## Release verification -The dedicated `Sei Global Wallet Consumer Smoke` workflow runs on wallet-related pull-request paths and can be started manually with `workflow_dispatch` before release. It executes `bun run test:sei-global-wallet-release`, including an audit-clean scoped npm consumer, a waiver-aware Bun consumer, native and bundled edge-like SSR, real local ZeroDev provider operations in esbuild/Vite, dependency graphs, and package contents. Its output names the exact accepted Bun set: `GHSA-378v-28hj-76wf`, `GHSA-58qx-3vcg-4xpx`, and `GHSA-96hv-2xvq-fx4p`; the verifier fails if Bun reports any new, missing, or different advisory. Regular package tests remain deterministic and do not perform clean consumer installs. +The dedicated `Sei Global Wallet Consumer Smoke` workflow runs on wallet-related paths for pull requests and for pushes to `main` (so the publishing commit is gated too), daily on a schedule to catch registry and advisory drift, and on demand with `workflow_dispatch`. It executes `bun run test:sei-global-wallet-release`, including an audit-clean scoped npm consumer, a waiver-aware Bun consumer, declarations that resolve with no optional peer installed, native and bundled edge-like SSR, real local ZeroDev provider operations in esbuild/Vite, dependency graphs, and package contents. Regular package tests remain deterministic and do not perform clean consumer installs. + +`SEI_GLOBAL_WALLET_FAST_CHECK=1` shortens the local loop by skipping the two clean npm consumers and the entire Bun consumer path, so a green run under that flag covers neither the audit waiver nor Bun. Release verification must run without it, which is what CI does. diff --git a/packages/sei-global-wallet/package.json b/packages/sei-global-wallet/package.json index 395dedbb2..19d437586 100644 --- a/packages/sei-global-wallet/package.json +++ b/packages/sei-global-wallet/package.json @@ -24,7 +24,8 @@ "test": "bun test --isolate src" }, "dependencies": { - "@dynamic-labs/global-wallet-client": "4.96.3", + "@dynamic-labs/global-wallet-client": "^4.96.3", + "@wallet-standard/wallet": "^1.1.0", "events": "3.3.0", "process": "0.11.10" }, @@ -40,15 +41,14 @@ "zksync-sso": "0.2.0" }, "peerDependencies": { - "@dynamic-labs/ethereum-aa": "4.96.3", + "@dynamic-labs/ethereum-aa": "^4.15.0", "@solana/wallet-standard-features": "^1.2.0", - "@solana/web3.js": "1.98.1", + "@solana/web3.js": "^1.92.1", "@wallet-standard/base": "^1.0.1", "@wallet-standard/features": "^1.0.3", "@wallet-standard/wallet": "^1.1.0", - "@zerodev/sdk": "5.5.7", - "viem": "2.45.3", - "zksync-sso": "0.2.0" + "@zerodev/sdk": "^5.4.36", + "viem": "^2.7.12" }, "peerDependenciesMeta": { "viem": { @@ -74,9 +74,6 @@ }, "@dynamic-labs/ethereum-aa": { "optional": true - }, - "zksync-sso": { - "optional": true } }, "typesVersions": { diff --git a/packages/sei-global-wallet/src/lib/EIP6963Emitter.ts b/packages/sei-global-wallet/src/lib/EIP6963Emitter.ts index cf26426c3..1f0a67f89 100644 --- a/packages/sei-global-wallet/src/lib/EIP6963Emitter.ts +++ b/packages/sei-global-wallet/src/lib/EIP6963Emitter.ts @@ -16,7 +16,7 @@ export interface EIP6963ProviderDetail { } export const eip6963ProviderInfo: Readonly = Object.freeze({ - icon: config.walletIcon as DataURIImage, + icon: config.walletIcon, name: config.walletName, rdns: config.eip6963.rdns, uuid: config.eip6963.uuid diff --git a/packages/sei-global-wallet/src/lib/__tests__/browserGlobal.preserve.spec.ts b/packages/sei-global-wallet/src/lib/__tests__/browserGlobal.preserve.spec.ts new file mode 100644 index 000000000..0a87764dc --- /dev/null +++ b/packages/sei-global-wallet/src/lib/__tests__/browserGlobal.preserve.spec.ts @@ -0,0 +1,34 @@ +import { describe, expect, it } from 'bun:test'; + +// Separate file so `bun test --isolate` gives this the only import of the shim +// in its registry, with both globals already present. +describe('browser global shim with consumer values present', () => { + it('leaves consumer-defined global and process untouched', async () => { + const originalGlobal = Object.getOwnPropertyDescriptor(globalThis, 'global'); + const originalProcess = Object.getOwnPropertyDescriptor(globalThis, 'process'); + const consumerGlobal = { sentinel: 'consumer-global' }; + const consumerProcess = { env: { NODE_ENV: 'development' }, sentinel: 'consumer-process' }; + Object.defineProperty(globalThis, 'global', { configurable: true, value: consumerGlobal, writable: true }); + Object.defineProperty(globalThis, 'process', { configurable: true, value: consumerProcess, writable: true }); + + try { + await import('../browserGlobal.js'); + + // Read through Reflect so the ambient Node global typings do not narrow + // the comparison against these sentinels. + const installedGlobal: unknown = Reflect.get(globalThis, 'global'); + const installedProcess: unknown = Reflect.get(globalThis, 'process'); + + expect(installedGlobal).toBe(consumerGlobal); + expect(installedProcess).toBe(consumerProcess); + // The shim must not rewrite an environment the consumer chose. + expect(consumerProcess.env.NODE_ENV).toBe('development'); + } finally { + if (originalGlobal) Object.defineProperty(globalThis, 'global', originalGlobal); + else Reflect.deleteProperty(globalThis, 'global'); + + if (originalProcess) Object.defineProperty(globalThis, 'process', originalProcess); + else Reflect.deleteProperty(globalThis, 'process'); + } + }); +}); diff --git a/packages/sei-global-wallet/src/lib/__tests__/browserGlobal.spec.ts b/packages/sei-global-wallet/src/lib/__tests__/browserGlobal.spec.ts new file mode 100644 index 000000000..ae30ae3cd --- /dev/null +++ b/packages/sei-global-wallet/src/lib/__tests__/browserGlobal.spec.ts @@ -0,0 +1,31 @@ +import { describe, expect, it } from 'bun:test'; + +// Runs in its own module registry (`bun test --isolate`), so the shim's +// import-time side effect is observed exactly once against absent globals. +describe('browser global shim with nothing defined', () => { + it('installs global and a process shim that reports a production NODE_ENV', async () => { + const originalGlobal = Object.getOwnPropertyDescriptor(globalThis, 'global'); + const originalProcess = Object.getOwnPropertyDescriptor(globalThis, 'process'); + Reflect.deleteProperty(globalThis, 'global'); + Reflect.deleteProperty(globalThis, 'process'); + + try { + await import('../browserGlobal.js'); + + const runtime = globalThis as typeof globalThis & { + global?: unknown; + process?: { browser?: boolean; env?: Record; nextTick?: unknown }; + }; + + expect(runtime.global).toBe(globalThis); + expect(runtime.process?.browser).toBe(true); + expect(typeof runtime.process?.nextTick).toBe('function'); + // Without this, libraries gating on NODE_ENV take their development + // branch inside a production browser bundle. + expect(runtime.process?.env?.NODE_ENV).toBe('production'); + } finally { + if (originalGlobal) Object.defineProperty(globalThis, 'global', originalGlobal); + if (originalProcess) Object.defineProperty(globalThis, 'process', originalProcess); + } + }); +}); diff --git a/packages/sei-global-wallet/src/lib/__tests__/entrypoints.spec.ts b/packages/sei-global-wallet/src/lib/__tests__/entrypoints.spec.ts index eeb4c68f2..ceee5d192 100644 --- a/packages/sei-global-wallet/src/lib/__tests__/entrypoints.spec.ts +++ b/packages/sei-global-wallet/src/lib/__tests__/entrypoints.spec.ts @@ -25,7 +25,33 @@ describe('public entrypoints', () => { import: './dist/zerodev.js', default: './dist/zerodev.js' }); - expect(packageJson.peerDependencies['@dynamic-labs/ethereum-aa']).toBe('4.96.3'); expect(packageJson.peerDependenciesMeta['@dynamic-labs/ethereum-aa']).toEqual({ optional: true }); }); + + // Optional peers only stop erroring when absent; once an application has one, + // a narrower range than 1.4.1 published fails its install with ERESOLVE. Any + // change here must stay a superset of these ranges. + it('keeps every optional peer range compatible with the 1.4.1 contract', () => { + expect(packageJson.peerDependencies).toEqual({ + '@dynamic-labs/ethereum-aa': '^4.15.0', + '@solana/wallet-standard-features': '^1.2.0', + '@solana/web3.js': '^1.92.1', + '@wallet-standard/base': '^1.0.1', + '@wallet-standard/features': '^1.0.3', + '@wallet-standard/wallet': '^1.1.0', + '@zerodev/sdk': '^5.4.36', + viem: '^2.7.12' + }); + }); + + // Dynamic's ./solana module imports @wallet-standard/wallet directly, so the + // solana entrypoint needs it installed rather than merely declared as a peer. + it('keeps @wallet-standard/wallet installed for the solana entrypoint', () => { + expect(packageJson.dependencies['@wallet-standard/wallet']).toBe('^1.1.0'); + }); + + // An exact pin would make every Dynamic transitive fix wait on a release here. + it('declares the Dynamic dependency as a range', () => { + expect(packageJson.dependencies['@dynamic-labs/global-wallet-client']).toBe('^4.96.3'); + }); }); diff --git a/packages/sei-global-wallet/src/lib/browserGlobal.ts b/packages/sei-global-wallet/src/lib/browserGlobal.ts index fabf7a472..6f2cac900 100644 --- a/packages/sei-global-wallet/src/lib/browserGlobal.ts +++ b/packages/sei-global-wallet/src/lib/browserGlobal.ts @@ -7,23 +7,27 @@ type BrowserGlobal = typeof globalThis & { const runtime = globalThis as BrowserGlobal; -// Dynamic 4.x reads Node-style globals in browser and edge-like runtimes, but -// its own polyfills can execute later after bundling. Install only missing -// values and preserve anything the consumer already set. -if (typeof runtime.global === 'undefined') { - Object.defineProperty(runtime, 'global', { +const install = (key: 'global' | 'process', value: unknown) => { + Object.defineProperty(runtime, key, { configurable: true, enumerable: false, - value: runtime, + value, writable: true }); +}; + +// Dynamic 4.x reads Node-style globals in browser and edge-like runtimes, but +// its own polyfills can execute later after bundling. Install only missing +// values and preserve anything the consumer already set. +if (typeof runtime.global === 'undefined') { + install('global', runtime); } if (typeof runtime.process === 'undefined') { - Object.defineProperty(runtime, 'process', { - configurable: true, - enumerable: false, - value: processShim, - writable: true - }); + // Every library loaded after this point shares the shim, and + // `process/browser.js` ships an empty `env`. Libraries that branch on + // `process.env.NODE_ENV !== 'production'` would otherwise take their + // development path inside a production bundle. + processShim.env.NODE_ENV ??= 'production'; + install('process', processShim); } diff --git a/packages/sei-global-wallet/src/lib/config.ts b/packages/sei-global-wallet/src/lib/config.ts index 71443f06a..69f2ddd41 100644 --- a/packages/sei-global-wallet/src/lib/config.ts +++ b/packages/sei-global-wallet/src/lib/config.ts @@ -1,9 +1,11 @@ -import type { WalletIcon } from '@wallet-standard/base'; import type { DataURIImage } from './dynamicClient.js'; +// Deliberately free of `@wallet-standard/base`: config.d.ts is reachable from +// the root and eip6963 entrypoints, which must typecheck without any optional +// peer installed. The Solana path narrows this to `WalletIcon` at its boundary. interface WalletConfig { walletName: string; - walletIcon: DataURIImage | WalletIcon; + walletIcon: DataURIImage; walletUrl: string; environmentId: string; eip6963: { @@ -16,10 +18,11 @@ export const config: WalletConfig = { // Wallet name will be seen as the Wallet name walletName: 'Sei Global Wallet', // Wallet icon will be seen as the Wallet icon - // Exact, unrecolored encoding of the official square Sei mark: + // Exact, unrecolored encoding of the official square Sei mark, including the + // source file's terminal newline. config.spec.ts pins the decoded SHA-256: // https://github.com/sei-protocol/sei-docs/blob/8710d6078058bdf67ec704b346f75ee9883e25ea/assets/brand/logo/sei-mark.svg walletIcon: - 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNDAiIGhlaWdodD0iMjQwIiB2aWV3Qm94PSIwIDAgMjMuOTk2NSAyMy45OTY1IiBmaWxsPSIjMDAwMDAwIj48dGl0bGU+U2VpIG1hcms8L3RpdGxlPjxwYXRoIGQ9Ik0xMS45OTY5IDIzLjk5NjVIMTEuOTk2NUwxMS45OTY3IDIzLjk5NjVMMTEuOTk2OSAyMy45OTY1WiIvPjxwYXRoIGQ9Ik0xNi4wODUgMTkuNTI1NkMxNi44MDYxIDE4Ljg2ODkgMTcuOTA5MiAxOC44NjkgMTguNjMwMyAxOS41MjU4TDE4LjYzMDUgMTkuNTI1OUwyMC4wOTEgMjAuODU1OEMxNy45NTcgMjIuODA2NSAxNS4xMTU4IDIzLjk5NjUgMTEuOTk2NyAyMy45OTY1QzguODg4MjQgMjMuOTk2NCA2LjA1NTkxIDIyLjgxNDcgMy45MjQ0OCAyMC44NzZMNS40MDcyIDE5LjUyNTlMNS40MDczNCAxOS41MjU4QzYuMTI4NDQgMTguODY5IDcuMjMxNDcgMTguODY4OSA3Ljk1MjY1IDE5LjUyNTZMOS4yNTA4OCAyMC43MDg3TDkuMjUxMDkgMjAuNzA4OUMxMC44MTk1IDIyLjEzNzQgMTMuMjE4MiAyMi4xMzc0IDE0Ljc4NjYgMjAuNzA4OUwxNC43ODY4IDIwLjcwODdMMTYuMDg1IDE5LjUyNTZMMTYuMDg1IDE5LjUyNTZaIi8+PHBhdGggZD0iTTExLjk5NjUgMEMxNS4xMjE0IDAgMTcuOTY3MiAxLjE5NDIxIDIwLjEwMjUgMy4xNTEwNUMyMC4wNDEyIDMuMjAwNzUgMTkuOTgxIDMuMjUyNDUgMTkuOTIyIDMuMzA2MTlMMTkuOTIxOCAzLjMwNjM2TDE4LjYyMzYgNC40ODk0NEMxNy45MDI1IDUuMTQ2MDUgMTYuNzk5NiA1LjE0NjA1IDE2LjA3ODUgNC40ODk0NEwxNC43ODAzIDMuMzA2MzZMMTQuNzggMy4zMDYxOUwxNC43NDMxIDMuMjcyOTZDMTMuMTc0MiAxLjg3NzcyIDEwLjgwMDcgMS44ODg4MyA5LjI0NDU0IDMuMzA2MjJMNS45MjU2NiA2LjMyODMyTDcuNDIwMzggNy45NjkzOUwxMC43Mzk0IDQuOTQ3MTVMMTAuNzM5NSA0Ljk0NzA0QzExLjQ2MDcgNC4yOTAyNSAxMi41NjM3IDQuMjkwMTYgMTMuMjg0OSA0Ljk0NjgzTDE0LjU4MzEgNi4xMjk5MUwxNC41ODMzIDYuMTMwMTJDMTYuMTUxNyA3LjU1ODY2IDE4LjU1MDQgNy41NTg2NiAyMC4xMTg4IDYuMTMwMTJMMjAuMTE5IDYuMTI5OTRMMjEuNDE3MiA0Ljk0Njg3TDIxLjQxNzIgNC45NDY4M0MyMS40NzUzIDQuODkzOTEgMjEuNTM1OSA0Ljg0NTMgMjEuNTk4NiA0LjgwMDkxQzIzLjEwNDMgNi44MDU5MiAyMy45OTY1IDkuMjk3OSAyMy45OTY1IDExLjk5ODNDMjMuOTk2NSAxNC43MDY5IDIzLjA5ODggMTcuMjA1OCAyMS41ODQ3IDE5LjIxMzlMMjAuMTI1MyAxNy44ODVMMjAuMTI1MyAxNy44ODQ5QzE4LjU1NjkgMTYuNDU2NCAxNi4xNTgyIDE2LjQ1NjQgMTQuNTg5OCAxNy44ODQ5TDE0LjU4OTYgMTcuODg1MUwxMy4yOTE0IDE5LjA2ODJDMTIuNTcwMyAxOS43MjQ4IDExLjQ2NzQgMTkuNzI0OCAxMC43NDYzIDE5LjA2ODJMOS40NDgwNSAxNy44ODUxTDkuNDQ3ODQgMTcuODg0OUw5LjQxMDkyIDE3Ljg1MTdDNy44NDIgMTYuNDU2NSA1LjQ2ODQ5IDE2LjQ2NzYgMy45MTIzMyAxNy44ODVMMi40MjY2NCAxOS4yMzc4QzEuMzgxMjcgMTcuODU4NCAwLjYyNzM2NSAxNi4yNDYxIDAuMjU2NTM2IDE0LjQ5MjRMMi43MzQ1OCAxMi4yMzZMMi43MzQ3MiAxMi4yMzU5QzMuNDU1ODYgMTEuNTc5IDQuNTU4NjEgMTEuNTc5IDUuMjc5NzggMTIuMjM1OEw2LjU3ODM3IDEzLjQxODhMNi41Nzg0NyAxMy40MTg5QzguMTQ2ODEgMTQuODQ3NCAxMC41NDU1IDE0Ljg0NzYgMTIuMTEzNyAxMy40MTg4TDEzLjQxMjIgMTIuMjM1OEMxNC4xMzM0IDExLjU3OSAxNS4yMzY1IDExLjU3OSAxNS45NTc3IDEyLjIzNTlMMTUuOTU3OCAxMi4yMzZMMTkuMjc2OSAxNS4yNTgyTDIwLjc3MTYgMTMuNjE3MUwxNy40NTI3IDEwLjU5NUwxNy40NTI3IDEwLjU5NUMxNS44ODQzIDkuMTY2NDYgMTMuNDg1NiA5LjE2NjQ2IDExLjkxNzIgMTAuNTk1TDExLjkxNzEgMTAuNTk1MUwxMC42MTg1IDExLjc3ODJMMTAuNjE4NSAxMS43NzgyQzkuODk3NzkgMTIuNDM0OCA4Ljc5NDc2IDEyLjQzNSA4LjA3MzUyIDExLjc3ODJMNi43NzQ5MyAxMC41OTUxTDYuNzc0ODYgMTAuNTk1TDYuNzM3OTUgMTAuNTYxOEM1LjE2OTAzIDkuMTY2NTQgMi43OTU4NyA5LjE3NzY1IDEuMjM5NzEgMTAuNTk1TDAgMTEuNzIzOUMwLjE0NTg3NiA1LjIyNDM4IDUuNDYwNzEgNy4wNzkxM2UtMDYgMTEuOTk2NSAwWiIvPjwvc3ZnPg==', + 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNDAiIGhlaWdodD0iMjQwIiB2aWV3Qm94PSIwIDAgMjMuOTk2NSAyMy45OTY1IiBmaWxsPSIjMDAwMDAwIj48dGl0bGU+U2VpIG1hcms8L3RpdGxlPjxwYXRoIGQ9Ik0xMS45OTY5IDIzLjk5NjVIMTEuOTk2NUwxMS45OTY3IDIzLjk5NjVMMTEuOTk2OSAyMy45OTY1WiIvPjxwYXRoIGQ9Ik0xNi4wODUgMTkuNTI1NkMxNi44MDYxIDE4Ljg2ODkgMTcuOTA5MiAxOC44NjkgMTguNjMwMyAxOS41MjU4TDE4LjYzMDUgMTkuNTI1OUwyMC4wOTEgMjAuODU1OEMxNy45NTcgMjIuODA2NSAxNS4xMTU4IDIzLjk5NjUgMTEuOTk2NyAyMy45OTY1QzguODg4MjQgMjMuOTk2NCA2LjA1NTkxIDIyLjgxNDcgMy45MjQ0OCAyMC44NzZMNS40MDcyIDE5LjUyNTlMNS40MDczNCAxOS41MjU4QzYuMTI4NDQgMTguODY5IDcuMjMxNDcgMTguODY4OSA3Ljk1MjY1IDE5LjUyNTZMOS4yNTA4OCAyMC43MDg3TDkuMjUxMDkgMjAuNzA4OUMxMC44MTk1IDIyLjEzNzQgMTMuMjE4MiAyMi4xMzc0IDE0Ljc4NjYgMjAuNzA4OUwxNC43ODY4IDIwLjcwODdMMTYuMDg1IDE5LjUyNTZMMTYuMDg1IDE5LjUyNTZaIi8+PHBhdGggZD0iTTExLjk5NjUgMEMxNS4xMjE0IDAgMTcuOTY3MiAxLjE5NDIxIDIwLjEwMjUgMy4xNTEwNUMyMC4wNDEyIDMuMjAwNzUgMTkuOTgxIDMuMjUyNDUgMTkuOTIyIDMuMzA2MTlMMTkuOTIxOCAzLjMwNjM2TDE4LjYyMzYgNC40ODk0NEMxNy45MDI1IDUuMTQ2MDUgMTYuNzk5NiA1LjE0NjA1IDE2LjA3ODUgNC40ODk0NEwxNC43ODAzIDMuMzA2MzZMMTQuNzggMy4zMDYxOUwxNC43NDMxIDMuMjcyOTZDMTMuMTc0MiAxLjg3NzcyIDEwLjgwMDcgMS44ODg4MyA5LjI0NDU0IDMuMzA2MjJMNS45MjU2NiA2LjMyODMyTDcuNDIwMzggNy45NjkzOUwxMC43Mzk0IDQuOTQ3MTVMMTAuNzM5NSA0Ljk0NzA0QzExLjQ2MDcgNC4yOTAyNSAxMi41NjM3IDQuMjkwMTYgMTMuMjg0OSA0Ljk0NjgzTDE0LjU4MzEgNi4xMjk5MUwxNC41ODMzIDYuMTMwMTJDMTYuMTUxNyA3LjU1ODY2IDE4LjU1MDQgNy41NTg2NiAyMC4xMTg4IDYuMTMwMTJMMjAuMTE5IDYuMTI5OTRMMjEuNDE3MiA0Ljk0Njg3TDIxLjQxNzIgNC45NDY4M0MyMS40NzUzIDQuODkzOTEgMjEuNTM1OSA0Ljg0NTMgMjEuNTk4NiA0LjgwMDkxQzIzLjEwNDMgNi44MDU5MiAyMy45OTY1IDkuMjk3OSAyMy45OTY1IDExLjk5ODNDMjMuOTk2NSAxNC43MDY5IDIzLjA5ODggMTcuMjA1OCAyMS41ODQ3IDE5LjIxMzlMMjAuMTI1MyAxNy44ODVMMjAuMTI1MyAxNy44ODQ5QzE4LjU1NjkgMTYuNDU2NCAxNi4xNTgyIDE2LjQ1NjQgMTQuNTg5OCAxNy44ODQ5TDE0LjU4OTYgMTcuODg1MUwxMy4yOTE0IDE5LjA2ODJDMTIuNTcwMyAxOS43MjQ4IDExLjQ2NzQgMTkuNzI0OCAxMC43NDYzIDE5LjA2ODJMOS40NDgwNSAxNy44ODUxTDkuNDQ3ODQgMTcuODg0OUw5LjQxMDkyIDE3Ljg1MTdDNy44NDIgMTYuNDU2NSA1LjQ2ODQ5IDE2LjQ2NzYgMy45MTIzMyAxNy44ODVMMi40MjY2NCAxOS4yMzc4QzEuMzgxMjcgMTcuODU4NCAwLjYyNzM2NSAxNi4yNDYxIDAuMjU2NTM2IDE0LjQ5MjRMMi43MzQ1OCAxMi4yMzZMMi43MzQ3MiAxMi4yMzU5QzMuNDU1ODYgMTEuNTc5IDQuNTU4NjEgMTEuNTc5IDUuMjc5NzggMTIuMjM1OEw2LjU3ODM3IDEzLjQxODhMNi41Nzg0NyAxMy40MTg5QzguMTQ2ODEgMTQuODQ3NCAxMC41NDU1IDE0Ljg0NzYgMTIuMTEzNyAxMy40MTg4TDEzLjQxMjIgMTIuMjM1OEMxNC4xMzM0IDExLjU3OSAxNS4yMzY1IDExLjU3OSAxNS45NTc3IDEyLjIzNTlMMTUuOTU3OCAxMi4yMzZMMTkuMjc2OSAxNS4yNTgyTDIwLjc3MTYgMTMuNjE3MUwxNy40NTI3IDEwLjU5NUwxNy40NTI3IDEwLjU5NUMxNS44ODQzIDkuMTY2NDYgMTMuNDg1NiA5LjE2NjQ2IDExLjkxNzIgMTAuNTk1TDExLjkxNzEgMTAuNTk1MUwxMC42MTg1IDExLjc3ODJMMTAuNjE4NSAxMS43NzgyQzkuODk3NzkgMTIuNDM0OCA4Ljc5NDc2IDEyLjQzNSA4LjA3MzUyIDExLjc3ODJMNi43NzQ5MyAxMC41OTUxTDYuNzc0ODYgMTAuNTk1TDYuNzM3OTUgMTAuNTYxOEM1LjE2OTAzIDkuMTY2NTQgMi43OTU4NyA5LjE3NzY1IDEuMjM5NzEgMTAuNTk1TDAgMTEuNzIzOUMwLjE0NTg3NiA1LjIyNDM4IDUuNDYwNzEgNy4wNzkxM2UtMDYgMTEuOTk2NSAwWiIvPjwvc3ZnPgo=', // URL of your wallet domain (e.g. https://dynamic.example.com) walletUrl: 'https://global-wallet.sei.io', // Environment ID of your wallet (e.g. 1234567890) @@ -32,7 +35,3 @@ export const config: WalletConfig = { uuid: '36b63d10-7ba6-49a3-9614-22f471b9283c' } }; - -// The pinned source ends in `\n`; preserve that terminal byte in the -// base64 data URI instead of relying on editor treatment of a multiline asset. -config.walletIcon = `${config.walletIcon.slice(0, -2)}o=` as DataURIImage; diff --git a/scripts/check-sei-global-wallet.ts b/scripts/check-sei-global-wallet.ts index ea58bcb4b..00632398f 100644 --- a/scripts/check-sei-global-wallet.ts +++ b/scripts/check-sei-global-wallet.ts @@ -5,7 +5,7 @@ import { tmpdir } from 'node:os'; import { dirname, join, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; import vm from 'node:vm'; -import { findStaleDynamicPackages } from './dynamic-package-lock.js'; +import { collectDynamicLineVersions, findDynamicLineConflicts, formatDynamicLineConflicts } from './dynamic-package-lock.js'; interface ProcessResult { exitCode: number; @@ -34,8 +34,52 @@ interface PackageLock { const root = resolve(dirname(fileURLToPath(import.meta.url)), '..'); const packageDir = join(root, 'packages/sei-global-wallet'); const temporaryRoot = await mkdtemp(join(tmpdir(), 'sei-global-wallet-release-')); +// Documented in packages/sei-global-wallet/README.md: skips the clean npm +// consumers and the whole Bun path, so it never substitutes for a full run. const fastCheck = process.env.SEI_GLOBAL_WALLET_FAST_CHECK === '1'; -const acceptedBunAdvisories = ['GHSA-378v-28hj-76wf', 'GHSA-58qx-3vcg-4xpx', 'GHSA-96hv-2xvq-fx4p'] as const; +const acceptedBunAdvisories: readonly string[] = ['GHSA-378v-28hj-76wf', 'GHSA-58qx-3vcg-4xpx', 'GHSA-96hv-2xvq-fx4p']; + +const manifest = JSON.parse(await readFile(join(packageDir, 'package.json'), 'utf8')) as { + dependencies: Record; + peerDependencies: Record; +}; +const dynamicRange = manifest.dependencies['@dynamic-labs/global-wallet-client']; + +// The versions the consumers are built against: Dynamic 4.96.3's own peer +// contract. The published peer ranges stay wider than these on purpose, so an +// application that already carries one of these packages keeps resolving. +const testedPeerVersions = { + '@dynamic-labs/ethereum-aa': '4.96.3', + '@solana/wallet-standard-features': '^1.2.0', + '@solana/web3.js': '1.98.1', + '@wallet-standard/base': '^1.0.1', + '@wallet-standard/features': '^1.0.3', + '@wallet-standard/wallet': '^1.1.0', + '@zerodev/sdk': '5.5.7', + viem: '2.45.3', + 'zksync-sso': '0.2.0' +} as const; + +// Guards the two from drifting: every version the harness installs has to be +// allowed by the range the package publishes. +for (const [name, tested] of Object.entries(testedPeerVersions)) { + const declared = manifest.peerDependencies[name]; + if (!declared || tested.startsWith('^')) continue; + + assert(Bun.semver.satisfies(tested, declared), `Harness installs ${name}@${tested}, which the published ${name}@${declared} peer range excludes`); +} + +// The published manifest carries a range so consumers inherit upstream fixes; +// exactness belongs to the lockfile, not the contract. +const assertSatisfiesDynamicRange = (version: string | undefined, label: string) => { + assert(version, `${label} did not resolve @dynamic-labs/global-wallet-client`); + assert(Bun.semver.satisfies(version, dynamicRange), `${label} resolved @dynamic-labs/global-wallet-client@${version}, outside the declared ${dynamicRange}`); + return version; +}; + +const reportWaiverProgress = (message: string) => { + console.warn(`[waiver] ${message}`); +}; const run = async (command: string[], cwd: string, allowFailure = false): Promise => { const child = Bun.spawn(command, { @@ -100,18 +144,10 @@ const fullConsumerManifest = (tarball: string, packageManager: 'bun' | 'npm') => private: true, type: 'module', dependencies: { - '@dynamic-labs/ethereum-aa': '4.96.3', + ...testedPeerVersions, '@sei-js/sei-global-wallet': `file:${tarball}`, - '@solana/wallet-standard-features': '^1.2.0', - '@solana/web3.js': '1.98.1', - '@wallet-standard/base': '^1.0.1', - '@wallet-standard/features': '^1.0.3', - '@wallet-standard/wallet': '^1.1.0', - '@zerodev/sdk': '5.5.7', 'ethjs-unit': '0.1.6', - 'number-to-bn': '1.7.0', - viem: '2.45.3', - 'zksync-sso': '0.2.0' + 'number-to-bn': '1.7.0' }, devDependencies: { esbuild: '0.28.2', @@ -121,6 +157,52 @@ const fullConsumerManifest = (tarball: string, packageManager: 'bun' | 'npm') => overrides: packageManager === 'npm' ? npmSafeOverrides : baseSafeOverrides }); +/** + * Typechecks the entrypoints that need no optional peer, with `skipLibCheck` + * off, inside a consumer where no optional peer is installed. The full consumer + * installs every peer and skips lib checks, so it cannot catch an emitted + * declaration that leaks a type from a peer the consumer never installed. + */ +const assertDeclarationsResolveWithoutOptionalPeers = async (consumerDir: string) => { + await writeFile( + join(consumerDir, 'strict-types.ts'), + `import Wallet, { connect } from '@sei-js/sei-global-wallet'; +import { eip6963ProviderInfo, registerEIP6963Provider, unregisterEIP6963Provider } from '@sei-js/sei-global-wallet/eip6963'; +import { createEIP1193Provider } from '@sei-js/sei-global-wallet/ethereum'; + +void [Wallet, connect, eip6963ProviderInfo, registerEIP6963Provider, unregisterEIP6963Provider, createEIP1193Provider]; +` + ); + await writeJson(join(consumerDir, 'tsconfig.strict.json'), { + compilerOptions: { + lib: ['ES2022', 'DOM'], + module: 'ESNext', + moduleResolution: 'Bundler', + noEmit: true, + skipLibCheck: false, + strict: true, + target: 'ES2022' + }, + files: ['strict-types.ts'] + }); + + // Uses the workspace compiler so the minimal consumer stays free of a + // TypeScript install, which would otherwise pollute its audit surface. + const strictTypecheck = await run([join(root, 'node_modules/.bin/tsc'), '--project', 'tsconfig.strict.json'], consumerDir, true); + const output = `${strictTypecheck.stdout}${strictTypecheck.stderr}`; + // Upstream declarations are outside this package's control, so only fail on + // diagnostics raised against what this package publishes. + const ownDiagnostics = output + .split('\n') + .filter((line) => /@sei-js\/sei-global-wallet\/dist\/.*error TS/.test(line)) + .sort(); + assert.deepEqual( + ownDiagnostics, + [], + `Published declarations do not resolve without optional peers installed:\n${ownDiagnostics.join('\n')}\n\nFull output:\n${output}` + ); +}; + const setupConsumerFiles = async (consumerDir: string) => { await writeFile( join(consumerDir, 'check-ssr.mjs'), @@ -486,44 +568,78 @@ const assertAuditClean = (report: AuditReport, label: string) => { }; const assertAcceptedBunAudit = (result: ProcessResult) => { - assert.notEqual(result.exitCode, 0, 'Bun AA consumer audit unexpectedly reported a clean dependency tree'); + if (result.exitCode === 0) { + reportWaiverProgress( + 'the Bun AA consumer now audits clean: every accepted advisory was fixed upstream. Delete the waiver from packages/sei-global-wallet/README.md and acceptedBunAdvisories in this script.' + ); + return; + } + const report = parseJsonOutput>>(result.stdout); - assert.deepEqual(Object.keys(report).sort(), ['bn.js', 'ws']); - assert.equal(report['bn.js']?.length, 1); - assert.equal(report['bn.js']?.[0]?.severity, 'moderate'); - assert.equal(report['bn.js']?.[0]?.url, 'https://github.com/advisories/GHSA-378v-28hj-76wf'); - assert.equal(report.ws?.length, 2); + const serialized = JSON.stringify(report); + const reported = new Set(serialized.match(/GHSA-[a-z0-9-]+/gi) ?? []); + + // A subset check, not an exact set: the advisory database changes on its own + // schedule, so a withdrawn or upstream-fixed advisory must not fail an + // unrelated pull request, while any new exposure still must. + const unwaived = [...reported].filter((advisory) => !acceptedBunAdvisories.includes(advisory)).sort(); assert.deepEqual( - report.ws?.map(({ severity, url }) => ({ severity, url })).sort((a, b) => (a.url ?? '').localeCompare(b.url ?? '')), - [ - { - severity: 'moderate', - url: 'https://github.com/advisories/GHSA-58qx-3vcg-4xpx' - }, - { - severity: 'high', - url: 'https://github.com/advisories/GHSA-96hv-2xvq-fx4p' - } - ] + unwaived, + [], + `Bun AA consumer reported advisories outside the accepted waiver: ${unwaived.join(', ')}. Assess them and update packages/sei-global-wallet/README.md before releasing.` ); - const serialized = JSON.stringify(report); - const advisories = [...new Set(serialized.match(/GHSA-[a-z0-9-]+/gi) ?? [])].sort(); - assert.deepEqual(advisories, [...acceptedBunAdvisories].sort()); + + const fixed = acceptedBunAdvisories.filter((advisory) => !reported.has(advisory)); + if (fixed.length > 0) { + reportWaiverProgress( + `Bun no longer reports ${fixed.join(', ')}. Narrow the waiver in packages/sei-global-wallet/README.md and acceptedBunAdvisories in this script.` + ); + } + + // The documented Axios and UUID overrides must still be taking effect. assert.doesNotMatch(serialized, /axios|uuid/i); + console.log( + `Bun AA consumer advisories, all within the waiver: ${Object.entries(report) + .map(([name, findings]) => `${name} (${findings.map(({ severity }) => severity).join(', ')})`) + .join('; ')}` + ); }; const assertNpmDynamicGraph = (lock: PackageLock) => { - assert.equal(lock.packages['node_modules/@dynamic-labs/global-wallet-client']?.version, '4.96.3'); - assert.equal(lock.packages['node_modules/@dynamic-labs/ethereum-aa']?.version, '4.96.3'); + const resolved = assertSatisfiesDynamicRange(lock.packages['node_modules/@dynamic-labs/global-wallet-client']?.version, 'npm consumer'); + assert.equal(lock.packages['node_modules/@dynamic-labs/ethereum-aa']?.version, testedPeerVersions['@dynamic-labs/ethereum-aa']); + + const conflicts = findDynamicLineConflicts(lock.packages, resolved); + assert.deepEqual(conflicts, [], `npm consumer kept a stale Dynamic ${resolved} subtree: ${formatDynamicLineConflicts(conflicts)}`); - const stale = findStaleDynamicPackages(lock.packages); - assert.deepEqual(stale, [], `Unexpected stale Dynamic 4.96.1 npm resolutions: ${stale.map(([location]) => location).join(', ')}`); + return resolved; }; const assertBunDynamicGraph = (lockText: string) => { - assert.match(lockText, /"@dynamic-labs\/global-wallet-client": \["@dynamic-labs\/global-wallet-client@4\.96\.3"/); - assert.match(lockText, /"@dynamic-labs\/ethereum-aa": \["@dynamic-labs\/ethereum-aa@4\.96\.3"/); - assert.doesNotMatch(lockText, /@dynamic-labs\/[^"]+@4\.96\.1/, 'Bun lockfile retained a stale Dynamic 4.96.1 resolution'); + // Bun records every resolution as a "@" specifier rather than + // as install locations, so group the specifiers instead of lock paths. + const versions = new Map>(); + for (const [, name, version] of lockText.matchAll(/"(@dynamic-labs\/[^"@/]+)@([^"]+)"/g)) { + versions.set(name, (versions.get(name) ?? new Set()).add(version)); + } + + const walletClient = [...(versions.get('@dynamic-labs/global-wallet-client') ?? [])]; + assert.equal(walletClient.length, 1, `Bun consumer resolved multiple Dynamic clients: ${walletClient.join(', ')}`); + const resolved = assertSatisfiesDynamicRange(walletClient[0], 'Bun consumer'); + assert( + [...(versions.get('@dynamic-labs/ethereum-aa') ?? [])].includes(testedPeerVersions['@dynamic-labs/ethereum-aa']), + `Bun consumer did not resolve @dynamic-labs/ethereum-aa@${testedPeerVersions['@dynamic-labs/ethereum-aa']}` + ); + + // Same major-line invariant as the npm graph: versions outside the client's + // major belong to unrelated dependents, such as zksync-sso's Dynamic 5.x. + const line = `${resolved.split('.')[0]}.`; + const conflicts = [...versions] + .map(([name, resolved]) => [name, [...resolved].filter((version) => version.startsWith(line)).sort()] as const) + .filter(([, inLine]) => inLine.length > 1) + .map(([name, inLine]) => `${name}@{${inLine.join(', ')}}`) + .sort(); + assert.deepEqual(conflicts, [], `Bun consumer kept a stale Dynamic ${resolved} subtree: ${conflicts.join(', ')}`); }; const assertBrowserMetafile = async (metafilePath: string, lock: PackageLock) => { @@ -533,6 +649,8 @@ const assertBrowserMetafile = async (metafilePath: string, lock: PackageLock) => }; const inputs = Object.keys(metafile.inputs); assert(inputs.some((path) => path.includes('node_modules/@dynamic-labs/global-wallet-client/'))); + const clientVersion = assertSatisfiesDynamicRange(lock.packages['node_modules/@dynamic-labs/global-wallet-client']?.version, 'Browser bundle lockfile'); + const lineVersions = collectDynamicLineVersions(lock.packages, clientVersion); const resolvedDynamicInputs = new Map(); for (const path of inputs) { const normalizedPath = path.replaceAll('\\', '/'); @@ -546,10 +664,19 @@ const assertBrowserMetafile = async (metafilePath: string, lock: PackageLock) => const lockLocation = normalizedPath.slice(lockStart, packageStart + packageName.length); const version = lock.packages[lockLocation]?.version; assert(version, `Metafile input did not resolve to its nearest npm lock installation: ${path} -> ${lockLocation}`); - assert.notEqual(version, '4.96.1', `Unexpected stale Dynamic runtime in bundle: ${path} -> ${lockLocation}@${version}`); - resolvedDynamicInputs.set(lockLocation, version); + const inLine = [...(lineVersions.get(packageName) ?? [])]; + // The lock is already asserted conflict-free within the client's major + // line, so a bundled input from that line must be its single version. + if (inLine.length > 0) { + assert.deepEqual(inLine, [version], `Bundle pulled a stale Dynamic runtime: ${path} -> ${lockLocation}@${version}, expected ${inLine.join(', ')}`); + } + resolvedDynamicInputs.set(packageName, version); } - assert.equal(resolvedDynamicInputs.get('node_modules/@dynamic-labs/global-wallet-client'), '4.96.3'); + assert.equal( + resolvedDynamicInputs.get('@dynamic-labs/global-wallet-client'), + clientVersion, + 'Browser bundle did not load the Dynamic client the lockfile resolved' + ); const runtimeImports = Object.values(metafile.outputs).flatMap((output) => output.imports ?? []); assert(!runtimeImports.some(({ path }) => path === 'node:worker_threads' || path === 'worker_threads')); }; @@ -580,12 +707,18 @@ try { Object.entries(unwaivedLock.packages) .filter(([location]) => location === `node_modules/${name}` || location.endsWith(`/node_modules/${name}`)) .map(([, metadata]) => metadata.version); - assert(lockedVersions('axios').includes('1.16.0')); - assert(lockedVersions('uuid').includes('11.1.0')); const unwaivedAuditResult = await run(['npm', 'audit', '--json'], unwaivedDir, true); const unwaivedAudit = parseJsonOutput(unwaivedAuditResult.stdout); - assert(unwaivedAudit.vulnerabilities?.axios, 'Unwaived npm audit did not expose vulnerable axios'); - assert(unwaivedAudit.vulnerabilities?.uuid, 'Unwaived npm audit did not expose vulnerable uuid'); + // Reported, not asserted: an unwaived consumer going clean means Dynamic + // corrected its transitive pins, which must not read as a CI failure. + const stillVulnerable = ['axios', 'uuid'].filter((name) => unwaivedAudit.vulnerabilities?.[name]); + if (stillVulnerable.length === 0) { + reportWaiverProgress( + 'an npm consumer without overrides now audits clean: Dynamic corrected its transitive axios and uuid pins. Remove the override guidance from packages/sei-global-wallet/README.md and the changeset.' + ); + } else { + console.log(`Overrides still required for ${stillVulnerable.map((name) => `${name}@${[...new Set(lockedVersions(name))].join('/')}`).join(', ')}`); + } const waivedDir = join(temporaryRoot, 'npm-waived'); await mkdir(waivedDir); @@ -602,6 +735,7 @@ try { ); const waivedAudit = parseJsonOutput((await run(['npm', 'audit', '--json'], waivedDir)).stdout); assertAuditClean(waivedAudit, 'Waived npm consumer'); + await assertDeclarationsResolveWithoutOptionalPeers(waivedDir); } const npmConsumerDir = join(temporaryRoot, 'npm-full'); @@ -655,10 +789,13 @@ try { await assertBrowserMetafile(join(npmConsumerDir, 'edge-meta.json'), npmLock); await runEdgeBundle(join(npmConsumerDir, 'edge-esbuild.js')); const viteBuild = await run(['npx', '--no-install', 'vite', 'build'], npmConsumerDir); + // Vite routes externalization warnings through its own logger, which writes + // to stdout in most versions, so scan both streams. + const viteOutput = `${viteBuild.stdout}\n${viteBuild.stderr}`; assert.doesNotMatch( - viteBuild.stderr, + viteOutput, /(?:node:)?worker_threads.*externaliz|externaliz.*(?:node:)?worker_threads/i, - `Vite externalized worker_threads:\n${viteBuild.stderr}` + `Vite externalized worker_threads:\n${viteOutput}` ); const viteFiles = (await readdir(join(npmConsumerDir, 'vite-dist'))).filter((path) => path.endsWith('.js')); assert.equal(viteFiles.length, 1, `Expected one Vite bundle, found: ${viteFiles.join(', ')}`); diff --git a/scripts/dynamic-package-lock.test.ts b/scripts/dynamic-package-lock.test.ts index a9fec5c7b..72842b633 100644 --- a/scripts/dynamic-package-lock.test.ts +++ b/scripts/dynamic-package-lock.test.ts @@ -1,26 +1,75 @@ import { describe, expect, test } from 'bun:test'; -import { findStaleDynamicPackages, isDynamicLabsLockLocation, STALE_DYNAMIC_VERSION } from './dynamic-package-lock.js'; +import { collectDynamicLineVersions, dynamicLockPackageName, findDynamicLineConflicts, formatDynamicLineConflicts } from './dynamic-package-lock.js'; describe('dynamic package lock locations', () => { - test('matches hoisted and nested Dynamic packages', () => { - expect(isDynamicLabsLockLocation('node_modules/@dynamic-labs/logger')).toBe(true); - expect(isDynamicLabsLockLocation('node_modules/@dynamic-labs/global-wallet-client')).toBe(true); - expect(isDynamicLabsLockLocation('node_modules/foo/node_modules/@dynamic-labs/logger')).toBe(true); - expect(isDynamicLabsLockLocation('node_modules/@dynamic-labs')).toBe(false); - expect(isDynamicLabsLockLocation('node_modules/axios')).toBe(false); + test('names hoisted and nested Dynamic packages, and nothing else', () => { + expect(dynamicLockPackageName('node_modules/@dynamic-labs/logger')).toBe('@dynamic-labs/logger'); + expect(dynamicLockPackageName('node_modules/@dynamic-labs/global-wallet-client')).toBe('@dynamic-labs/global-wallet-client'); + expect(dynamicLockPackageName('node_modules/foo/node_modules/@dynamic-labs/logger')).toBe('@dynamic-labs/logger'); + expect(dynamicLockPackageName('node_modules/a/node_modules/b/node_modules/@dynamic-labs/store')).toBe('@dynamic-labs/store'); + expect(dynamicLockPackageName('node_modules/@dynamic-labs')).toBeUndefined(); + expect(dynamicLockPackageName('node_modules/axios')).toBeUndefined(); }); - test('rejects stale 4.96.1 copies at the top level and when nested', () => { - const stale = findStaleDynamicPackages({ - 'node_modules/@dynamic-labs/logger': { version: STALE_DYNAMIC_VERSION }, - 'node_modules/@dynamic-labs/global-wallet-client': { version: '4.96.3' }, - 'node_modules/viem/node_modules/@dynamic-labs/message-transport': { version: STALE_DYNAMIC_VERSION }, - 'node_modules/axios': { version: STALE_DYNAMIC_VERSION } - }); - - expect(stale.map(([location]) => location).sort()).toEqual([ - 'node_modules/@dynamic-labs/logger', - 'node_modules/viem/node_modules/@dynamic-labs/message-transport' - ]); + test('collects only the resolutions inside the requested major line', () => { + const versions = collectDynamicLineVersions( + { + 'node_modules/@dynamic-labs/logger': { version: '4.96.3' }, + 'node_modules/viem/node_modules/@dynamic-labs/logger': { version: '4.96.1' }, + // zksync-sso brings its own Dynamic 5.x line, which is not this runtime. + 'node_modules/zksync-sso/node_modules/@dynamic-labs/logger': { version: '5.3.2' }, + 'node_modules/@dynamic-labs/sdk-api-core': { version: '0.12.0' }, + 'node_modules/axios': { version: '1.18.0' } + }, + '4.96.3' + ); + + expect([...(versions.get('@dynamic-labs/logger') ?? [])].sort()).toEqual(['4.96.1', '4.96.3']); + expect(versions.has('@dynamic-labs/sdk-api-core')).toBe(false); + expect(versions.has('axios')).toBe(false); + }); + + test('reports a stale nested copy inside the line', () => { + const conflicts = findDynamicLineConflicts( + { + 'node_modules/@dynamic-labs/logger': { version: '4.96.3' }, + 'node_modules/viem/node_modules/@dynamic-labs/logger': { version: '4.96.1' }, + 'node_modules/@dynamic-labs/message-transport': { version: '4.96.3' }, + 'node_modules/foo/node_modules/@dynamic-labs/message-transport': { version: '4.96.1' }, + 'node_modules/@dynamic-labs/global-wallet-client': { version: '4.96.3' } + }, + '4.96.3' + ); + + expect(conflicts.map(([name]) => name)).toEqual(['@dynamic-labs/logger', '@dynamic-labs/message-transport']); + expect(formatDynamicLineConflicts(conflicts)).toBe('@dynamic-labs/logger@{4.96.1, 4.96.3}, @dynamic-labs/message-transport@{4.96.1, 4.96.3}'); + }); + + test('accepts unrelated major lines and independently versioned Dynamic packages', () => { + expect( + findDynamicLineConflicts( + { + 'node_modules/@dynamic-labs/global-wallet-client': { version: '4.96.3' }, + 'node_modules/@dynamic-labs/logger': { version: '4.96.3' }, + 'node_modules/zksync-sso/node_modules/@dynamic-labs/logger': { version: '5.3.2' }, + 'node_modules/@dynamic-labs/sdk-api-core': { version: '0.0.1093' }, + 'node_modules/foo/node_modules/@dynamic-labs/sdk-api-core': { version: '0.12.0' } + }, + '4.96.3' + ) + ).toEqual([]); + }); + + test('stays meaningful after a Dynamic major upgrade', () => { + const packages = { + 'node_modules/@dynamic-labs/global-wallet-client': { version: '5.4.0' }, + 'node_modules/@dynamic-labs/logger': { version: '5.4.0' }, + 'node_modules/foo/node_modules/@dynamic-labs/logger': { version: '5.3.2' } + }; + + expect(findDynamicLineConflicts(packages, '5.4.0').map(([name]) => name)).toEqual(['@dynamic-labs/logger']); + // The same graph read against the old line reports nothing, because 5.x is + // no longer the runtime being checked. + expect(findDynamicLineConflicts(packages, '4.96.3')).toEqual([]); }); }); diff --git a/scripts/dynamic-package-lock.ts b/scripts/dynamic-package-lock.ts index 6c446945d..4b9df8123 100644 --- a/scripts/dynamic-package-lock.ts +++ b/scripts/dynamic-package-lock.ts @@ -1,8 +1,41 @@ -export const STALE_DYNAMIC_VERSION = '4.96.1'; +const DYNAMIC_PACKAGE_LOCATION = /(?:^|\/)node_modules\/(@dynamic-labs\/[^/]+)$/; -const DYNAMIC_PACKAGE_LOCATION = /(?:^|\/)node_modules\/@dynamic-labs\//; +/** Returns the `@dynamic-labs/*` package a lock location installs, at any nesting depth. */ +export const dynamicLockPackageName = (location: string) => location.match(DYNAMIC_PACKAGE_LOCATION)?.[1]; -export const isDynamicLabsLockLocation = (location: string) => DYNAMIC_PACKAGE_LOCATION.test(location); +const majorOf = (version: string) => version.split('.')[0]; -export const findStaleDynamicPackages = (packages: Record, staleVersion = STALE_DYNAMIC_VERSION) => - Object.entries(packages).filter(([location, metadata]) => isDynamicLabsLockLocation(location) && metadata.version === staleVersion); +/** + * Maps every `@dynamic-labs/*` package that resolved within one major line to + * the versions it resolved to. Other majors are excluded because they belong to + * unrelated dependents — `zksync-sso` ships its own Dynamic 5.x line — and are + * not the runtime this package loads. + */ +export const collectDynamicLineVersions = (packages: Record, lineVersion: string) => { + const line = majorOf(lineVersion); + const versions = new Map>(); + + for (const [location, metadata] of Object.entries(packages)) { + const name = dynamicLockPackageName(location); + if (!name || !metadata.version || majorOf(metadata.version) !== line) continue; + + versions.set(name, (versions.get(name) ?? new Set()).add(metadata.version)); + } + + return versions; +}; + +/** + * Dynamic pins its internal packages to the client's exact version, so any name + * resolving to two versions inside that line means a stale nested subtree + * survived. Checking for disagreement rather than for a known-bad version keeps + * this meaningful across Dynamic upgrades. + */ +export const findDynamicLineConflicts = (packages: Record, lineVersion: string) => + [...collectDynamicLineVersions(packages, lineVersion)] + .filter(([, versions]) => versions.size > 1) + .map(([name, versions]) => [name, [...versions].sort()] as const) + .sort(([left], [right]) => left.localeCompare(right)); + +export const formatDynamicLineConflicts = (conflicts: ReturnType) => + conflicts.map(([name, versions]) => `${name}@{${versions.join(', ')}}`).join(', '); From c0db1d9198e404c7f022f6f48bb123c252494ac3 Mon Sep 17 00:00:00 2001 From: alexander-sei Date: Sun, 23 Aug 2026 13:29:57 +0200 Subject: [PATCH 4/4] fix(mcp-server): stop CI typecheck OOM from a split zod tree Dynamic's lockfile refresh nested zod 4 under the MCP SDK while mcp-server stayed on zod 3, so tsc compared two recursive schema graphs until the runner's 4GB heap died. Co-authored-by: Cursor --- .changeset/align-mcp-zod.md | 5 ++++ bun.lock | 10 ++----- packages/mcp-server/package.json | 2 +- scripts/mcp-zod-lock.test.ts | 47 ++++++++++++++++++++++++++++++++ scripts/mcp-zod-lock.ts | 31 +++++++++++++++++++++ 5 files changed, 86 insertions(+), 9 deletions(-) create mode 100644 .changeset/align-mcp-zod.md create mode 100644 scripts/mcp-zod-lock.test.ts create mode 100644 scripts/mcp-zod-lock.ts diff --git a/.changeset/align-mcp-zod.md b/.changeset/align-mcp-zod.md new file mode 100644 index 000000000..92e04a84c --- /dev/null +++ b/.changeset/align-mcp-zod.md @@ -0,0 +1,5 @@ +--- +'@sei-js/mcp-server': patch +--- + +Align `zod` with `@modelcontextprotocol/sdk` so both resolve the same schema types. diff --git a/bun.lock b/bun.lock index 58cf19f59..a79e83c6a 100644 --- a/bun.lock +++ b/bun.lock @@ -42,7 +42,7 @@ "dotenv": "^16.5.0", "express": "^4.21.2", "viem": "2.55.16", - "zod": "^3.24.2", + "zod": "^4.0.5", }, "devDependencies": { "@types/cors": "^2.8.17", @@ -1187,7 +1187,7 @@ "zksync-sso": ["zksync-sso@0.2.0", "", { "dependencies": { "@peculiar/asn1-ecc": "^2.3.13", "@peculiar/asn1-schema": "^2.3.13", "abitype": "^1.0.6", "bigint-conversion": "^2.4.3", "buffer": "^6.0.3", "ms": "^2.1.3" }, "peerDependencies": { "@simplewebauthn/browser": "13.x", "@simplewebauthn/server": "13.x", "@wagmi/core": "2.x", "typescript": "*" }, "optionalPeers": ["typescript"] }, "sha512-JyxmYx2KnreTEQANyihkhzQGqA0Opa0j1qT6BLBmjP8WOwsYEiOMolbwxNK7X/KETXI77IZhGxWl8ZMKQgYl8A=="], - "zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + "zod": ["zod@4.0.5", "", {}, "sha512-/5UuuRPStvHXu7RS+gmvRf4NXrNxpSllGwDnCBcJZtQsKrviYXm54yDGV2KYNLT5kq0lHGcl7lqWJLgSaG+tgA=="], "zod-to-json-schema": ["zod-to-json-schema@3.25.2", "", { "peerDependencies": { "zod": "^3.25.28 || ^4" } }, "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA=="], @@ -1201,8 +1201,6 @@ "@dynamic-labs-sdk/client/@dynamic-labs/sdk-api-core": ["@dynamic-labs/sdk-api-core@0.0.1125", "", {}, "sha512-DZiEWOJD9ibwJRknhp3sed2YALaE7d8DGyM0zXIaFNzQ0GpYABDlXSLRCAFnYOof1yK7qMsOlYq9C5WD5tf7Hg=="], - "@dynamic-labs-sdk/client/zod": ["zod@4.0.5", "", {}, "sha512-/5UuuRPStvHXu7RS+gmvRf4NXrNxpSllGwDnCBcJZtQsKrviYXm54yDGV2KYNLT5kq0lHGcl7lqWJLgSaG+tgA=="], - "@dynamic-labs-wallet/core/@dynamic-labs-wallet/primitives": ["@dynamic-labs-wallet/primitives@1.0.92", "", {}, "sha512-/v2ZNA4rxoMf9hoo2CVzTG9BceS/UVfkKPNmXUqsjqEkl/KQAA0p0fTCeba8FGLjUtub/U1UmmU9SpNlCU8/+Q=="], "@dynamic-labs-wallet/core/@dynamic-labs/sdk-api-core": ["@dynamic-labs/sdk-api-core@0.0.1093", "", {}, "sha512-NdtIGe5XlgY4ohvy//RHjokUiMJ/1BHA+IV12awIDwPfeR9+dp0gMKurlTIbnOqn0P95pbUQKdpbtxZmtCWDRw=="], @@ -1213,8 +1211,6 @@ "@dynamic-labs-wallet/forward-mpc-shared/@noble/hashes": ["@noble/hashes@2.3.0", "", {}, "sha512-oN+QwyX7VSHotibwubG3kpzbwKrfnyR6OOO+3Nk/53ADL7FmgHHz4TgrbaYKvvOw09u6QTx0oiH1cNCIOuN0CQ=="], - "@dynamic-labs/wallet-book/zod": ["zod@4.0.5", "", {}, "sha512-/5UuuRPStvHXu7RS+gmvRf4NXrNxpSllGwDnCBcJZtQsKrviYXm54yDGV2KYNLT5kq0lHGcl7lqWJLgSaG+tgA=="], - "@emnapi/runtime/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], "@manypkg/find-root/@types/node": ["@types/node@12.20.55", "", {}, "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ=="], @@ -1227,8 +1223,6 @@ "@modelcontextprotocol/sdk/express": ["express@5.2.1", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.1", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "depd": "^2.0.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw=="], - "@modelcontextprotocol/sdk/zod": ["zod@4.0.5", "", {}, "sha512-/5UuuRPStvHXu7RS+gmvRf4NXrNxpSllGwDnCBcJZtQsKrviYXm54yDGV2KYNLT5kq0lHGcl7lqWJLgSaG+tgA=="], - "@noble/post-quantum/@noble/curves": ["@noble/curves@2.0.1", "", { "dependencies": { "@noble/hashes": "2.0.1" } }, "sha512-vs1Az2OOTBiP4q0pwjW5aF0xp9n4MxVrmkFBxc6EKZc6ddYx5gaZiAsZoq0uRRXWbi3AT/sBqn05eRPtn1JCPw=="], "@noble/post-quantum/@noble/hashes": ["@noble/hashes@2.0.1", "", {}, "sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw=="], diff --git a/packages/mcp-server/package.json b/packages/mcp-server/package.json index d3846b3f7..34d2569bb 100644 --- a/packages/mcp-server/package.json +++ b/packages/mcp-server/package.json @@ -40,7 +40,7 @@ "dotenv": "^16.5.0", "express": "^4.21.2", "viem": "2.55.16", - "zod": "^3.24.2" + "zod": "^4.0.5" }, "keywords": [ "mcp", diff --git a/scripts/mcp-zod-lock.test.ts b/scripts/mcp-zod-lock.test.ts new file mode 100644 index 000000000..d87ba2729 --- /dev/null +++ b/scripts/mcp-zod-lock.test.ts @@ -0,0 +1,47 @@ +import { describe, expect, test } from 'bun:test'; +import { readFileSync } from 'node:fs'; +import { join } from 'node:path'; +import { type ParseError, parse } from 'jsonc-parser'; +import { bunLockResolvedVersion, findMcpSdkZodSplit, formatMcpSdkZodSplit } from './mcp-zod-lock.js'; + +describe('mcp sdk zod lock', () => { + test('reads versions from bun.lock package tuples', () => { + expect(bunLockResolvedVersion(['zod@3.25.76', '', {}, 'sha'])).toBe('3.25.76'); + expect(bunLockResolvedVersion(['@modelcontextprotocol/sdk@1.30.0', '', {}, 'sha'])).toBe('1.30.0'); + expect(bunLockResolvedVersion({ version: '4.0.5' })).toBeUndefined(); + }); + + test('reports when the MCP SDK nested a different zod than the workspace', () => { + const split = findMcpSdkZodSplit({ + zod: ['zod@3.25.76', '', {}, 'sha'], + '@modelcontextprotocol/sdk/zod': ['zod@4.0.5', '', {}, 'sha'] + }); + + expect(split).toEqual({ hoisted: '3.25.76', nested: '4.0.5' }); + expect(formatMcpSdkZodSplit(split!)).toBe('@modelcontextprotocol/sdk resolved zod@4.0.5 while the workspace hoisted zod@3.25.76'); + }); + + test('accepts a shared resolution, including an exact nested pin of the same version', () => { + expect( + findMcpSdkZodSplit({ + zod: ['zod@4.0.5', '', {}, 'sha'] + }) + ).toBeUndefined(); + expect( + findMcpSdkZodSplit({ + zod: ['zod@4.0.5', '', {}, 'sha'], + '@modelcontextprotocol/sdk/zod': ['zod@4.0.5', '', {}, 'sha'] + }) + ).toBeUndefined(); + }); + + test('the repo lockfile keeps the MCP SDK on the same zod as mcp-server', () => { + const parseErrors: ParseError[] = []; + const lockfile = parse(readFileSync(join(import.meta.dir, '..', 'bun.lock'), 'utf8'), parseErrors, { + allowTrailingComma: true + }) as { packages?: Record }; + + expect(parseErrors).toEqual([]); + expect(findMcpSdkZodSplit(lockfile.packages ?? {})).toBeUndefined(); + }); +}); diff --git a/scripts/mcp-zod-lock.ts b/scripts/mcp-zod-lock.ts new file mode 100644 index 000000000..dc817deea --- /dev/null +++ b/scripts/mcp-zod-lock.ts @@ -0,0 +1,31 @@ +export const HOISTED_ZOD_LOCK_KEY = 'zod'; +export const MCP_SDK_ZOD_LOCK_KEY = '@modelcontextprotocol/sdk/zod'; + +/** Reads `name@version` from a bun.lock package tuple. */ +export const bunLockResolvedVersion = (entry: unknown): string | undefined => { + if (!Array.isArray(entry) || typeof entry[0] !== 'string') return undefined; + const specifier = entry[0]; + const at = specifier.lastIndexOf('@'); + if (at <= 0) return undefined; + return specifier.slice(at + 1); +}; + +/** + * The MCP SDK accepts zod 3 or 4. If it resolves a different copy than the + * hoisted workspace `zod`, `server.tool` / `server.prompt` compare two + * incompatible recursive schema trees and `tsc` OOMs. + */ +export const findMcpSdkZodSplit = (packages: Record) => { + const hoisted = bunLockResolvedVersion(packages[HOISTED_ZOD_LOCK_KEY]); + const nested = bunLockResolvedVersion(packages[MCP_SDK_ZOD_LOCK_KEY]); + if (!hoisted) { + throw new Error('bun.lock is missing a hoisted zod resolution'); + } + if (nested && nested !== hoisted) { + return { hoisted, nested }; + } + return undefined; +}; + +export const formatMcpSdkZodSplit = (split: { hoisted: string; nested: string }) => + `@modelcontextprotocol/sdk resolved zod@${split.nested} while the workspace hoisted zod@${split.hoisted}`;