@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,852 @@
|
|
|
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 Central service for managing multiple wallet providers in Angular applications.
|
|
13
|
+
* @module services/unified-wallet
|
|
14
|
+
*
|
|
15
|
+
* @description
|
|
16
|
+
* UnifiedWalletService is the primary entry point for dApp developers to interact with
|
|
17
|
+
* blockchain wallets. It provides a unified API that abstracts the differences between
|
|
18
|
+
* various wallet connection protocols (HSuite Native, WalletConnect, P2P).
|
|
19
|
+
*
|
|
20
|
+
* Key Capabilities:
|
|
21
|
+
* - **Multi-Provider Management**: Register and manage multiple wallet providers
|
|
22
|
+
* - **Unified Account Access**: Aggregate accounts from all connected providers
|
|
23
|
+
* - **Active Account Tracking**: Maintain and switch the currently active account
|
|
24
|
+
* - **Transaction Operations**: Sign and submit transactions through any connected wallet
|
|
25
|
+
* - **Session Management**: Handle wallet sessions with automatic reconnection
|
|
26
|
+
*
|
|
27
|
+
* Architecture:
|
|
28
|
+
* ```
|
|
29
|
+
* +-------------------------------------------------------------------+
|
|
30
|
+
* | UnifiedWalletService |
|
|
31
|
+
* +-------------------------------------------------------------------+
|
|
32
|
+
* | |
|
|
33
|
+
* | +-------------------+ +-------------------+ +----------------+ |
|
|
34
|
+
* | | HsuiteNative | | WalletConnect | | P2PNative | |
|
|
35
|
+
* | | Provider | | V2Provider | | Provider | |
|
|
36
|
+
* | +-------------------+ +-------------------+ +----------------+ |
|
|
37
|
+
* | | | | |
|
|
38
|
+
* | +----------------------+----------------------+ |
|
|
39
|
+
* | | |
|
|
40
|
+
* | BaseWalletProvider |
|
|
41
|
+
* | (common interface) |
|
|
42
|
+
* +-------------------------------------------------------------------+
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
|
|
46
|
+
import { Injectable, signal, computed, inject, effect } from '@angular/core';
|
|
47
|
+
import { getLogger } from '@hsuite/native-connect-sdk';
|
|
48
|
+
|
|
49
|
+
import type { ConnectionConfig } from '../models/connection-config.model';
|
|
50
|
+
import type { ProviderType, ConnectionStatus } from '../models/provider-types';
|
|
51
|
+
import type { UnifiedAccount } from '../models/unified-account.model';
|
|
52
|
+
import { BaseWalletProvider } from '../providers/base-wallet-provider';
|
|
53
|
+
import { HsuiteNativeProvider } from '../providers/hsuite-native-provider';
|
|
54
|
+
import { P2PNativeProvider } from '../providers/p2p-native/p2p-native.provider';
|
|
55
|
+
import { WalletConnectV2Provider } from '../providers/walletconnect/core/walletconnect-provider';
|
|
56
|
+
|
|
57
|
+
import { WalletEventBus } from './wallet-event-bus.service';
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
const logger = getLogger().scoped?.('UnifiedWalletService') ?? getLogger();
|
|
61
|
+
|
|
62
|
+
interface ProviderSummary {
|
|
63
|
+
id: string;
|
|
64
|
+
name: string;
|
|
65
|
+
providerType: string;
|
|
66
|
+
status: ConnectionStatus;
|
|
67
|
+
accounts: UnifiedAccount[];
|
|
68
|
+
supportsReconnect: boolean;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Central service for managing wallet connections across multiple protocols.
|
|
73
|
+
*
|
|
74
|
+
* @description
|
|
75
|
+
* UnifiedWalletService provides a unified interface for interacting with blockchain wallets
|
|
76
|
+
* regardless of the underlying connection protocol. It manages multiple provider instances,
|
|
77
|
+
* aggregates accounts, and provides transaction signing/submission capabilities.
|
|
78
|
+
*
|
|
79
|
+
* The service automatically registers built-in providers (HSuite Native, WalletConnect, P2P)
|
|
80
|
+
* and supports session restoration across page reloads.
|
|
81
|
+
*
|
|
82
|
+
* @Component({
|
|
83
|
+
* template: `
|
|
84
|
+
* <div *ngIf="wallet.activeAccount() as account">
|
|
85
|
+
* Connected: {{ account.address }}
|
|
86
|
+
* </div>
|
|
87
|
+
* <button (click)="connectWallet()">Connect</button>
|
|
88
|
+
* `
|
|
89
|
+
* })
|
|
90
|
+
* export class MyComponent {
|
|
91
|
+
* wallet = inject(UnifiedWalletService);
|
|
92
|
+
*
|
|
93
|
+
* async connectWallet() {
|
|
94
|
+
* await this.wallet.connect('hsuite-native', {
|
|
95
|
+
* type: 'hsuite-native',
|
|
96
|
+
* appId: 'my-dapp',
|
|
97
|
+
* appName: 'My dApp',
|
|
98
|
+
* ledgerId: 'hedera',
|
|
99
|
+
* networkId: 'testnet',
|
|
100
|
+
* });
|
|
101
|
+
* }
|
|
102
|
+
* }
|
|
103
|
+
* ```
|
|
104
|
+
*
|
|
105
|
+
* @publicApi
|
|
106
|
+
*/
|
|
107
|
+
@Injectable({ providedIn: 'root' })
|
|
108
|
+
export class UnifiedWalletService {
|
|
109
|
+
/**
|
|
110
|
+
* Map of registered providers
|
|
111
|
+
*/
|
|
112
|
+
private readonly providers = new Map<string, BaseWalletProvider>();
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Signal tracking all registered provider IDs
|
|
116
|
+
*/
|
|
117
|
+
private readonly _providerIds = signal<string[]>([]);
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Signal for the active account (across all providers)
|
|
121
|
+
*/
|
|
122
|
+
private readonly _activeAccount = signal<UnifiedAccount | null>(null);
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Event bus for emitting wallet events
|
|
126
|
+
*/
|
|
127
|
+
private readonly eventBus = inject(WalletEventBus);
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
*
|
|
131
|
+
* @param hsuiteProvider
|
|
132
|
+
* @param walletConnectProvider
|
|
133
|
+
* @param p2pNativeProvider
|
|
134
|
+
*/
|
|
135
|
+
constructor(
|
|
136
|
+
hsuiteProvider: HsuiteNativeProvider,
|
|
137
|
+
walletConnectProvider: WalletConnectV2Provider,
|
|
138
|
+
p2pNativeProvider: P2PNativeProvider,
|
|
139
|
+
) {
|
|
140
|
+
// Auto-register built-in providers (injected as constructor params)
|
|
141
|
+
this.registerProvider(hsuiteProvider);
|
|
142
|
+
this.registerProvider(walletConnectProvider);
|
|
143
|
+
this.registerProvider(p2pNativeProvider);
|
|
144
|
+
|
|
145
|
+
// Auto-select first account from unknown restored session (after a delay to let providers restore)
|
|
146
|
+
setTimeout(() => {
|
|
147
|
+
const allAccounts = this.allAccounts();
|
|
148
|
+
if (!this._activeAccount() && allAccounts.length > 0) {
|
|
149
|
+
this.setActiveAccount(allAccounts[0]);
|
|
150
|
+
|
|
151
|
+
// Emit session restored event
|
|
152
|
+
this.eventBus.sessionRestored.emit({
|
|
153
|
+
providerId: allAccounts[0].providerId,
|
|
154
|
+
sessionKey: allAccounts[0].id,
|
|
155
|
+
accounts: allAccounts,
|
|
156
|
+
metadata: { autoRestored: true },
|
|
157
|
+
timestamp: Date.now(),
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
}, 100);
|
|
161
|
+
|
|
162
|
+
effect(() => {
|
|
163
|
+
const accounts = this.allAccounts();
|
|
164
|
+
const active = this._activeAccount();
|
|
165
|
+
|
|
166
|
+
if (accounts.length === 0) {
|
|
167
|
+
if (active) {
|
|
168
|
+
this.setActiveAccount(null);
|
|
169
|
+
}
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const activeStillPresent = active ? accounts.some((acct) => acct.id === active.id) : false;
|
|
174
|
+
if (!activeStillPresent) {
|
|
175
|
+
this.setActiveAccount(accounts[0]);
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Gets summaries of all registered providers including status and accounts.
|
|
182
|
+
*
|
|
183
|
+
* @description
|
|
184
|
+
* Returns metadata about each registered provider, useful for building
|
|
185
|
+
* wallet selection UI or debugging connection states.
|
|
186
|
+
*
|
|
187
|
+
* @returns Array of provider summaries with status and account information
|
|
188
|
+
*/
|
|
189
|
+
getProviderSummaries(): ProviderSummary[] {
|
|
190
|
+
return Array.from(this.providers.values()).map((provider) => ({
|
|
191
|
+
id: provider.id,
|
|
192
|
+
name: provider.metadata.name,
|
|
193
|
+
providerType: provider.metadata.type,
|
|
194
|
+
status: provider.status(),
|
|
195
|
+
accounts: provider.accounts(),
|
|
196
|
+
supportsReconnect: typeof (provider as any).attemptReconnect === 'function',
|
|
197
|
+
}));
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Attempts to reconnect a provider using stored session data.
|
|
202
|
+
*
|
|
203
|
+
* @description
|
|
204
|
+
* Some providers (like HSuite Native) support session persistence and can
|
|
205
|
+
* automatically reconnect after page reload without user interaction.
|
|
206
|
+
* This method triggers the reconnection attempt.
|
|
207
|
+
*
|
|
208
|
+
* @param providerId - The provider ID to reconnect (e.g., 'hsuite-native')
|
|
209
|
+
*
|
|
210
|
+
* @returns Promise resolving to true if reconnection succeeded, false otherwise
|
|
211
|
+
*/
|
|
212
|
+
async reconnectProvider(providerId: string): Promise<boolean> {
|
|
213
|
+
const provider = this.providers.get(providerId);
|
|
214
|
+
if (!provider) {
|
|
215
|
+
return false;
|
|
216
|
+
}
|
|
217
|
+
const reconnect = (provider as unknown as { attemptReconnect?: () => Promise<boolean> })
|
|
218
|
+
.attemptReconnect;
|
|
219
|
+
if (typeof reconnect === 'function') {
|
|
220
|
+
try {
|
|
221
|
+
return await reconnect.call(provider);
|
|
222
|
+
} catch (error) {
|
|
223
|
+
logger.warn('Provider reconnect failed', { providerId, error });
|
|
224
|
+
return false;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return false;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* All accounts from all connected providers (reactive)
|
|
232
|
+
*/
|
|
233
|
+
readonly allAccounts = computed<UnifiedAccount[]>(() => {
|
|
234
|
+
const providers = Array.from(this.providers.values());
|
|
235
|
+
return providers.flatMap((p) => p.accounts());
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Currently active account (reactive)
|
|
240
|
+
*/
|
|
241
|
+
readonly activeAccount = computed(() => this._activeAccount());
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* List of connected providers (reactive)
|
|
245
|
+
*/
|
|
246
|
+
readonly connectedProviders = computed<BaseWalletProvider[]>(() => {
|
|
247
|
+
return Array.from(this.providers.values()).filter((p) => p.isConnected());
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Transport state for HSuite Native and P2P Native connections.
|
|
252
|
+
* Values: 'idle' | 'nostr-only' | 'upgrading' | 'p2p-connected' | 'p2p-failed'
|
|
253
|
+
*
|
|
254
|
+
* Checks both HSuite Native and P2P Native providers.
|
|
255
|
+
* Returns 'idle' for non-HSuite connections (WalletConnect, etc.)
|
|
256
|
+
*/
|
|
257
|
+
readonly transportState = computed<string>(() => {
|
|
258
|
+
// Check HSuite Native provider first
|
|
259
|
+
const hsuiteProvider = this.providers.get('hsuite-native') as HsuiteNativeProvider | undefined;
|
|
260
|
+
if (hsuiteProvider) {
|
|
261
|
+
const status = hsuiteProvider.status();
|
|
262
|
+
if (status === 'connecting' || status === 'connected') {
|
|
263
|
+
return hsuiteProvider.transportState();
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Check P2P Native provider (mobile-native)
|
|
268
|
+
const p2pProvider = this.providers.get('mobile-native') as P2PNativeProvider | undefined;
|
|
269
|
+
if (p2pProvider) {
|
|
270
|
+
const status = p2pProvider.status();
|
|
271
|
+
if (status === 'connecting' || status === 'connected') {
|
|
272
|
+
return p2pProvider.transportState();
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
return 'idle';
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Registers a wallet provider instance.
|
|
281
|
+
*
|
|
282
|
+
* @description
|
|
283
|
+
* Adds a provider to the service's internal registry. Once registered,
|
|
284
|
+
* the provider's accounts will be included in {@link allAccounts} and
|
|
285
|
+
* can be used for wallet operations.
|
|
286
|
+
*
|
|
287
|
+
* Built-in providers (HSuite Native, WalletConnect, P2P) are auto-registered.
|
|
288
|
+
* Use this method only for custom provider implementations.
|
|
289
|
+
*
|
|
290
|
+
* @param provider - The provider instance to register
|
|
291
|
+
*/
|
|
292
|
+
registerProvider(provider: BaseWalletProvider): void {
|
|
293
|
+
if (this.providers.has(provider.id)) {
|
|
294
|
+
logger.warn('Provider already registered', { providerId: provider.id });
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
this.providers.set(provider.id, provider);
|
|
299
|
+
this._providerIds.set(Array.from(this.providers.keys()));
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Unregisters a wallet provider.
|
|
304
|
+
*
|
|
305
|
+
* @description
|
|
306
|
+
* Removes a provider from the service's registry. The provider's accounts
|
|
307
|
+
* will no longer be included in {@link allAccounts}.
|
|
308
|
+
*
|
|
309
|
+
* @param providerId - The provider ID to unregister
|
|
310
|
+
*/
|
|
311
|
+
unregisterProvider(providerId: string): void {
|
|
312
|
+
this.providers.delete(providerId);
|
|
313
|
+
this._providerIds.set(Array.from(this.providers.keys()));
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Gets a specific provider by ID.
|
|
318
|
+
*
|
|
319
|
+
* @description
|
|
320
|
+
* Retrieves a registered provider instance for direct interaction.
|
|
321
|
+
* Useful for accessing provider-specific features not exposed through
|
|
322
|
+
* the unified interface.
|
|
323
|
+
*
|
|
324
|
+
* @param providerId - The provider ID (e.g., 'hsuite-native', 'walletconnect-v2')
|
|
325
|
+
*
|
|
326
|
+
* @returns The provider instance or undefined if not found
|
|
327
|
+
*/
|
|
328
|
+
getProvider(providerId: string): BaseWalletProvider | undefined {
|
|
329
|
+
return this.providers.get(providerId);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Gets all providers of a specific type.
|
|
334
|
+
*
|
|
335
|
+
* @description
|
|
336
|
+
* Filters providers by their type, useful when you need to work with
|
|
337
|
+
* a specific category of wallets.
|
|
338
|
+
*
|
|
339
|
+
* @param type - Provider type to filter by (e.g., 'hsuite-native', 'walletconnect-v2')
|
|
340
|
+
*
|
|
341
|
+
* @returns Array of providers matching the specified type
|
|
342
|
+
*/
|
|
343
|
+
getProvidersByType(type: ProviderType): BaseWalletProvider[] {
|
|
344
|
+
return Array.from(this.providers.values()).filter((p) => p.metadata.type === type);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Connects to a wallet using a specific provider.
|
|
349
|
+
*
|
|
350
|
+
* @description
|
|
351
|
+
* Initiates a wallet connection through the specified provider. The connection
|
|
352
|
+
* flow varies by provider type:
|
|
353
|
+
* - **HSuite Native**: Opens wallet window/tab or uses Nostr discovery
|
|
354
|
+
* - **WalletConnect**: Displays QR code for mobile wallet scanning
|
|
355
|
+
* - **P2P Native**: Displays QR code for direct P2P connection
|
|
356
|
+
*
|
|
357
|
+
* Upon successful connection, emits 'connected' and 'accountsUpdated' events
|
|
358
|
+
* via WalletEventBus.
|
|
359
|
+
*
|
|
360
|
+
* @param providerId - The provider ID to use for connection
|
|
361
|
+
* @param config - Connection configuration (varies by provider type)
|
|
362
|
+
*
|
|
363
|
+
* @throws {Error} If provider is not found
|
|
364
|
+
* @throws {Error} If connection fails or times out
|
|
365
|
+
*/
|
|
366
|
+
async connect(providerId: string, config: ConnectionConfig): Promise<void> {
|
|
367
|
+
const provider = this.providers.get(providerId);
|
|
368
|
+
if (!provider) {
|
|
369
|
+
throw new Error(`Provider ${providerId} not found`);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
await provider.connect(config);
|
|
373
|
+
|
|
374
|
+
const accounts = provider.accounts();
|
|
375
|
+
|
|
376
|
+
// Emit connection event
|
|
377
|
+
this.eventBus.connected.emit({
|
|
378
|
+
providerId,
|
|
379
|
+
providerType: provider.metadata.type as 'hsuite-native' | 'walletconnect-v2',
|
|
380
|
+
accounts,
|
|
381
|
+
timestamp: Date.now(),
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
// Emit accounts updated
|
|
385
|
+
this.eventBus.accountsUpdated.emit({
|
|
386
|
+
providerId,
|
|
387
|
+
accounts,
|
|
388
|
+
totalAccounts: this.allAccounts().length,
|
|
389
|
+
timestamp: Date.now(),
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
// Auto-select first account if none is active
|
|
393
|
+
if (!this._activeAccount() && provider.accounts().length > 0) {
|
|
394
|
+
this.setActiveAccount(provider.accounts()[0]);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* Disconnects a specific provider.
|
|
400
|
+
*
|
|
401
|
+
* @description
|
|
402
|
+
* Terminates the wallet connection for the specified provider. If the active
|
|
403
|
+
* account belonged to this provider, automatically selects another available
|
|
404
|
+
* account or clears the active account.
|
|
405
|
+
*
|
|
406
|
+
* @param providerId - The provider ID to disconnect
|
|
407
|
+
*
|
|
408
|
+
* @throws {Error} If provider is not found
|
|
409
|
+
*/
|
|
410
|
+
async disconnect(providerId: string): Promise<void> {
|
|
411
|
+
const provider = this.providers.get(providerId);
|
|
412
|
+
if (!provider) {
|
|
413
|
+
throw new Error(`Provider ${providerId} not found`);
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
await provider.disconnect();
|
|
417
|
+
|
|
418
|
+
// If the active account belonged to this provider, clear it
|
|
419
|
+
const active = this._activeAccount();
|
|
420
|
+
if (active && active.providerId === providerId) {
|
|
421
|
+
// Try to select another account from a different provider
|
|
422
|
+
const accounts = this.allAccounts();
|
|
423
|
+
const nextAccount = accounts.find((a) => a.providerId !== providerId);
|
|
424
|
+
this.setActiveAccount(nextAccount || null);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* Disconnects all connected providers.
|
|
430
|
+
*
|
|
431
|
+
* @description
|
|
432
|
+
* Terminates all wallet connections and clears the active account.
|
|
433
|
+
* Useful for logout flows or cleanup operations.
|
|
434
|
+
*/
|
|
435
|
+
async disconnectAll(): Promise<void> {
|
|
436
|
+
const disconnectPromises = Array.from(this.providers.values())
|
|
437
|
+
.filter((p) => p.isConnected())
|
|
438
|
+
.map((p) => p.disconnect());
|
|
439
|
+
|
|
440
|
+
await Promise.all(disconnectPromises);
|
|
441
|
+
this.setActiveAccount(null);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
/**
|
|
445
|
+
* Sets the active account for wallet operations.
|
|
446
|
+
*
|
|
447
|
+
* @description
|
|
448
|
+
* Changes the currently active account. All subsequent signing and transaction
|
|
449
|
+
* operations will use this account. Emits an 'accountChanged' event via
|
|
450
|
+
* WalletEventBus.
|
|
451
|
+
*
|
|
452
|
+
* @param account - The account to set as active, or null to clear
|
|
453
|
+
*/
|
|
454
|
+
setActiveAccount(account: UnifiedAccount | null): void {
|
|
455
|
+
const previous = this._activeAccount();
|
|
456
|
+
this._activeAccount.set(account);
|
|
457
|
+
|
|
458
|
+
// Emit account change event
|
|
459
|
+
this.eventBus.accountChanged.emit({
|
|
460
|
+
previousAccount: previous,
|
|
461
|
+
newAccount: account,
|
|
462
|
+
timestamp: Date.now(),
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
/**
|
|
467
|
+
* Signs a transaction using the active account.
|
|
468
|
+
*
|
|
469
|
+
* @description
|
|
470
|
+
* Requests the wallet to sign the provided transaction payload using the
|
|
471
|
+
* active account's private key. The transaction is not submitted to the
|
|
472
|
+
* network.
|
|
473
|
+
*
|
|
474
|
+
* @param payload - Serialized transaction payload to sign (format depends on ledger)
|
|
475
|
+
*
|
|
476
|
+
* @returns Promise resolving to sign result with signed payload and signature
|
|
477
|
+
*
|
|
478
|
+
* @throws {Error} If no active account is set
|
|
479
|
+
* @throws {Error} If provider is not found
|
|
480
|
+
* @throws {Error} If user rejects the signing request
|
|
481
|
+
*/
|
|
482
|
+
async signTransaction(payload: string): Promise<unknown> {
|
|
483
|
+
const account = this._activeAccount();
|
|
484
|
+
if (!account) {
|
|
485
|
+
throw new Error('No active account');
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
const provider = this.providers.get(account.providerId);
|
|
489
|
+
if (!provider) {
|
|
490
|
+
throw new Error(`Provider ${account.providerId} not found`);
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
return await provider.signTransaction({
|
|
494
|
+
accountAddress: account.address,
|
|
495
|
+
payload,
|
|
496
|
+
ledgerId: account.ledgerId,
|
|
497
|
+
networkId: account.networkId,
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
/**
|
|
502
|
+
* Submits a transaction using the active account.
|
|
503
|
+
*
|
|
504
|
+
* @description
|
|
505
|
+
* Signs and submits a transaction to the blockchain network. This is a two-step
|
|
506
|
+
* operation: sign then submit. For a single-prompt flow, use
|
|
507
|
+
* {@link signAndExecuteTransaction} instead.
|
|
508
|
+
*
|
|
509
|
+
* Supports batch transactions when isBatch is true.
|
|
510
|
+
*
|
|
511
|
+
* @param payload - Serialized transaction payload to submit
|
|
512
|
+
* @param options - Optional submission options
|
|
513
|
+
* @param options.isBatch - Whether this is a batch transaction
|
|
514
|
+
* @param options.batchKey - Unique key for batch grouping
|
|
515
|
+
* @param options.innerTransactions - Individual transactions within the batch
|
|
516
|
+
*
|
|
517
|
+
* @returns Promise resolving to submit result with transaction ID and hash
|
|
518
|
+
*
|
|
519
|
+
* @throws {Error} If no active account is set
|
|
520
|
+
* @throws {Error} If provider is not found
|
|
521
|
+
* @throws {Error} If user rejects or transaction fails
|
|
522
|
+
*/
|
|
523
|
+
async submitTransaction(
|
|
524
|
+
payload: string,
|
|
525
|
+
options?: {
|
|
526
|
+
isBatch?: boolean;
|
|
527
|
+
batchKey?: string;
|
|
528
|
+
innerTransactions?: Array<{ payload: string; description?: string }>;
|
|
529
|
+
},
|
|
530
|
+
): Promise<unknown> {
|
|
531
|
+
const account = this._activeAccount();
|
|
532
|
+
if (!account) {
|
|
533
|
+
throw new Error('No active account');
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
const provider = this.providers.get(account.providerId);
|
|
537
|
+
if (!provider) {
|
|
538
|
+
throw new Error(`Provider ${account.providerId} not found`);
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
return await provider.submitTransaction({
|
|
542
|
+
accountAddress: account.address,
|
|
543
|
+
payload,
|
|
544
|
+
ledgerId: account.ledgerId,
|
|
545
|
+
networkId: account.networkId,
|
|
546
|
+
...options,
|
|
547
|
+
});
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
/**
|
|
551
|
+
* Signs an arbitrary message using the active account.
|
|
552
|
+
*
|
|
553
|
+
* @description
|
|
554
|
+
* Requests the wallet to sign a message for authentication or verification
|
|
555
|
+
* purposes (e.g., DAO votes, login challenges). The message is not a
|
|
556
|
+
* blockchain transaction.
|
|
557
|
+
*
|
|
558
|
+
* @param message - The message to sign (plain text or base64 encoded)
|
|
559
|
+
* @param encoding - Message encoding: 'utf-8' (default) or 'base64'
|
|
560
|
+
*
|
|
561
|
+
* @returns Promise resolving to sign result with signature and public key
|
|
562
|
+
*
|
|
563
|
+
* @throws {Error} If no active account is set
|
|
564
|
+
* @throws {Error} If provider is not found
|
|
565
|
+
* @throws {Error} If user rejects the signing request
|
|
566
|
+
*/
|
|
567
|
+
async signMessage(message: string, encoding?: 'utf-8' | 'base64'): Promise<unknown> {
|
|
568
|
+
const account = this._activeAccount();
|
|
569
|
+
if (!account) {
|
|
570
|
+
throw new Error('No active account');
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
const provider = this.providers.get(account.providerId);
|
|
574
|
+
if (!provider) {
|
|
575
|
+
throw new Error(`Provider ${account.providerId} not found`);
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
return await provider.signMessage({
|
|
579
|
+
accountAddress: account.address,
|
|
580
|
+
message,
|
|
581
|
+
encoding,
|
|
582
|
+
ledgerId: account.ledgerId,
|
|
583
|
+
networkId: account.networkId,
|
|
584
|
+
});
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
/**
|
|
588
|
+
* Signs and executes a transaction in a single prompt.
|
|
589
|
+
*
|
|
590
|
+
* @description
|
|
591
|
+
* Performs atomic sign-and-submit in a single wallet prompt. This is the
|
|
592
|
+
* **recommended method** for most transaction submissions as it:
|
|
593
|
+
* - Only requires one user approval (better UX)
|
|
594
|
+
* - Matches WalletConnect's `hedera_signAndExecuteTransaction` behavior
|
|
595
|
+
* - Provides atomic operation (sign+submit happen together)
|
|
596
|
+
*
|
|
597
|
+
* For providers that don't support native signAndExecute, this method
|
|
598
|
+
* falls back to separate sign and submit calls.
|
|
599
|
+
*
|
|
600
|
+
* @param payload - Serialized transaction payload
|
|
601
|
+
* @param options - Optional provider-specific options
|
|
602
|
+
*
|
|
603
|
+
* @returns Promise resolving to execution result with transaction ID and hash
|
|
604
|
+
*
|
|
605
|
+
* @throws {Error} If no active account is set
|
|
606
|
+
* @throws {Error} If provider is not found
|
|
607
|
+
* @throws {Error} If user rejects or transaction fails
|
|
608
|
+
*/
|
|
609
|
+
async signAndExecuteTransaction(
|
|
610
|
+
payload: string,
|
|
611
|
+
options?: Record<string, unknown>,
|
|
612
|
+
): Promise<unknown> {
|
|
613
|
+
const account = this._activeAccount();
|
|
614
|
+
if (!account) {
|
|
615
|
+
throw new Error('No active account');
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
const provider = this.providers.get(account.providerId);
|
|
619
|
+
if (!provider) {
|
|
620
|
+
throw new Error(`Provider ${account.providerId} not found`);
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
// Check if provider has native signAndExecute support
|
|
624
|
+
if (
|
|
625
|
+
typeof (provider as any as { signAndExecuteTransaction: (payload: any) => Promise<any> })
|
|
626
|
+
.signAndExecuteTransaction === 'function'
|
|
627
|
+
) {
|
|
628
|
+
return await (
|
|
629
|
+
provider as any as { signAndExecuteTransaction: (payload: any) => Promise<any> }
|
|
630
|
+
).signAndExecuteTransaction({
|
|
631
|
+
accountAddress: account.address,
|
|
632
|
+
payload,
|
|
633
|
+
ledgerId: account.ledgerId,
|
|
634
|
+
networkId: account.networkId,
|
|
635
|
+
...options,
|
|
636
|
+
});
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
// Fallback: sign then submit
|
|
640
|
+
const signResult = await provider.signTransaction({
|
|
641
|
+
accountAddress: account.address,
|
|
642
|
+
payload,
|
|
643
|
+
ledgerId: account.ledgerId,
|
|
644
|
+
networkId: account.networkId,
|
|
645
|
+
...options,
|
|
646
|
+
});
|
|
647
|
+
|
|
648
|
+
return await provider.submitTransaction({
|
|
649
|
+
accountAddress: account.address,
|
|
650
|
+
payload: signResult.signedPayload || payload,
|
|
651
|
+
ledgerId: account.ledgerId,
|
|
652
|
+
networkId: account.networkId,
|
|
653
|
+
...options,
|
|
654
|
+
});
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
/**
|
|
658
|
+
* Gets all active sessions across all providers.
|
|
659
|
+
*
|
|
660
|
+
* @description
|
|
661
|
+
* Returns detailed session information for all connected providers. For
|
|
662
|
+
* WalletConnect, each session is returned separately. For other providers,
|
|
663
|
+
* a single session entry represents the connection.
|
|
664
|
+
*
|
|
665
|
+
* @returns Array of session objects with provider and account information
|
|
666
|
+
*/
|
|
667
|
+
getActiveSessions(): Array<{
|
|
668
|
+
providerId: string;
|
|
669
|
+
providerType: string;
|
|
670
|
+
providerName: string;
|
|
671
|
+
accounts: import('../models/unified-account.model').UnifiedAccount[];
|
|
672
|
+
metadata: any;
|
|
673
|
+
}> {
|
|
674
|
+
const sessions: Array<{
|
|
675
|
+
providerId: string;
|
|
676
|
+
providerType: string;
|
|
677
|
+
providerName: string;
|
|
678
|
+
accounts: import('../models/unified-account.model').UnifiedAccount[];
|
|
679
|
+
metadata: any;
|
|
680
|
+
}> = [];
|
|
681
|
+
|
|
682
|
+
for (const provider of this.providers.values()) {
|
|
683
|
+
const accounts = provider.accounts();
|
|
684
|
+
|
|
685
|
+
if (accounts.length > 0) {
|
|
686
|
+
// For WalletConnect, get detailed session info
|
|
687
|
+
if (provider.id === 'walletconnect-v2' && 'getActiveSessions' in provider) {
|
|
688
|
+
const wcProvider = provider as any;
|
|
689
|
+
const wcSessions = (
|
|
690
|
+
wcProvider as { getActiveSessions: () => unknown[] }
|
|
691
|
+
).getActiveSessions();
|
|
692
|
+
|
|
693
|
+
for (const wcSession of wcSessions) {
|
|
694
|
+
sessions.push({
|
|
695
|
+
providerId: provider.id,
|
|
696
|
+
providerType: provider.metadata.type,
|
|
697
|
+
providerName: provider.metadata.name,
|
|
698
|
+
accounts: (wcSession as { accounts?: any[] }).accounts || [],
|
|
699
|
+
metadata: {
|
|
700
|
+
sessionKey: (wcSession as { sessionKey?: string }).sessionKey,
|
|
701
|
+
ledgerId: (wcSession as { ledgerId?: string }).ledgerId,
|
|
702
|
+
networkId: (wcSession as { networkId?: string }).networkId,
|
|
703
|
+
topic: (wcSession as { topic?: string }).topic,
|
|
704
|
+
},
|
|
705
|
+
});
|
|
706
|
+
}
|
|
707
|
+
} else {
|
|
708
|
+
// For HSuite Native and other providers, create a single session entry
|
|
709
|
+
sessions.push({
|
|
710
|
+
providerId: provider.id,
|
|
711
|
+
providerType: provider.metadata.type,
|
|
712
|
+
providerName: provider.metadata.name,
|
|
713
|
+
accounts,
|
|
714
|
+
metadata: {
|
|
715
|
+
type: provider.metadata.type,
|
|
716
|
+
},
|
|
717
|
+
});
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
return sessions;
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
/**
|
|
726
|
+
* Disconnects a specific session from a provider.
|
|
727
|
+
*
|
|
728
|
+
* @description
|
|
729
|
+
* For WalletConnect which supports multiple concurrent sessions, this allows
|
|
730
|
+
* disconnecting a specific session without affecting others. For other
|
|
731
|
+
* providers, this is equivalent to calling {@link disconnect}.
|
|
732
|
+
*
|
|
733
|
+
* @param providerId - The provider ID
|
|
734
|
+
* @param sessionKey - Optional session key (required for WalletConnect multi-session)
|
|
735
|
+
*
|
|
736
|
+
* @throws {Error} If provider is not found
|
|
737
|
+
*/
|
|
738
|
+
async disconnectSession(providerId: string, sessionKey?: string): Promise<void> {
|
|
739
|
+
const provider = this.providers.get(providerId);
|
|
740
|
+
if (!provider) {
|
|
741
|
+
throw new Error(`Provider ${providerId} not found`);
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
// If provider supports session-level disconnect (WalletConnect), use it
|
|
745
|
+
if ('disconnectSession' in provider && sessionKey) {
|
|
746
|
+
const wcProvider = provider as any;
|
|
747
|
+
await (wcProvider as { disconnectSession: (key: string) => Promise<void> }).disconnectSession(
|
|
748
|
+
sessionKey,
|
|
749
|
+
);
|
|
750
|
+
} else {
|
|
751
|
+
// Otherwise, disconnect the entire provider
|
|
752
|
+
await provider.disconnect();
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
// Emit disconnection event
|
|
756
|
+
this.eventBus.disconnected.emit({
|
|
757
|
+
providerId,
|
|
758
|
+
providerType: provider.metadata.type,
|
|
759
|
+
sessionKey,
|
|
760
|
+
reason: 'user_initiated',
|
|
761
|
+
timestamp: Date.now(),
|
|
762
|
+
});
|
|
763
|
+
|
|
764
|
+
// Update active account if needed
|
|
765
|
+
const active = this._activeAccount();
|
|
766
|
+
if (active && active.providerId === providerId) {
|
|
767
|
+
const accounts = this.allAccounts();
|
|
768
|
+
const nextAccount = accounts.find(
|
|
769
|
+
(a) =>
|
|
770
|
+
a.providerId !== providerId ||
|
|
771
|
+
(sessionKey && (a.metadata as { sessionKey?: string })?.sessionKey !== sessionKey),
|
|
772
|
+
);
|
|
773
|
+
this.setActiveAccount(nextAccount || null);
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
/**
|
|
778
|
+
* Check if any provider is connected
|
|
779
|
+
*/
|
|
780
|
+
isAnyConnected(): boolean {
|
|
781
|
+
return this.connectedProviders().length > 0;
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
/**
|
|
785
|
+
* Alias for isAnyConnected() - convenience method
|
|
786
|
+
*/
|
|
787
|
+
isConnected(): boolean {
|
|
788
|
+
return this.isAnyConnected();
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
/**
|
|
792
|
+
* Get account by ID
|
|
793
|
+
* @param accountId
|
|
794
|
+
*/
|
|
795
|
+
getAccountById(accountId: string): UnifiedAccount | undefined {
|
|
796
|
+
return this.allAccounts().find((a) => a.id === accountId);
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
/**
|
|
800
|
+
* Get list of unique ledger IDs from connected accounts
|
|
801
|
+
* @returns Array of ledger IDs (e.g., ['hedera', 'xrpl'])
|
|
802
|
+
*/
|
|
803
|
+
getConnectedLedgers(): string[] {
|
|
804
|
+
const accounts = this.allAccounts();
|
|
805
|
+
const ledgerIds = new Set(accounts.map((a) => a.ledgerId).filter(Boolean));
|
|
806
|
+
return Array.from(ledgerIds);
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
/**
|
|
810
|
+
* Get accounts filtered by ledger ID
|
|
811
|
+
* @param ledgerId - Ledger identifier (e.g., 'hedera', 'xrpl')
|
|
812
|
+
* @returns Array of accounts for the specified ledger
|
|
813
|
+
*/
|
|
814
|
+
getAccountsByLedger(ledgerId: string): UnifiedAccount[] {
|
|
815
|
+
return this.allAccounts().filter((a) => a.ledgerId === ledgerId);
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
/**
|
|
819
|
+
* Switch to an account by its ID
|
|
820
|
+
* @param accountId - The account ID to switch to
|
|
821
|
+
* @returns true if account was found and switched, false otherwise
|
|
822
|
+
*/
|
|
823
|
+
switchAccount(accountId: string): boolean {
|
|
824
|
+
const account = this.getAccountById(accountId);
|
|
825
|
+
if (!account) {
|
|
826
|
+
logger.warn('Account not found', { accountId });
|
|
827
|
+
return false;
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
this.setActiveAccount(account);
|
|
831
|
+
return true;
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
/**
|
|
835
|
+
* Get the primary account for a specific ledger
|
|
836
|
+
* Returns the first account found for the specified ledger
|
|
837
|
+
* @param ledgerId - Ledger identifier (e.g., 'hedera', 'xrpl')
|
|
838
|
+
* @returns The first account for the ledger, or undefined
|
|
839
|
+
*/
|
|
840
|
+
getPrimaryAccountForLedger(ledgerId: string): UnifiedAccount | undefined {
|
|
841
|
+
return this.allAccounts().find((a) => a.ledgerId === ledgerId);
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
/**
|
|
845
|
+
* Check if a specific ledger has connected accounts
|
|
846
|
+
* @param ledgerId - Ledger identifier (e.g., 'hedera', 'xrpl')
|
|
847
|
+
* @returns true if at least one account exists for the ledger
|
|
848
|
+
*/
|
|
849
|
+
hasAccountsForLedger(ledgerId: string): boolean {
|
|
850
|
+
return this.getAccountsByLedger(ledgerId).length > 0;
|
|
851
|
+
}
|
|
852
|
+
}
|