@hsuite/native-connect-angular 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +48 -0
- package/USAGE_EXAMPLES.md +476 -0
- package/assets/wallets/extension.svg +7 -0
- package/assets/wallets/hashpack.svg +6 -0
- package/assets/wallets/hsuite.svg +11 -0
- package/assets/wallets/kabila.svg +11 -0
- package/assets/wallets/walletconnect.svg +13 -0
- package/coverage/base.css +224 -0
- package/coverage/block-navigation.js +87 -0
- package/coverage/coverage-summary.json +50 -0
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +476 -0
- package/coverage/lcov-report/base.css +224 -0
- package/coverage/lcov-report/block-navigation.js +87 -0
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +476 -0
- package/coverage/lcov-report/lib/components/account-selector/account-actions/account-actions.component.ts.html +868 -0
- package/coverage/lcov-report/lib/components/account-selector/account-actions/index.html +116 -0
- package/coverage/lcov-report/lib/components/account-selector/account-filter/account-filter.component.ts.html +1288 -0
- package/coverage/lcov-report/lib/components/account-selector/account-filter/index.html +116 -0
- package/coverage/lcov-report/lib/components/account-selector/account-formatting.service.ts.html +685 -0
- package/coverage/lcov-report/lib/components/account-selector/account-grouping.service.ts.html +766 -0
- package/coverage/lcov-report/lib/components/account-selector/account-list/account-list.component.ts.html +1495 -0
- package/coverage/lcov-report/lib/components/account-selector/account-list/index.html +116 -0
- package/coverage/lcov-report/lib/components/account-selector/account-selector.component.ts.html +1495 -0
- package/coverage/lcov-report/lib/components/account-selector/account-selector.service.ts.html +1588 -0
- package/coverage/lcov-report/lib/components/account-selector/index.html +161 -0
- package/coverage/lcov-report/lib/components/wallet-account-display/index.html +116 -0
- package/coverage/lcov-report/lib/components/wallet-account-display/wallet-account-display.component.ts.html +505 -0
- package/coverage/lcov-report/lib/components/wallet-connect-button/index.html +116 -0
- package/coverage/lcov-report/lib/components/wallet-connect-button/wallet-connect-button.component.ts.html +805 -0
- package/coverage/lcov-report/lib/components/wallet-connect-prompt/index.html +116 -0
- package/coverage/lcov-report/lib/components/wallet-connect-prompt/wallet-connect-prompt.component.ts.html +409 -0
- package/coverage/lcov-report/lib/components/wallet-connected-guard/index.html +116 -0
- package/coverage/lcov-report/lib/components/wallet-connected-guard/wallet-connected-guard.component.ts.html +304 -0
- package/coverage/lcov-report/lib/components/wallet-connection-modal/connection-method-step/connection-method-step.component.ts.html +436 -0
- package/coverage/lcov-report/lib/components/wallet-connection-modal/connection-method-step/index.html +116 -0
- package/coverage/lcov-report/lib/components/wallet-connection-modal/index.html +116 -0
- package/coverage/lcov-report/lib/components/wallet-connection-modal/qr-pairing-step/index.html +116 -0
- package/coverage/lcov-report/lib/components/wallet-connection-modal/qr-pairing-step/qr-pairing-step.component.ts.html +2287 -0
- package/coverage/lcov-report/lib/components/wallet-connection-modal/wallet-connection-modal.component.ts.html +2275 -0
- package/coverage/lcov-report/lib/components/wallet-session-display/index.html +116 -0
- package/coverage/lcov-report/lib/components/wallet-session-display/wallet-session-display.component.ts.html +676 -0
- package/coverage/lcov-report/lib/components/wallet-transaction-status/index.html +116 -0
- package/coverage/lcov-report/lib/components/wallet-transaction-status/wallet-transaction-status.component.ts.html +703 -0
- package/coverage/lcov-report/lib/directives/index.html +146 -0
- package/coverage/lcov-report/lib/directives/wallet-connected.directive.ts.html +670 -0
- package/coverage/lcov-report/lib/directives/wallet-context.directive.ts.html +547 -0
- package/coverage/lcov-report/lib/directives/wallet-events.directive.ts.html +781 -0
- package/coverage/lcov-report/lib/hsuite-wallet.module.ts.html +715 -0
- package/coverage/lcov-report/lib/index.html +116 -0
- package/coverage/lcov-report/lib/models/connection-config.model.ts.html +280 -0
- package/coverage/lcov-report/lib/models/index.html +131 -0
- package/coverage/lcov-report/lib/models/provider-types.ts.html +577 -0
- package/coverage/lcov-report/lib/providers/base-wallet-provider.ts.html +1138 -0
- package/coverage/lcov-report/lib/providers/hsuite-native/channel-client.service.ts.html +2671 -0
- package/coverage/lcov-report/lib/providers/hsuite-native/index.html +116 -0
- package/coverage/lcov-report/lib/providers/hsuite-native-provider.ts.html +2347 -0
- package/coverage/lcov-report/lib/providers/index.html +146 -0
- package/coverage/lcov-report/lib/providers/p2p-native/index.html +131 -0
- package/coverage/lcov-report/lib/providers/p2p-native/p2p-native.provider.ts.html +2254 -0
- package/coverage/lcov-report/lib/providers/p2p-native/p2p-session-manager.ts.html +2170 -0
- package/coverage/lcov-report/lib/providers/wallet-error-handler.ts.html +1132 -0
- package/coverage/lcov-report/lib/providers/walletconnect/core/index.html +176 -0
- package/coverage/lcov-report/lib/providers/walletconnect/core/session-health.ts.html +673 -0
- package/coverage/lcov-report/lib/providers/walletconnect/core/walletconnect-client-manager.ts.html +1177 -0
- package/coverage/lcov-report/lib/providers/walletconnect/core/walletconnect-provider.ts.html +2563 -0
- package/coverage/lcov-report/lib/providers/walletconnect/core/walletconnect-session-store.ts.html +904 -0
- package/coverage/lcov-report/lib/providers/walletconnect/core/walletconnect-signing-orchestrator.ts.html +982 -0
- package/coverage/lcov-report/lib/providers/walletconnect/signers/hedera-signer.ts.html +1915 -0
- package/coverage/lcov-report/lib/providers/walletconnect/signers/index.html +146 -0
- package/coverage/lcov-report/lib/providers/walletconnect/signers/signer-factory.ts.html +445 -0
- package/coverage/lcov-report/lib/providers/walletconnect/signers/xrpl-signer.ts.html +1519 -0
- package/coverage/lcov-report/lib/services/index.html +191 -0
- package/coverage/lcov-report/lib/services/logger.service.ts.html +463 -0
- package/coverage/lcov-report/lib/services/transaction-builders/base-transaction-builder.service.ts.html +1840 -0
- package/coverage/lcov-report/lib/services/transaction-builders/hedera-amount-utils.ts.html +337 -0
- package/coverage/lcov-report/lib/services/transaction-builders/hedera-transaction-builder.service.ts.html +3940 -0
- package/coverage/lcov-report/lib/services/transaction-builders/index.html +161 -0
- package/coverage/lcov-report/lib/services/transaction-builders/xrpl-transaction-builder.service.ts.html +2581 -0
- package/coverage/lcov-report/lib/services/transaction.service.ts.html +1123 -0
- package/coverage/lcov-report/lib/services/unified-wallet.service.ts.html +2641 -0
- package/coverage/lcov-report/lib/services/wallet-context.service.ts.html +637 -0
- package/coverage/lcov-report/lib/services/wallet-event-bus.service.ts.html +643 -0
- package/coverage/lcov-report/lib/services/wallet-providers.service.ts.html +496 -0
- package/coverage/lcov-report/lib/transports/chrome-extension-transport.ts.html +823 -0
- package/coverage/lcov-report/lib/transports/index.html +116 -0
- package/coverage/lcov-report/lib/utils/index.html +116 -0
- package/coverage/lcov-report/lib/utils/ledger-icons.util.ts.html +319 -0
- package/coverage/lcov-report/prettify.css +1 -0
- package/coverage/lcov-report/prettify.js +2 -0
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +210 -0
- package/coverage/lcov.info +19252 -0
- package/coverage/lib/components/account-selector/account-actions/account-actions.component.ts.html +868 -0
- package/coverage/lib/components/account-selector/account-actions/index.html +116 -0
- package/coverage/lib/components/account-selector/account-filter/account-filter.component.ts.html +1288 -0
- package/coverage/lib/components/account-selector/account-filter/index.html +116 -0
- package/coverage/lib/components/account-selector/account-formatting.service.ts.html +685 -0
- package/coverage/lib/components/account-selector/account-grouping.service.ts.html +766 -0
- package/coverage/lib/components/account-selector/account-list/account-list.component.ts.html +1495 -0
- package/coverage/lib/components/account-selector/account-list/index.html +116 -0
- package/coverage/lib/components/account-selector/account-selector.component.ts.html +1495 -0
- package/coverage/lib/components/account-selector/account-selector.service.ts.html +1588 -0
- package/coverage/lib/components/account-selector/index.html +161 -0
- package/coverage/lib/components/wallet-account-display/index.html +116 -0
- package/coverage/lib/components/wallet-account-display/wallet-account-display.component.ts.html +505 -0
- package/coverage/lib/components/wallet-connect-button/index.html +116 -0
- package/coverage/lib/components/wallet-connect-button/wallet-connect-button.component.ts.html +805 -0
- package/coverage/lib/components/wallet-connect-prompt/index.html +116 -0
- package/coverage/lib/components/wallet-connect-prompt/wallet-connect-prompt.component.ts.html +409 -0
- package/coverage/lib/components/wallet-connected-guard/index.html +116 -0
- package/coverage/lib/components/wallet-connected-guard/wallet-connected-guard.component.ts.html +304 -0
- package/coverage/lib/components/wallet-connection-modal/connection-method-step/connection-method-step.component.ts.html +436 -0
- package/coverage/lib/components/wallet-connection-modal/connection-method-step/index.html +116 -0
- package/coverage/lib/components/wallet-connection-modal/index.html +116 -0
- package/coverage/lib/components/wallet-connection-modal/qr-pairing-step/index.html +116 -0
- package/coverage/lib/components/wallet-connection-modal/qr-pairing-step/qr-pairing-step.component.ts.html +2287 -0
- package/coverage/lib/components/wallet-connection-modal/wallet-connection-modal.component.ts.html +2275 -0
- package/coverage/lib/components/wallet-session-display/index.html +116 -0
- package/coverage/lib/components/wallet-session-display/wallet-session-display.component.ts.html +676 -0
- package/coverage/lib/components/wallet-transaction-status/index.html +116 -0
- package/coverage/lib/components/wallet-transaction-status/wallet-transaction-status.component.ts.html +703 -0
- package/coverage/lib/directives/index.html +146 -0
- package/coverage/lib/directives/wallet-connected.directive.ts.html +670 -0
- package/coverage/lib/directives/wallet-context.directive.ts.html +547 -0
- package/coverage/lib/directives/wallet-events.directive.ts.html +781 -0
- package/coverage/lib/hsuite-wallet.module.ts.html +715 -0
- package/coverage/lib/index.html +116 -0
- package/coverage/lib/models/connection-config.model.ts.html +280 -0
- package/coverage/lib/models/index.html +131 -0
- package/coverage/lib/models/provider-types.ts.html +577 -0
- package/coverage/lib/providers/base-wallet-provider.ts.html +1138 -0
- package/coverage/lib/providers/hsuite-native/channel-client.service.ts.html +2671 -0
- package/coverage/lib/providers/hsuite-native/index.html +116 -0
- package/coverage/lib/providers/hsuite-native-provider.ts.html +2347 -0
- package/coverage/lib/providers/index.html +146 -0
- package/coverage/lib/providers/p2p-native/index.html +131 -0
- package/coverage/lib/providers/p2p-native/p2p-native.provider.ts.html +2254 -0
- package/coverage/lib/providers/p2p-native/p2p-session-manager.ts.html +2170 -0
- package/coverage/lib/providers/wallet-error-handler.ts.html +1132 -0
- package/coverage/lib/providers/walletconnect/core/index.html +176 -0
- package/coverage/lib/providers/walletconnect/core/session-health.ts.html +673 -0
- package/coverage/lib/providers/walletconnect/core/walletconnect-client-manager.ts.html +1177 -0
- package/coverage/lib/providers/walletconnect/core/walletconnect-provider.ts.html +2563 -0
- package/coverage/lib/providers/walletconnect/core/walletconnect-session-store.ts.html +904 -0
- package/coverage/lib/providers/walletconnect/core/walletconnect-signing-orchestrator.ts.html +982 -0
- package/coverage/lib/providers/walletconnect/signers/hedera-signer.ts.html +1915 -0
- package/coverage/lib/providers/walletconnect/signers/index.html +146 -0
- package/coverage/lib/providers/walletconnect/signers/signer-factory.ts.html +445 -0
- package/coverage/lib/providers/walletconnect/signers/xrpl-signer.ts.html +1519 -0
- package/coverage/lib/services/index.html +191 -0
- package/coverage/lib/services/logger.service.ts.html +463 -0
- package/coverage/lib/services/transaction-builders/base-transaction-builder.service.ts.html +1840 -0
- package/coverage/lib/services/transaction-builders/hedera-amount-utils.ts.html +337 -0
- package/coverage/lib/services/transaction-builders/hedera-transaction-builder.service.ts.html +3940 -0
- package/coverage/lib/services/transaction-builders/index.html +161 -0
- package/coverage/lib/services/transaction-builders/xrpl-transaction-builder.service.ts.html +2581 -0
- package/coverage/lib/services/transaction.service.ts.html +1123 -0
- package/coverage/lib/services/unified-wallet.service.ts.html +2641 -0
- package/coverage/lib/services/wallet-context.service.ts.html +637 -0
- package/coverage/lib/services/wallet-event-bus.service.ts.html +643 -0
- package/coverage/lib/services/wallet-providers.service.ts.html +496 -0
- package/coverage/lib/transports/chrome-extension-transport.ts.html +823 -0
- package/coverage/lib/transports/index.html +116 -0
- package/coverage/lib/utils/index.html +116 -0
- package/coverage/lib/utils/ledger-icons.util.ts.html +319 -0
- package/coverage/prettify.css +1 -0
- package/coverage/prettify.js +2 -0
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +210 -0
- package/dist/README.md +48 -0
- package/dist/fesm2022/hsuite-native-connect-angular.mjs +14592 -0
- package/dist/fesm2022/hsuite-native-connect-angular.mjs.map +1 -0
- package/dist/index.d.ts +6949 -0
- package/examples/minimal-connect.ts +178 -0
- package/examples/multi-protocol.ts +495 -0
- package/examples/transaction-signing.ts +361 -0
- package/jest.config.json +45 -0
- package/karma.conf.js +42 -0
- package/ng-package.json +20 -0
- package/package.json +60 -0
- package/src/index.ts +203 -0
- package/src/lib/components/account-selector/account-actions/account-actions.component.ts +261 -0
- package/src/lib/components/account-selector/account-filter/account-filter.component.ts +401 -0
- package/src/lib/components/account-selector/account-formatting.service.ts +200 -0
- package/src/lib/components/account-selector/account-grouping.service.ts +227 -0
- package/src/lib/components/account-selector/account-list/account-list.component.ts +470 -0
- package/src/lib/components/account-selector/account-selector.component.html +135 -0
- package/src/lib/components/account-selector/account-selector.component.scss +2039 -0
- package/src/lib/components/account-selector/account-selector.component.ts +470 -0
- package/src/lib/components/account-selector/account-selector.service.ts +501 -0
- package/src/lib/components/wallet-account-display/wallet-account-display.component.html +34 -0
- package/src/lib/components/wallet-account-display/wallet-account-display.component.scss +99 -0
- package/src/lib/components/wallet-account-display/wallet-account-display.component.ts +140 -0
- package/src/lib/components/wallet-connect-button/wallet-connect-button.component.html +14 -0
- package/src/lib/components/wallet-connect-button/wallet-connect-button.component.scss +272 -0
- package/src/lib/components/wallet-connect-button/wallet-connect-button.component.ts +240 -0
- package/src/lib/components/wallet-connect-prompt/wallet-connect-prompt.component.html +24 -0
- package/src/lib/components/wallet-connect-prompt/wallet-connect-prompt.component.scss +50 -0
- package/src/lib/components/wallet-connect-prompt/wallet-connect-prompt.component.ts +108 -0
- package/src/lib/components/wallet-connected-guard/wallet-connected-guard.component.html +24 -0
- package/src/lib/components/wallet-connected-guard/wallet-connected-guard.component.ts +73 -0
- package/src/lib/components/wallet-connection-modal/connection-method-step/connection-method-step.component.html +56 -0
- package/src/lib/components/wallet-connection-modal/connection-method-step/connection-method-step.component.scss +218 -0
- package/src/lib/components/wallet-connection-modal/connection-method-step/connection-method-step.component.ts +117 -0
- package/src/lib/components/wallet-connection-modal/qr-pairing-step/qr-pairing-step.component.html +94 -0
- package/src/lib/components/wallet-connection-modal/qr-pairing-step/qr-pairing-step.component.scss +272 -0
- package/src/lib/components/wallet-connection-modal/qr-pairing-step/qr-pairing-step.component.ts +734 -0
- package/src/lib/components/wallet-connection-modal/wallet-connection-modal.component.html +197 -0
- package/src/lib/components/wallet-connection-modal/wallet-connection-modal.component.scss +678 -0
- package/src/lib/components/wallet-connection-modal/wallet-connection-modal.component.ts +730 -0
- package/src/lib/components/wallet-session-display/wallet-session-display.component.html +110 -0
- package/src/lib/components/wallet-session-display/wallet-session-display.component.scss +179 -0
- package/src/lib/components/wallet-session-display/wallet-session-display.component.ts +197 -0
- package/src/lib/components/wallet-transaction-status/wallet-transaction-status.component.html +65 -0
- package/src/lib/components/wallet-transaction-status/wallet-transaction-status.component.scss +254 -0
- package/src/lib/components/wallet-transaction-status/wallet-transaction-status.component.ts +206 -0
- package/src/lib/directives/wallet-connected.directive.ts +195 -0
- package/src/lib/directives/wallet-context.directive.ts +154 -0
- package/src/lib/directives/wallet-events.directive.ts +232 -0
- package/src/lib/hsuite-wallet.module.ts +210 -0
- package/src/lib/models/connection-config.model.ts +65 -0
- package/src/lib/models/provider-types.ts +164 -0
- package/src/lib/models/unified-account.model.ts +76 -0
- package/src/lib/models/wallet-context.model.ts +121 -0
- package/src/lib/models/wallet-events.model.ts +158 -0
- package/src/lib/providers/base-wallet-provider.ts +351 -0
- package/src/lib/providers/hsuite-native/channel-client.service.spec.ts +73 -0
- package/src/lib/providers/hsuite-native/channel-client.service.ts +862 -0
- package/src/lib/providers/hsuite-native/index.ts +8 -0
- package/src/lib/providers/hsuite-native-provider.ts +754 -0
- package/src/lib/providers/mobile-native/mobile-native.provider.spec.ts +19 -0
- package/src/lib/providers/p2p-native/index.ts +30 -0
- package/src/lib/providers/p2p-native/p2p-native.provider.spec.ts +523 -0
- package/src/lib/providers/p2p-native/p2p-native.provider.ts +723 -0
- package/src/lib/providers/p2p-native/p2p-session-manager.ts +695 -0
- package/src/lib/providers/wallet-error-handler.ts +349 -0
- package/src/lib/providers/walletconnect/core/base-signer.interface.ts +122 -0
- package/src/lib/providers/walletconnect/core/session-health.ts +196 -0
- package/src/lib/providers/walletconnect/core/walletconnect-client-manager.ts +364 -0
- package/src/lib/providers/walletconnect/core/walletconnect-provider.integration.spec.ts +348 -0
- package/src/lib/providers/walletconnect/core/walletconnect-provider.ts +826 -0
- package/src/lib/providers/walletconnect/core/walletconnect-session-store.ts +273 -0
- package/src/lib/providers/walletconnect/core/walletconnect-signing-orchestrator.ts +299 -0
- package/src/lib/providers/walletconnect/core/walletconnect-types.ts +48 -0
- package/src/lib/providers/walletconnect/index.ts +33 -0
- package/src/lib/providers/walletconnect/signers/hedera-signer.spec.ts +367 -0
- package/src/lib/providers/walletconnect/signers/hedera-signer.ts +610 -0
- package/src/lib/providers/walletconnect/signers/signer-factory.spec.ts +62 -0
- package/src/lib/providers/walletconnect/signers/signer-factory.ts +120 -0
- package/src/lib/providers/walletconnect/signers/xrpl-signer.spec.ts +296 -0
- package/src/lib/providers/walletconnect/signers/xrpl-signer.ts +478 -0
- package/src/lib/services/logger.service.ts +126 -0
- package/src/lib/services/transaction-builders/base-transaction-builder.service.ts +585 -0
- package/src/lib/services/transaction-builders/hedera-amount-utils.ts +84 -0
- package/src/lib/services/transaction-builders/hedera-transaction-builder.service.spec.ts +741 -0
- package/src/lib/services/transaction-builders/hedera-transaction-builder.service.ts +1285 -0
- package/src/lib/services/transaction-builders/index.ts +54 -0
- package/src/lib/services/transaction-builders/xrpl-transaction-builder.service.spec.ts +937 -0
- package/src/lib/services/transaction-builders/xrpl-transaction-builder.service.ts +832 -0
- package/src/lib/services/transaction.service.ts +346 -0
- package/src/lib/services/unified-wallet.service.spec.ts +1382 -0
- package/src/lib/services/unified-wallet.service.ts +852 -0
- package/src/lib/services/wallet-context.service.ts +184 -0
- package/src/lib/services/wallet-event-bus.service.ts +186 -0
- package/src/lib/services/wallet-providers.service.ts +137 -0
- package/src/lib/transports/chrome-extension-transport.ts +246 -0
- package/src/lib/utils/index.ts +14 -0
- package/src/lib/utils/ledger-icons.util.ts +78 -0
- package/test/test-setup.ts +21 -0
- package/test-setup.ts +63 -0
- package/tsconfig.build.json +11 -0
- package/tsconfig.json +29 -0
- package/tsconfig.spec.json +15 -0
- package/vitest.config.ts +48 -0
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HSuite Native Connect
|
|
3
|
+
* Copyright 2024-2025 HSuite (https://hsuite.finance)
|
|
4
|
+
*
|
|
5
|
+
* SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0
|
|
6
|
+
*
|
|
7
|
+
* This file is part of HSuite Native Connect. For commercial licensing,
|
|
8
|
+
* visit https://hsuite.finance/licensing
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @file walletconnect-client-manager.ts
|
|
13
|
+
* @description WalletConnect SignClient lifecycle management
|
|
14
|
+
*
|
|
15
|
+
* Handles:
|
|
16
|
+
* - SignClient initialization with projectId
|
|
17
|
+
* - Client reuse across multiple connections
|
|
18
|
+
* - Session restoration from IndexedDB
|
|
19
|
+
* - Event listener registration
|
|
20
|
+
*
|
|
21
|
+
* Extracted from WalletConnectV2Provider to reduce file size.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import { getLogger } from '@hsuite/native-connect-sdk';
|
|
25
|
+
import { WalletConnectModal } from '@walletconnect/modal';
|
|
26
|
+
import SignClient from '@walletconnect/sign-client';
|
|
27
|
+
|
|
28
|
+
import { SessionHealthManager } from './session-health';
|
|
29
|
+
|
|
30
|
+
const logger = getLogger().scoped?.('WCClientManager') ?? getLogger();
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Storage key for persisted projectId
|
|
34
|
+
*/
|
|
35
|
+
const STORAGE_KEY_PROJECT_ID = 'hsuite.walletconnect.projectId';
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* WalletConnect app metadata
|
|
39
|
+
*/
|
|
40
|
+
export interface WCAppMetadata {
|
|
41
|
+
name: string;
|
|
42
|
+
description: string;
|
|
43
|
+
url: string;
|
|
44
|
+
icons: string[];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* WalletConnect Client Manager
|
|
49
|
+
*
|
|
50
|
+
* Manages the SignClient instance lifecycle.
|
|
51
|
+
* Handles initialization, session restoration, and cleanup.
|
|
52
|
+
*/
|
|
53
|
+
export class WalletConnectClientManager {
|
|
54
|
+
private client?: SignClient;
|
|
55
|
+
private modal?: WalletConnectModal;
|
|
56
|
+
private projectId?: string;
|
|
57
|
+
private sessionHealth?: SessionHealthManager;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Initialize or return existing SignClient.
|
|
61
|
+
*
|
|
62
|
+
* @param projectId - WalletConnect Cloud project ID
|
|
63
|
+
* @param metadata - App metadata for wallet display
|
|
64
|
+
* @returns Initialized SignClient instance
|
|
65
|
+
*/
|
|
66
|
+
async initialize(projectId: string, metadata: WCAppMetadata): Promise<SignClient> {
|
|
67
|
+
if (this.client && this.projectId === projectId) {
|
|
68
|
+
return this.client;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
logger.debug('Initializing SignClient', { projectId: projectId.substring(0, 8) });
|
|
72
|
+
|
|
73
|
+
// Store projectId for session restoration
|
|
74
|
+
this.projectId = projectId;
|
|
75
|
+
this.persistProjectId(projectId);
|
|
76
|
+
|
|
77
|
+
// Use 'fatal' logger to suppress pino noise from WalletConnect SDK
|
|
78
|
+
this.client = await SignClient.init({
|
|
79
|
+
projectId,
|
|
80
|
+
logger: 'fatal',
|
|
81
|
+
metadata,
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// Initialize session health manager for relay subscription management
|
|
85
|
+
this.sessionHealth = new SessionHealthManager(this.client);
|
|
86
|
+
|
|
87
|
+
logger.info('SignClient initialized with session health manager');
|
|
88
|
+
return this.client;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Get the current client instance.
|
|
93
|
+
* @throws Error if not initialized
|
|
94
|
+
*/
|
|
95
|
+
getClient(): SignClient {
|
|
96
|
+
if (!this.client) {
|
|
97
|
+
throw new Error('WalletConnect client not initialized');
|
|
98
|
+
}
|
|
99
|
+
return this.client;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Check if client is initialized.
|
|
104
|
+
*/
|
|
105
|
+
isInitialized(): boolean {
|
|
106
|
+
return !!this.client;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Restore client from stored projectId.
|
|
111
|
+
* Used for session restoration on page reload.
|
|
112
|
+
*
|
|
113
|
+
* @param metadata - App metadata
|
|
114
|
+
* @returns Client if restoration succeeded, undefined otherwise
|
|
115
|
+
*/
|
|
116
|
+
async restoreClient(metadata: WCAppMetadata): Promise<SignClient | undefined> {
|
|
117
|
+
const storedProjectId = this.getStoredProjectId();
|
|
118
|
+
if (!storedProjectId) {
|
|
119
|
+
logger.debug('No stored projectId, skipping client restoration');
|
|
120
|
+
return undefined;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
try {
|
|
124
|
+
return await this.initialize(storedProjectId, metadata);
|
|
125
|
+
} catch (error) {
|
|
126
|
+
logger.error('Failed to restore client', {
|
|
127
|
+
error: error instanceof Error ? error.message : String(error),
|
|
128
|
+
});
|
|
129
|
+
return undefined;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Get all active sessions from the client.
|
|
135
|
+
*/
|
|
136
|
+
getActiveSessions(): any[] {
|
|
137
|
+
if (!this.client) {
|
|
138
|
+
return [];
|
|
139
|
+
}
|
|
140
|
+
return this.client.session.getAll();
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Get a specific session by topic.
|
|
145
|
+
* @param topic
|
|
146
|
+
*/
|
|
147
|
+
getSession(topic: string): any | undefined {
|
|
148
|
+
if (!this.client) {
|
|
149
|
+
return undefined;
|
|
150
|
+
}
|
|
151
|
+
try {
|
|
152
|
+
return this.client.session.get(topic);
|
|
153
|
+
} catch {
|
|
154
|
+
return undefined;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Create and return a modal for QR code display.
|
|
160
|
+
* @param projectId
|
|
161
|
+
* @param chains
|
|
162
|
+
*/
|
|
163
|
+
createModal(projectId: string, chains: string[]): WalletConnectModal {
|
|
164
|
+
this.modal = new WalletConnectModal({
|
|
165
|
+
projectId,
|
|
166
|
+
chains,
|
|
167
|
+
});
|
|
168
|
+
return this.modal;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Close the modal if open.
|
|
173
|
+
*/
|
|
174
|
+
closeModal(): void {
|
|
175
|
+
if (this.modal) {
|
|
176
|
+
this.modal.closeModal();
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Connect to wallet and get session.
|
|
182
|
+
*
|
|
183
|
+
* @param optionalNamespaces - Namespace configuration
|
|
184
|
+
* @param sessionProperties - Optional session properties (e.g., preferredNetwork)
|
|
185
|
+
* @returns URI and approval promise
|
|
186
|
+
*/
|
|
187
|
+
async connect(
|
|
188
|
+
optionalNamespaces: Record<string, any>,
|
|
189
|
+
sessionProperties?: Record<string, string>,
|
|
190
|
+
): Promise<{
|
|
191
|
+
uri?: string;
|
|
192
|
+
approval: () => Promise<any>;
|
|
193
|
+
}> {
|
|
194
|
+
if (!this.client) {
|
|
195
|
+
throw new Error('Client not initialized');
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const connectParams: any = { optionalNamespaces };
|
|
199
|
+
|
|
200
|
+
// Add session properties if provided
|
|
201
|
+
// This allows passing metadata like preferredNetwork to the wallet
|
|
202
|
+
if (sessionProperties) {
|
|
203
|
+
connectParams.sessionProperties = sessionProperties;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
logger.debug('Connecting with params', {
|
|
207
|
+
namespaces: Object.keys(optionalNamespaces),
|
|
208
|
+
hasSessionProperties: !!sessionProperties,
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
return this.client.connect(connectParams);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Disconnect a session.
|
|
216
|
+
* @param topic
|
|
217
|
+
* @param reason
|
|
218
|
+
* @param reason.code
|
|
219
|
+
* @param reason.message
|
|
220
|
+
*/
|
|
221
|
+
async disconnect(topic: string, reason?: { code: number; message: string }): Promise<void> {
|
|
222
|
+
if (!this.client) {
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
await this.client.disconnect({
|
|
226
|
+
topic,
|
|
227
|
+
reason: reason || { code: 6000, message: 'User disconnected' },
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Register event listener on the client.
|
|
233
|
+
* @param event
|
|
234
|
+
* @param handler
|
|
235
|
+
*/
|
|
236
|
+
on(event: string, handler: (event: any) => void): void {
|
|
237
|
+
if (!this.client) {
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
(this.client as any).on(event, handler);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Send a request to a session.
|
|
245
|
+
*
|
|
246
|
+
* Features:
|
|
247
|
+
* - Automatically ensures session health by pinging before the request
|
|
248
|
+
* - Runs keep-alive pings during long-running requests (e.g., transaction approval)
|
|
249
|
+
* - Prevents stale relay subscription issues that cause empty error objects
|
|
250
|
+
*
|
|
251
|
+
* @param params - Request parameters including topic, chainId, and request data
|
|
252
|
+
* @param params.expiry - Optional expiry time in seconds (default: 300)
|
|
253
|
+
* @param params.topic
|
|
254
|
+
* @param params.chainId
|
|
255
|
+
* @param params.request
|
|
256
|
+
* @param params.request.method
|
|
257
|
+
* @param params.request.params
|
|
258
|
+
* @returns Promise resolving to the request result
|
|
259
|
+
*/
|
|
260
|
+
async request<T = unknown>(params: {
|
|
261
|
+
topic: string;
|
|
262
|
+
chainId: string;
|
|
263
|
+
request: { method: string; params: unknown };
|
|
264
|
+
expiry?: number;
|
|
265
|
+
}): Promise<T> {
|
|
266
|
+
if (!this.client) {
|
|
267
|
+
throw new Error('Client not initialized');
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// Ensure session health before request (transparent to caller)
|
|
271
|
+
// This pings the session if needed to refresh relay subscription
|
|
272
|
+
if (this.sessionHealth) {
|
|
273
|
+
await this.sessionHealth.ensureSessionHealth(params.topic);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Keep-alive pings during long-running requests (e.g., transaction approval)
|
|
277
|
+
// WC relay has ~30s subscription timeout, so we ping every 20s to keep it alive
|
|
278
|
+
const KEEP_ALIVE_INTERVAL_MS = 20000;
|
|
279
|
+
let keepAliveInterval: ReturnType<typeof setInterval> | undefined;
|
|
280
|
+
|
|
281
|
+
const startKeepAlive = () => {
|
|
282
|
+
keepAliveInterval = setInterval(async () => {
|
|
283
|
+
try {
|
|
284
|
+
logger.debug('Keep-alive ping during request', {
|
|
285
|
+
topic: params.topic?.substring(0, 16) + '...',
|
|
286
|
+
method: params.request.method,
|
|
287
|
+
});
|
|
288
|
+
if (this.client) {
|
|
289
|
+
await Promise.race([
|
|
290
|
+
this.client.ping({ topic: params.topic }),
|
|
291
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error('Ping timeout')), 5000)),
|
|
292
|
+
]);
|
|
293
|
+
}
|
|
294
|
+
} catch (err) {
|
|
295
|
+
// Log but don't throw - ping failure during wait is not critical
|
|
296
|
+
logger.debug('Keep-alive ping failed (non-critical)', {
|
|
297
|
+
error: err instanceof Error ? err.message : String(err),
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
}, KEEP_ALIVE_INTERVAL_MS);
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
const stopKeepAlive = () => {
|
|
304
|
+
if (keepAliveInterval) {
|
|
305
|
+
clearInterval(keepAliveInterval);
|
|
306
|
+
keepAliveInterval = undefined;
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
// Start keep-alive pings
|
|
311
|
+
startKeepAlive();
|
|
312
|
+
|
|
313
|
+
try {
|
|
314
|
+
const result = await this.client.request<T>(params);
|
|
315
|
+
return result;
|
|
316
|
+
} finally {
|
|
317
|
+
// Always stop keep-alive, whether success or error
|
|
318
|
+
stopKeepAlive();
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Get the session health manager for advanced operations.
|
|
324
|
+
*
|
|
325
|
+
* Use this if you need to:
|
|
326
|
+
* - Force refresh a subscription
|
|
327
|
+
* - Clear ping cache
|
|
328
|
+
* - Access health manager directly
|
|
329
|
+
*
|
|
330
|
+
* @returns SessionHealthManager instance or undefined if not initialized
|
|
331
|
+
*/
|
|
332
|
+
getSessionHealthManager(): SessionHealthManager | undefined {
|
|
333
|
+
return this.sessionHealth;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// ========== STORAGE ==========
|
|
337
|
+
|
|
338
|
+
private persistProjectId(projectId: string): void {
|
|
339
|
+
try {
|
|
340
|
+
window.localStorage?.setItem(STORAGE_KEY_PROJECT_ID, projectId);
|
|
341
|
+
} catch {
|
|
342
|
+
logger.warn('Failed to persist projectId');
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
private getStoredProjectId(): string | null {
|
|
347
|
+
try {
|
|
348
|
+
return window.localStorage?.getItem(STORAGE_KEY_PROJECT_ID) ?? null;
|
|
349
|
+
} catch {
|
|
350
|
+
return null;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* Clear stored projectId.
|
|
356
|
+
*/
|
|
357
|
+
clearStoredProjectId(): void {
|
|
358
|
+
try {
|
|
359
|
+
window.localStorage?.removeItem(STORAGE_KEY_PROJECT_ID);
|
|
360
|
+
} catch {
|
|
361
|
+
// Ignore
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file walletconnect-provider.integration.spec.ts
|
|
3
|
+
* @description Integration tests for WalletConnectV2Provider
|
|
4
|
+
*
|
|
5
|
+
* @compodoc
|
|
6
|
+
* These tests verify the WalletConnect v2 provider integration.
|
|
7
|
+
* Some tests are skipped due to complex session state requirements.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
11
|
+
import { TestBed } from '@angular/core/testing';
|
|
12
|
+
import { WalletConnectV2Provider } from './walletconnect-provider';
|
|
13
|
+
import { SignerFactory } from '../signers/signer-factory';
|
|
14
|
+
import { HederaSigner } from '../signers/hedera-signer';
|
|
15
|
+
import { XrplSigner } from '../signers/xrpl-signer';
|
|
16
|
+
import type { WalletConnectV2Config } from './walletconnect-types';
|
|
17
|
+
|
|
18
|
+
// Mock WalletConnect modules
|
|
19
|
+
vi.mock('@walletconnect/sign-client', () => ({
|
|
20
|
+
default: {
|
|
21
|
+
init: vi.fn(),
|
|
22
|
+
},
|
|
23
|
+
}));
|
|
24
|
+
|
|
25
|
+
vi.mock('@walletconnect/modal', () => ({
|
|
26
|
+
WalletConnectModal: vi.fn(),
|
|
27
|
+
}));
|
|
28
|
+
|
|
29
|
+
describe('WalletConnectV2Provider Integration Tests', () => {
|
|
30
|
+
let provider: WalletConnectV2Provider;
|
|
31
|
+
// Note: SignerFactory uses static methods, no need to inject
|
|
32
|
+
let mockSignClient: any;
|
|
33
|
+
let mockModal: any;
|
|
34
|
+
|
|
35
|
+
beforeEach(async () => {
|
|
36
|
+
// Clear localStorage
|
|
37
|
+
localStorage.clear();
|
|
38
|
+
|
|
39
|
+
// Mock SignClient
|
|
40
|
+
mockSignClient = {
|
|
41
|
+
connect: vi.fn().mockResolvedValue({
|
|
42
|
+
uri: 'wc:test-uri',
|
|
43
|
+
approval: vi.fn().mockResolvedValue({
|
|
44
|
+
topic: 'test-topic',
|
|
45
|
+
namespaces: {
|
|
46
|
+
hedera: {
|
|
47
|
+
accounts: ['hedera:testnet:0.0.12345'],
|
|
48
|
+
methods: ['hedera_signTransaction'],
|
|
49
|
+
chains: ['hedera:testnet']
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
})
|
|
53
|
+
}),
|
|
54
|
+
disconnect: vi.fn().mockResolvedValue(undefined),
|
|
55
|
+
request: vi.fn(),
|
|
56
|
+
session: {
|
|
57
|
+
getAll: vi.fn().mockReturnValue([])
|
|
58
|
+
},
|
|
59
|
+
on: vi.fn()
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
// Mock Modal
|
|
63
|
+
mockModal = {
|
|
64
|
+
openModal: vi.fn().mockResolvedValue(undefined),
|
|
65
|
+
closeModal: vi.fn()
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const { default: SignClient } = await import('@walletconnect/sign-client');
|
|
69
|
+
const { WalletConnectModal } = await import('@walletconnect/modal');
|
|
70
|
+
|
|
71
|
+
vi.mocked(SignClient.init).mockResolvedValue(mockSignClient);
|
|
72
|
+
vi.mocked(WalletConnectModal).mockImplementation(() => mockModal);
|
|
73
|
+
|
|
74
|
+
TestBed.configureTestingModule({
|
|
75
|
+
providers: [
|
|
76
|
+
WalletConnectV2Provider,
|
|
77
|
+
HederaSigner,
|
|
78
|
+
XrplSigner
|
|
79
|
+
]
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
provider = TestBed.inject(WalletConnectV2Provider);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
describe('Provider Metadata', () => {
|
|
86
|
+
it('should have correct metadata', () => {
|
|
87
|
+
expect(provider.id).toBe('walletconnect-v2');
|
|
88
|
+
expect(provider.metadata.type).toBe('walletconnect-v2');
|
|
89
|
+
expect(provider.metadata.name).toBe('WalletConnect');
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
describe('Connection Flow', () => {
|
|
94
|
+
const config: WalletConnectV2Config = {
|
|
95
|
+
type: 'walletconnect-v2',
|
|
96
|
+
projectId: 'test-project-id',
|
|
97
|
+
ledgerId: 'hedera',
|
|
98
|
+
networkId: 'hedera:testnet',
|
|
99
|
+
appName: 'Test dApp'
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
it('should connect successfully with Hedera', async () => {
|
|
103
|
+
await provider.connect(config);
|
|
104
|
+
|
|
105
|
+
expect(provider.status()).toBe('connected');
|
|
106
|
+
expect(provider.accounts()).toHaveLength(1);
|
|
107
|
+
expect(provider.accounts()[0].address).toBe('0.0.12345');
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('should initialize SignClient with correct params', async () => {
|
|
111
|
+
const { default: SignClient } = await import('@walletconnect/sign-client');
|
|
112
|
+
|
|
113
|
+
await provider.connect(config);
|
|
114
|
+
|
|
115
|
+
expect(SignClient.init).toHaveBeenCalledWith(
|
|
116
|
+
expect.objectContaining({
|
|
117
|
+
projectId: 'test-project-id',
|
|
118
|
+
metadata: expect.objectContaining({
|
|
119
|
+
name: 'Test dApp'
|
|
120
|
+
})
|
|
121
|
+
})
|
|
122
|
+
);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it('should open modal with URI', async () => {
|
|
126
|
+
await provider.connect(config);
|
|
127
|
+
|
|
128
|
+
expect(mockModal.openModal).toHaveBeenCalledWith({
|
|
129
|
+
uri: 'wc:test-uri'
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it('should close modal after approval', async () => {
|
|
134
|
+
await provider.connect(config);
|
|
135
|
+
|
|
136
|
+
expect(mockModal.closeModal).toHaveBeenCalled();
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it('should store user network selection in localStorage', async () => {
|
|
140
|
+
await provider.connect(config);
|
|
141
|
+
|
|
142
|
+
// The provider stores user's network selection per session topic for restoration
|
|
143
|
+
// Check that the network selection was stored (using the test-topic from mock)
|
|
144
|
+
expect(localStorage.getItem('wc_user_network_selection_test-topic')).toBe('hedera:testnet');
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it('should set error state if connection fails', async () => {
|
|
148
|
+
const { default: SignClient } = await import('@walletconnect/sign-client');
|
|
149
|
+
vi.mocked(SignClient.init).mockRejectedValue(new Error('Network error'));
|
|
150
|
+
|
|
151
|
+
await expect(provider.connect(config)).rejects.toThrow();
|
|
152
|
+
|
|
153
|
+
expect(provider.status()).toBe('error');
|
|
154
|
+
expect(provider.error()).toContain('Network error');
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
// Transaction signing tests - provider delegates to signers via the orchestrator
|
|
159
|
+
describe('Transaction Signing', () => {
|
|
160
|
+
beforeEach(async () => {
|
|
161
|
+
// Connect first
|
|
162
|
+
await provider.connect({
|
|
163
|
+
type: 'walletconnect-v2',
|
|
164
|
+
projectId: 'test-project-id',
|
|
165
|
+
ledgerId: 'hedera',
|
|
166
|
+
networkId: 'hedera:testnet'
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
mockSignClient.request.mockResolvedValue({
|
|
170
|
+
signatureMap: 'signed-result'
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it('should throw error when signing with unknown account address', async () => {
|
|
175
|
+
// Attempt to sign with an account that doesn't exist in the session
|
|
176
|
+
await expect(provider.signTransaction({
|
|
177
|
+
ledgerId: 'hedera',
|
|
178
|
+
networkId: 'hedera:testnet',
|
|
179
|
+
accountAddress: '0.0.99999', // Not in session
|
|
180
|
+
payload: 'base64TransactionHere'
|
|
181
|
+
})).rejects.toThrow('No WalletConnect session found for account');
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
it('should throw error when no session exists for account', async () => {
|
|
185
|
+
// Disconnect first - this clears all sessions
|
|
186
|
+
await provider.disconnect();
|
|
187
|
+
|
|
188
|
+
// Create new provider that's not connected
|
|
189
|
+
const disconnectedProvider = TestBed.inject(WalletConnectV2Provider);
|
|
190
|
+
|
|
191
|
+
// The session lookup happens first, so we get "No WalletConnect session" error
|
|
192
|
+
await expect(disconnectedProvider.signTransaction({
|
|
193
|
+
ledgerId: 'hedera',
|
|
194
|
+
networkId: 'hedera:testnet',
|
|
195
|
+
accountAddress: '0.0.12345',
|
|
196
|
+
payload: 'base64'
|
|
197
|
+
})).rejects.toThrow('No WalletConnect session found for account');
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
// Transaction submission tests - provider delegates to signers via the orchestrator
|
|
202
|
+
describe('Transaction Submission', () => {
|
|
203
|
+
beforeEach(async () => {
|
|
204
|
+
await provider.connect({
|
|
205
|
+
type: 'walletconnect-v2',
|
|
206
|
+
projectId: 'test-project-id',
|
|
207
|
+
ledgerId: 'hedera',
|
|
208
|
+
networkId: 'hedera:testnet'
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
mockSignClient.request.mockResolvedValue({
|
|
212
|
+
transactionId: '0.0.12345@1699999999.123'
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
it('should throw error when submitting with unknown account address', async () => {
|
|
217
|
+
// Attempt to submit with an account that doesn't exist in the session
|
|
218
|
+
await expect(provider.submitTransaction({
|
|
219
|
+
ledgerId: 'hedera',
|
|
220
|
+
networkId: 'hedera:testnet',
|
|
221
|
+
accountAddress: '0.0.99999', // Not in session
|
|
222
|
+
payload: 'base64TransactionHere'
|
|
223
|
+
})).rejects.toThrow('No WalletConnect session found for account');
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
it('should throw error when no session exists for account', async () => {
|
|
227
|
+
// Disconnect first - this clears all sessions
|
|
228
|
+
await provider.disconnect();
|
|
229
|
+
|
|
230
|
+
// Create new provider that's not connected
|
|
231
|
+
const disconnectedProvider = TestBed.inject(WalletConnectV2Provider);
|
|
232
|
+
|
|
233
|
+
// The session lookup happens first, so we get "No WalletConnect session" error
|
|
234
|
+
await expect(disconnectedProvider.submitTransaction({
|
|
235
|
+
ledgerId: 'hedera',
|
|
236
|
+
networkId: 'hedera:testnet',
|
|
237
|
+
accountAddress: '0.0.12345',
|
|
238
|
+
payload: 'base64'
|
|
239
|
+
})).rejects.toThrow('No WalletConnect session found for account');
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
describe('Disconnection', () => {
|
|
244
|
+
it('should disconnect and clear state', async () => {
|
|
245
|
+
// Connect first
|
|
246
|
+
await provider.connect({
|
|
247
|
+
type: 'walletconnect-v2',
|
|
248
|
+
projectId: 'test-project-id',
|
|
249
|
+
ledgerId: 'hedera',
|
|
250
|
+
networkId: 'hedera:testnet'
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
expect(provider.status()).toBe('connected');
|
|
254
|
+
|
|
255
|
+
// Disconnect
|
|
256
|
+
await provider.disconnect();
|
|
257
|
+
|
|
258
|
+
expect(provider.status()).toBe('disconnected');
|
|
259
|
+
expect(provider.accounts()).toHaveLength(0);
|
|
260
|
+
expect(mockSignClient.disconnect).toHaveBeenCalledWith({
|
|
261
|
+
topic: 'test-topic',
|
|
262
|
+
reason: expect.any(Object)
|
|
263
|
+
});
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
it('should close modal on disconnect', async () => {
|
|
267
|
+
await provider.connect({
|
|
268
|
+
type: 'walletconnect-v2',
|
|
269
|
+
projectId: 'test-project-id',
|
|
270
|
+
ledgerId: 'hedera',
|
|
271
|
+
networkId: 'hedera:testnet'
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
await provider.disconnect();
|
|
275
|
+
|
|
276
|
+
// Modal closed during disconnect cleanup
|
|
277
|
+
expect(mockModal.closeModal).toHaveBeenCalled();
|
|
278
|
+
});
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
describe('Session Restoration', () => {
|
|
282
|
+
it('should restore session from localStorage', async () => {
|
|
283
|
+
// Set up stored session
|
|
284
|
+
localStorage.setItem('hsuite.walletconnect.projectId', 'stored-project-id');
|
|
285
|
+
localStorage.setItem('hsuite.walletconnect.ledgerId', 'hedera');
|
|
286
|
+
localStorage.setItem('hsuite.walletconnect.networkId', 'hedera:testnet');
|
|
287
|
+
|
|
288
|
+
mockSignClient.session.getAll.mockReturnValue([
|
|
289
|
+
{
|
|
290
|
+
topic: 'stored-topic',
|
|
291
|
+
namespaces: {
|
|
292
|
+
hedera: {
|
|
293
|
+
accounts: ['hedera:testnet:0.0.99999']
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
]);
|
|
298
|
+
|
|
299
|
+
// Create new provider instance (triggers restoration)
|
|
300
|
+
const newProvider = TestBed.inject(WalletConnectV2Provider);
|
|
301
|
+
|
|
302
|
+
// Wait for restoration
|
|
303
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
304
|
+
|
|
305
|
+
// Restoration happens in constructor, check if client was initialized
|
|
306
|
+
const { default: SignClient } = await import('@walletconnect/sign-client');
|
|
307
|
+
expect(SignClient.init).toHaveBeenCalled();
|
|
308
|
+
});
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
describe('Multi-Chain Support', () => {
|
|
312
|
+
it('should support XRPL connection', async () => {
|
|
313
|
+
mockSignClient.connect = vi.fn().mockResolvedValue({
|
|
314
|
+
uri: 'wc:xrpl-uri',
|
|
315
|
+
approval: vi.fn().mockResolvedValue({
|
|
316
|
+
topic: 'xrpl-topic',
|
|
317
|
+
namespaces: {
|
|
318
|
+
xrpl: {
|
|
319
|
+
accounts: ['xrpl:testnet:rN7n7otQDd6FczFgLdlqtyMVrn3HMfeeZE'],
|
|
320
|
+
methods: ['xrpl_signTransaction'],
|
|
321
|
+
chains: ['xrpl:testnet']
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
})
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
await provider.connect({
|
|
328
|
+
type: 'walletconnect-v2',
|
|
329
|
+
projectId: 'test-project-id',
|
|
330
|
+
ledgerId: 'xrpl',
|
|
331
|
+
networkId: 'xrpl:testnet'
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
expect(provider.status()).toBe('connected');
|
|
335
|
+
expect(provider.accounts()[0].ledgerId).toBe('xrpl');
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
it('should use correct signer for each ledger', async () => {
|
|
339
|
+
// SignerFactory uses static methods
|
|
340
|
+
const hederaSigner = SignerFactory.getSigner('hedera');
|
|
341
|
+
const xrplSigner = SignerFactory.getSigner('xrpl');
|
|
342
|
+
|
|
343
|
+
expect(hederaSigner.ledgerId).toBe('hedera');
|
|
344
|
+
expect(xrplSigner.ledgerId).toBe('xrpl');
|
|
345
|
+
expect(hederaSigner).not.toBe(xrplSigner);
|
|
346
|
+
});
|
|
347
|
+
});
|
|
348
|
+
});
|