@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.
Files changed (276) hide show
  1. package/README.md +48 -0
  2. package/USAGE_EXAMPLES.md +476 -0
  3. package/assets/wallets/extension.svg +7 -0
  4. package/assets/wallets/hashpack.svg +6 -0
  5. package/assets/wallets/hsuite.svg +11 -0
  6. package/assets/wallets/kabila.svg +11 -0
  7. package/assets/wallets/walletconnect.svg +13 -0
  8. package/coverage/base.css +224 -0
  9. package/coverage/block-navigation.js +87 -0
  10. package/coverage/coverage-summary.json +50 -0
  11. package/coverage/favicon.png +0 -0
  12. package/coverage/index.html +476 -0
  13. package/coverage/lcov-report/base.css +224 -0
  14. package/coverage/lcov-report/block-navigation.js +87 -0
  15. package/coverage/lcov-report/favicon.png +0 -0
  16. package/coverage/lcov-report/index.html +476 -0
  17. package/coverage/lcov-report/lib/components/account-selector/account-actions/account-actions.component.ts.html +868 -0
  18. package/coverage/lcov-report/lib/components/account-selector/account-actions/index.html +116 -0
  19. package/coverage/lcov-report/lib/components/account-selector/account-filter/account-filter.component.ts.html +1288 -0
  20. package/coverage/lcov-report/lib/components/account-selector/account-filter/index.html +116 -0
  21. package/coverage/lcov-report/lib/components/account-selector/account-formatting.service.ts.html +685 -0
  22. package/coverage/lcov-report/lib/components/account-selector/account-grouping.service.ts.html +766 -0
  23. package/coverage/lcov-report/lib/components/account-selector/account-list/account-list.component.ts.html +1495 -0
  24. package/coverage/lcov-report/lib/components/account-selector/account-list/index.html +116 -0
  25. package/coverage/lcov-report/lib/components/account-selector/account-selector.component.ts.html +1495 -0
  26. package/coverage/lcov-report/lib/components/account-selector/account-selector.service.ts.html +1588 -0
  27. package/coverage/lcov-report/lib/components/account-selector/index.html +161 -0
  28. package/coverage/lcov-report/lib/components/wallet-account-display/index.html +116 -0
  29. package/coverage/lcov-report/lib/components/wallet-account-display/wallet-account-display.component.ts.html +505 -0
  30. package/coverage/lcov-report/lib/components/wallet-connect-button/index.html +116 -0
  31. package/coverage/lcov-report/lib/components/wallet-connect-button/wallet-connect-button.component.ts.html +805 -0
  32. package/coverage/lcov-report/lib/components/wallet-connect-prompt/index.html +116 -0
  33. package/coverage/lcov-report/lib/components/wallet-connect-prompt/wallet-connect-prompt.component.ts.html +409 -0
  34. package/coverage/lcov-report/lib/components/wallet-connected-guard/index.html +116 -0
  35. package/coverage/lcov-report/lib/components/wallet-connected-guard/wallet-connected-guard.component.ts.html +304 -0
  36. package/coverage/lcov-report/lib/components/wallet-connection-modal/connection-method-step/connection-method-step.component.ts.html +436 -0
  37. package/coverage/lcov-report/lib/components/wallet-connection-modal/connection-method-step/index.html +116 -0
  38. package/coverage/lcov-report/lib/components/wallet-connection-modal/index.html +116 -0
  39. package/coverage/lcov-report/lib/components/wallet-connection-modal/qr-pairing-step/index.html +116 -0
  40. package/coverage/lcov-report/lib/components/wallet-connection-modal/qr-pairing-step/qr-pairing-step.component.ts.html +2287 -0
  41. package/coverage/lcov-report/lib/components/wallet-connection-modal/wallet-connection-modal.component.ts.html +2275 -0
  42. package/coverage/lcov-report/lib/components/wallet-session-display/index.html +116 -0
  43. package/coverage/lcov-report/lib/components/wallet-session-display/wallet-session-display.component.ts.html +676 -0
  44. package/coverage/lcov-report/lib/components/wallet-transaction-status/index.html +116 -0
  45. package/coverage/lcov-report/lib/components/wallet-transaction-status/wallet-transaction-status.component.ts.html +703 -0
  46. package/coverage/lcov-report/lib/directives/index.html +146 -0
  47. package/coverage/lcov-report/lib/directives/wallet-connected.directive.ts.html +670 -0
  48. package/coverage/lcov-report/lib/directives/wallet-context.directive.ts.html +547 -0
  49. package/coverage/lcov-report/lib/directives/wallet-events.directive.ts.html +781 -0
  50. package/coverage/lcov-report/lib/hsuite-wallet.module.ts.html +715 -0
  51. package/coverage/lcov-report/lib/index.html +116 -0
  52. package/coverage/lcov-report/lib/models/connection-config.model.ts.html +280 -0
  53. package/coverage/lcov-report/lib/models/index.html +131 -0
  54. package/coverage/lcov-report/lib/models/provider-types.ts.html +577 -0
  55. package/coverage/lcov-report/lib/providers/base-wallet-provider.ts.html +1138 -0
  56. package/coverage/lcov-report/lib/providers/hsuite-native/channel-client.service.ts.html +2671 -0
  57. package/coverage/lcov-report/lib/providers/hsuite-native/index.html +116 -0
  58. package/coverage/lcov-report/lib/providers/hsuite-native-provider.ts.html +2347 -0
  59. package/coverage/lcov-report/lib/providers/index.html +146 -0
  60. package/coverage/lcov-report/lib/providers/p2p-native/index.html +131 -0
  61. package/coverage/lcov-report/lib/providers/p2p-native/p2p-native.provider.ts.html +2254 -0
  62. package/coverage/lcov-report/lib/providers/p2p-native/p2p-session-manager.ts.html +2170 -0
  63. package/coverage/lcov-report/lib/providers/wallet-error-handler.ts.html +1132 -0
  64. package/coverage/lcov-report/lib/providers/walletconnect/core/index.html +176 -0
  65. package/coverage/lcov-report/lib/providers/walletconnect/core/session-health.ts.html +673 -0
  66. package/coverage/lcov-report/lib/providers/walletconnect/core/walletconnect-client-manager.ts.html +1177 -0
  67. package/coverage/lcov-report/lib/providers/walletconnect/core/walletconnect-provider.ts.html +2563 -0
  68. package/coverage/lcov-report/lib/providers/walletconnect/core/walletconnect-session-store.ts.html +904 -0
  69. package/coverage/lcov-report/lib/providers/walletconnect/core/walletconnect-signing-orchestrator.ts.html +982 -0
  70. package/coverage/lcov-report/lib/providers/walletconnect/signers/hedera-signer.ts.html +1915 -0
  71. package/coverage/lcov-report/lib/providers/walletconnect/signers/index.html +146 -0
  72. package/coverage/lcov-report/lib/providers/walletconnect/signers/signer-factory.ts.html +445 -0
  73. package/coverage/lcov-report/lib/providers/walletconnect/signers/xrpl-signer.ts.html +1519 -0
  74. package/coverage/lcov-report/lib/services/index.html +191 -0
  75. package/coverage/lcov-report/lib/services/logger.service.ts.html +463 -0
  76. package/coverage/lcov-report/lib/services/transaction-builders/base-transaction-builder.service.ts.html +1840 -0
  77. package/coverage/lcov-report/lib/services/transaction-builders/hedera-amount-utils.ts.html +337 -0
  78. package/coverage/lcov-report/lib/services/transaction-builders/hedera-transaction-builder.service.ts.html +3940 -0
  79. package/coverage/lcov-report/lib/services/transaction-builders/index.html +161 -0
  80. package/coverage/lcov-report/lib/services/transaction-builders/xrpl-transaction-builder.service.ts.html +2581 -0
  81. package/coverage/lcov-report/lib/services/transaction.service.ts.html +1123 -0
  82. package/coverage/lcov-report/lib/services/unified-wallet.service.ts.html +2641 -0
  83. package/coverage/lcov-report/lib/services/wallet-context.service.ts.html +637 -0
  84. package/coverage/lcov-report/lib/services/wallet-event-bus.service.ts.html +643 -0
  85. package/coverage/lcov-report/lib/services/wallet-providers.service.ts.html +496 -0
  86. package/coverage/lcov-report/lib/transports/chrome-extension-transport.ts.html +823 -0
  87. package/coverage/lcov-report/lib/transports/index.html +116 -0
  88. package/coverage/lcov-report/lib/utils/index.html +116 -0
  89. package/coverage/lcov-report/lib/utils/ledger-icons.util.ts.html +319 -0
  90. package/coverage/lcov-report/prettify.css +1 -0
  91. package/coverage/lcov-report/prettify.js +2 -0
  92. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  93. package/coverage/lcov-report/sorter.js +210 -0
  94. package/coverage/lcov.info +19252 -0
  95. package/coverage/lib/components/account-selector/account-actions/account-actions.component.ts.html +868 -0
  96. package/coverage/lib/components/account-selector/account-actions/index.html +116 -0
  97. package/coverage/lib/components/account-selector/account-filter/account-filter.component.ts.html +1288 -0
  98. package/coverage/lib/components/account-selector/account-filter/index.html +116 -0
  99. package/coverage/lib/components/account-selector/account-formatting.service.ts.html +685 -0
  100. package/coverage/lib/components/account-selector/account-grouping.service.ts.html +766 -0
  101. package/coverage/lib/components/account-selector/account-list/account-list.component.ts.html +1495 -0
  102. package/coverage/lib/components/account-selector/account-list/index.html +116 -0
  103. package/coverage/lib/components/account-selector/account-selector.component.ts.html +1495 -0
  104. package/coverage/lib/components/account-selector/account-selector.service.ts.html +1588 -0
  105. package/coverage/lib/components/account-selector/index.html +161 -0
  106. package/coverage/lib/components/wallet-account-display/index.html +116 -0
  107. package/coverage/lib/components/wallet-account-display/wallet-account-display.component.ts.html +505 -0
  108. package/coverage/lib/components/wallet-connect-button/index.html +116 -0
  109. package/coverage/lib/components/wallet-connect-button/wallet-connect-button.component.ts.html +805 -0
  110. package/coverage/lib/components/wallet-connect-prompt/index.html +116 -0
  111. package/coverage/lib/components/wallet-connect-prompt/wallet-connect-prompt.component.ts.html +409 -0
  112. package/coverage/lib/components/wallet-connected-guard/index.html +116 -0
  113. package/coverage/lib/components/wallet-connected-guard/wallet-connected-guard.component.ts.html +304 -0
  114. package/coverage/lib/components/wallet-connection-modal/connection-method-step/connection-method-step.component.ts.html +436 -0
  115. package/coverage/lib/components/wallet-connection-modal/connection-method-step/index.html +116 -0
  116. package/coverage/lib/components/wallet-connection-modal/index.html +116 -0
  117. package/coverage/lib/components/wallet-connection-modal/qr-pairing-step/index.html +116 -0
  118. package/coverage/lib/components/wallet-connection-modal/qr-pairing-step/qr-pairing-step.component.ts.html +2287 -0
  119. package/coverage/lib/components/wallet-connection-modal/wallet-connection-modal.component.ts.html +2275 -0
  120. package/coverage/lib/components/wallet-session-display/index.html +116 -0
  121. package/coverage/lib/components/wallet-session-display/wallet-session-display.component.ts.html +676 -0
  122. package/coverage/lib/components/wallet-transaction-status/index.html +116 -0
  123. package/coverage/lib/components/wallet-transaction-status/wallet-transaction-status.component.ts.html +703 -0
  124. package/coverage/lib/directives/index.html +146 -0
  125. package/coverage/lib/directives/wallet-connected.directive.ts.html +670 -0
  126. package/coverage/lib/directives/wallet-context.directive.ts.html +547 -0
  127. package/coverage/lib/directives/wallet-events.directive.ts.html +781 -0
  128. package/coverage/lib/hsuite-wallet.module.ts.html +715 -0
  129. package/coverage/lib/index.html +116 -0
  130. package/coverage/lib/models/connection-config.model.ts.html +280 -0
  131. package/coverage/lib/models/index.html +131 -0
  132. package/coverage/lib/models/provider-types.ts.html +577 -0
  133. package/coverage/lib/providers/base-wallet-provider.ts.html +1138 -0
  134. package/coverage/lib/providers/hsuite-native/channel-client.service.ts.html +2671 -0
  135. package/coverage/lib/providers/hsuite-native/index.html +116 -0
  136. package/coverage/lib/providers/hsuite-native-provider.ts.html +2347 -0
  137. package/coverage/lib/providers/index.html +146 -0
  138. package/coverage/lib/providers/p2p-native/index.html +131 -0
  139. package/coverage/lib/providers/p2p-native/p2p-native.provider.ts.html +2254 -0
  140. package/coverage/lib/providers/p2p-native/p2p-session-manager.ts.html +2170 -0
  141. package/coverage/lib/providers/wallet-error-handler.ts.html +1132 -0
  142. package/coverage/lib/providers/walletconnect/core/index.html +176 -0
  143. package/coverage/lib/providers/walletconnect/core/session-health.ts.html +673 -0
  144. package/coverage/lib/providers/walletconnect/core/walletconnect-client-manager.ts.html +1177 -0
  145. package/coverage/lib/providers/walletconnect/core/walletconnect-provider.ts.html +2563 -0
  146. package/coverage/lib/providers/walletconnect/core/walletconnect-session-store.ts.html +904 -0
  147. package/coverage/lib/providers/walletconnect/core/walletconnect-signing-orchestrator.ts.html +982 -0
  148. package/coverage/lib/providers/walletconnect/signers/hedera-signer.ts.html +1915 -0
  149. package/coverage/lib/providers/walletconnect/signers/index.html +146 -0
  150. package/coverage/lib/providers/walletconnect/signers/signer-factory.ts.html +445 -0
  151. package/coverage/lib/providers/walletconnect/signers/xrpl-signer.ts.html +1519 -0
  152. package/coverage/lib/services/index.html +191 -0
  153. package/coverage/lib/services/logger.service.ts.html +463 -0
  154. package/coverage/lib/services/transaction-builders/base-transaction-builder.service.ts.html +1840 -0
  155. package/coverage/lib/services/transaction-builders/hedera-amount-utils.ts.html +337 -0
  156. package/coverage/lib/services/transaction-builders/hedera-transaction-builder.service.ts.html +3940 -0
  157. package/coverage/lib/services/transaction-builders/index.html +161 -0
  158. package/coverage/lib/services/transaction-builders/xrpl-transaction-builder.service.ts.html +2581 -0
  159. package/coverage/lib/services/transaction.service.ts.html +1123 -0
  160. package/coverage/lib/services/unified-wallet.service.ts.html +2641 -0
  161. package/coverage/lib/services/wallet-context.service.ts.html +637 -0
  162. package/coverage/lib/services/wallet-event-bus.service.ts.html +643 -0
  163. package/coverage/lib/services/wallet-providers.service.ts.html +496 -0
  164. package/coverage/lib/transports/chrome-extension-transport.ts.html +823 -0
  165. package/coverage/lib/transports/index.html +116 -0
  166. package/coverage/lib/utils/index.html +116 -0
  167. package/coverage/lib/utils/ledger-icons.util.ts.html +319 -0
  168. package/coverage/prettify.css +1 -0
  169. package/coverage/prettify.js +2 -0
  170. package/coverage/sort-arrow-sprite.png +0 -0
  171. package/coverage/sorter.js +210 -0
  172. package/dist/README.md +48 -0
  173. package/dist/fesm2022/hsuite-native-connect-angular.mjs +14592 -0
  174. package/dist/fesm2022/hsuite-native-connect-angular.mjs.map +1 -0
  175. package/dist/index.d.ts +6949 -0
  176. package/examples/minimal-connect.ts +178 -0
  177. package/examples/multi-protocol.ts +495 -0
  178. package/examples/transaction-signing.ts +361 -0
  179. package/jest.config.json +45 -0
  180. package/karma.conf.js +42 -0
  181. package/ng-package.json +20 -0
  182. package/package.json +60 -0
  183. package/src/index.ts +203 -0
  184. package/src/lib/components/account-selector/account-actions/account-actions.component.ts +261 -0
  185. package/src/lib/components/account-selector/account-filter/account-filter.component.ts +401 -0
  186. package/src/lib/components/account-selector/account-formatting.service.ts +200 -0
  187. package/src/lib/components/account-selector/account-grouping.service.ts +227 -0
  188. package/src/lib/components/account-selector/account-list/account-list.component.ts +470 -0
  189. package/src/lib/components/account-selector/account-selector.component.html +135 -0
  190. package/src/lib/components/account-selector/account-selector.component.scss +2039 -0
  191. package/src/lib/components/account-selector/account-selector.component.ts +470 -0
  192. package/src/lib/components/account-selector/account-selector.service.ts +501 -0
  193. package/src/lib/components/wallet-account-display/wallet-account-display.component.html +34 -0
  194. package/src/lib/components/wallet-account-display/wallet-account-display.component.scss +99 -0
  195. package/src/lib/components/wallet-account-display/wallet-account-display.component.ts +140 -0
  196. package/src/lib/components/wallet-connect-button/wallet-connect-button.component.html +14 -0
  197. package/src/lib/components/wallet-connect-button/wallet-connect-button.component.scss +272 -0
  198. package/src/lib/components/wallet-connect-button/wallet-connect-button.component.ts +240 -0
  199. package/src/lib/components/wallet-connect-prompt/wallet-connect-prompt.component.html +24 -0
  200. package/src/lib/components/wallet-connect-prompt/wallet-connect-prompt.component.scss +50 -0
  201. package/src/lib/components/wallet-connect-prompt/wallet-connect-prompt.component.ts +108 -0
  202. package/src/lib/components/wallet-connected-guard/wallet-connected-guard.component.html +24 -0
  203. package/src/lib/components/wallet-connected-guard/wallet-connected-guard.component.ts +73 -0
  204. package/src/lib/components/wallet-connection-modal/connection-method-step/connection-method-step.component.html +56 -0
  205. package/src/lib/components/wallet-connection-modal/connection-method-step/connection-method-step.component.scss +218 -0
  206. package/src/lib/components/wallet-connection-modal/connection-method-step/connection-method-step.component.ts +117 -0
  207. package/src/lib/components/wallet-connection-modal/qr-pairing-step/qr-pairing-step.component.html +94 -0
  208. package/src/lib/components/wallet-connection-modal/qr-pairing-step/qr-pairing-step.component.scss +272 -0
  209. package/src/lib/components/wallet-connection-modal/qr-pairing-step/qr-pairing-step.component.ts +734 -0
  210. package/src/lib/components/wallet-connection-modal/wallet-connection-modal.component.html +197 -0
  211. package/src/lib/components/wallet-connection-modal/wallet-connection-modal.component.scss +678 -0
  212. package/src/lib/components/wallet-connection-modal/wallet-connection-modal.component.ts +730 -0
  213. package/src/lib/components/wallet-session-display/wallet-session-display.component.html +110 -0
  214. package/src/lib/components/wallet-session-display/wallet-session-display.component.scss +179 -0
  215. package/src/lib/components/wallet-session-display/wallet-session-display.component.ts +197 -0
  216. package/src/lib/components/wallet-transaction-status/wallet-transaction-status.component.html +65 -0
  217. package/src/lib/components/wallet-transaction-status/wallet-transaction-status.component.scss +254 -0
  218. package/src/lib/components/wallet-transaction-status/wallet-transaction-status.component.ts +206 -0
  219. package/src/lib/directives/wallet-connected.directive.ts +195 -0
  220. package/src/lib/directives/wallet-context.directive.ts +154 -0
  221. package/src/lib/directives/wallet-events.directive.ts +232 -0
  222. package/src/lib/hsuite-wallet.module.ts +210 -0
  223. package/src/lib/models/connection-config.model.ts +65 -0
  224. package/src/lib/models/provider-types.ts +164 -0
  225. package/src/lib/models/unified-account.model.ts +76 -0
  226. package/src/lib/models/wallet-context.model.ts +121 -0
  227. package/src/lib/models/wallet-events.model.ts +158 -0
  228. package/src/lib/providers/base-wallet-provider.ts +351 -0
  229. package/src/lib/providers/hsuite-native/channel-client.service.spec.ts +73 -0
  230. package/src/lib/providers/hsuite-native/channel-client.service.ts +862 -0
  231. package/src/lib/providers/hsuite-native/index.ts +8 -0
  232. package/src/lib/providers/hsuite-native-provider.ts +754 -0
  233. package/src/lib/providers/mobile-native/mobile-native.provider.spec.ts +19 -0
  234. package/src/lib/providers/p2p-native/index.ts +30 -0
  235. package/src/lib/providers/p2p-native/p2p-native.provider.spec.ts +523 -0
  236. package/src/lib/providers/p2p-native/p2p-native.provider.ts +723 -0
  237. package/src/lib/providers/p2p-native/p2p-session-manager.ts +695 -0
  238. package/src/lib/providers/wallet-error-handler.ts +349 -0
  239. package/src/lib/providers/walletconnect/core/base-signer.interface.ts +122 -0
  240. package/src/lib/providers/walletconnect/core/session-health.ts +196 -0
  241. package/src/lib/providers/walletconnect/core/walletconnect-client-manager.ts +364 -0
  242. package/src/lib/providers/walletconnect/core/walletconnect-provider.integration.spec.ts +348 -0
  243. package/src/lib/providers/walletconnect/core/walletconnect-provider.ts +826 -0
  244. package/src/lib/providers/walletconnect/core/walletconnect-session-store.ts +273 -0
  245. package/src/lib/providers/walletconnect/core/walletconnect-signing-orchestrator.ts +299 -0
  246. package/src/lib/providers/walletconnect/core/walletconnect-types.ts +48 -0
  247. package/src/lib/providers/walletconnect/index.ts +33 -0
  248. package/src/lib/providers/walletconnect/signers/hedera-signer.spec.ts +367 -0
  249. package/src/lib/providers/walletconnect/signers/hedera-signer.ts +610 -0
  250. package/src/lib/providers/walletconnect/signers/signer-factory.spec.ts +62 -0
  251. package/src/lib/providers/walletconnect/signers/signer-factory.ts +120 -0
  252. package/src/lib/providers/walletconnect/signers/xrpl-signer.spec.ts +296 -0
  253. package/src/lib/providers/walletconnect/signers/xrpl-signer.ts +478 -0
  254. package/src/lib/services/logger.service.ts +126 -0
  255. package/src/lib/services/transaction-builders/base-transaction-builder.service.ts +585 -0
  256. package/src/lib/services/transaction-builders/hedera-amount-utils.ts +84 -0
  257. package/src/lib/services/transaction-builders/hedera-transaction-builder.service.spec.ts +741 -0
  258. package/src/lib/services/transaction-builders/hedera-transaction-builder.service.ts +1285 -0
  259. package/src/lib/services/transaction-builders/index.ts +54 -0
  260. package/src/lib/services/transaction-builders/xrpl-transaction-builder.service.spec.ts +937 -0
  261. package/src/lib/services/transaction-builders/xrpl-transaction-builder.service.ts +832 -0
  262. package/src/lib/services/transaction.service.ts +346 -0
  263. package/src/lib/services/unified-wallet.service.spec.ts +1382 -0
  264. package/src/lib/services/unified-wallet.service.ts +852 -0
  265. package/src/lib/services/wallet-context.service.ts +184 -0
  266. package/src/lib/services/wallet-event-bus.service.ts +186 -0
  267. package/src/lib/services/wallet-providers.service.ts +137 -0
  268. package/src/lib/transports/chrome-extension-transport.ts +246 -0
  269. package/src/lib/utils/index.ts +14 -0
  270. package/src/lib/utils/ledger-icons.util.ts +78 -0
  271. package/test/test-setup.ts +21 -0
  272. package/test-setup.ts +63 -0
  273. package/tsconfig.build.json +11 -0
  274. package/tsconfig.json +29 -0
  275. package/tsconfig.spec.json +15 -0
  276. package/vitest.config.ts +48 -0
@@ -0,0 +1,826 @@
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-provider.ts
13
+ * @description Refactored WalletConnect v2 provider using Strategy Pattern
14
+ *
15
+ * Multi-chain WalletConnect v2 provider that delegates ledger-specific logic
16
+ * to specialized signer implementations.
17
+ *
18
+ * Architecture:
19
+ * - Provider: Orchestrates connection, session management, and UI
20
+ * - Signers: Handle ledger-specific transaction signing and formatting
21
+ * - Encoders: Convert between SDK formats and WalletConnect formats
22
+ *
23
+ * Benefits:
24
+ * - Clean separation of concerns
25
+ * - Easy to add new ledgers (just implement IWalletConnectSigner)
26
+ * - Testable (mock signers for unit tests)
27
+ * - Maintainable (ledger logic is isolated)
28
+ */
29
+
30
+ import { Injectable, signal, inject, NgZone } from '@angular/core';
31
+ import { getLogger } from '@hsuite/native-connect-sdk';
32
+
33
+ import type {
34
+ ConnectionStatus,
35
+ ProviderMetadata,
36
+ ConnectionConfig,
37
+ WalletConnectV2Config,
38
+ } from '../../../models/provider-types';
39
+ import type { UnifiedAccount } from '../../../models/unified-account.model';
40
+ import { WalletEventBus } from '../../../services/wallet-event-bus.service';
41
+ import { BaseWalletProvider } from '../../base-wallet-provider';
42
+ import type {
43
+ SignTransactionOptions,
44
+ SubmitTransactionOptions,
45
+ SignResult,
46
+ SubmitResult,
47
+ SignMessageOptions,
48
+ SignMessageResult,
49
+ } from '../../base-wallet-provider';
50
+ import { SignerFactory } from '../signers/signer-factory';
51
+
52
+ import { WalletConnectClientManager } from './walletconnect-client-manager';
53
+ import { WalletConnectSessionStore } from './walletconnect-session-store';
54
+ import { WalletConnectSigningOrchestrator } from './walletconnect-signing-orchestrator';
55
+
56
+ const logger = getLogger().scoped?.('WalletConnectV2Provider') ?? getLogger();
57
+
58
+ /**
59
+ * Storage key prefix for persisting user's network selection per session topic.
60
+ * This is critical for proper session restoration after page reload.
61
+ */
62
+ const NETWORK_SELECTION_STORAGE_KEY = 'wc_user_network_selection_';
63
+
64
+ /**
65
+ * WalletConnect v2 provider with multi-chain support.
66
+ *
67
+ * Uses Strategy Pattern to delegate ledger-specific operations to
68
+ * specialized signer implementations (HederaSigner, XrplSigner, etc.).
69
+ *
70
+ * Features:
71
+ * - Automatic session restoration from IndexedDB
72
+ * - QR code modal for wallet connection
73
+ * - Support for multiple ledgers (Hedera, XRPL, extensible)
74
+ * - Clean separation of orchestration vs ledger logic
75
+ * - **Multi-session support**: Connect multiple wallets across different ledgers/networks
76
+ */
77
+ @Injectable({ providedIn: 'root' })
78
+ export class WalletConnectV2Provider extends BaseWalletProvider {
79
+ override readonly id = 'walletconnect-v2';
80
+
81
+ override readonly metadata: ProviderMetadata = {
82
+ id: 'walletconnect-v2',
83
+ name: 'WalletConnect',
84
+ type: 'walletconnect-v2',
85
+ description: 'Connect via QR code to Hedera, XRPL, and other wallets',
86
+ supportsMultipleAccounts: true, // Changed to true for multi-session
87
+ };
88
+
89
+ /**
90
+ * Client manager - handles SignClient lifecycle.
91
+ */
92
+ private readonly clientManager = new WalletConnectClientManager();
93
+
94
+ /**
95
+ * Session store - handles session Map and account aggregation.
96
+ */
97
+ private readonly sessionStore = new WalletConnectSessionStore();
98
+
99
+ /**
100
+ * Signing orchestrator - handles transaction signing routing.
101
+ */
102
+ private signingOrchestrator!: WalletConnectSigningOrchestrator;
103
+
104
+ // Track session_delete listener registration
105
+ private sessionDeleteListenerRegistered = false;
106
+
107
+ // Reactive state
108
+ private _status = signal<ConnectionStatus>('disconnected');
109
+ private _error = signal<string | null>(null);
110
+
111
+ override readonly status = this._status.asReadonly();
112
+ override readonly accounts = this.sessionStore.accounts;
113
+ override readonly error = this._error.asReadonly();
114
+
115
+ // Event bus for emitting wallet events
116
+ private readonly eventBus = inject(WalletEventBus);
117
+
118
+ // NgZone for ensuring change detection runs after WalletConnect events
119
+ private readonly zone = inject(NgZone);
120
+
121
+ /**
122
+ *
123
+ */
124
+ constructor() {
125
+ super();
126
+
127
+ // Initialize signing orchestrator
128
+ this.signingOrchestrator = new WalletConnectSigningOrchestrator({
129
+ providerId: this.id,
130
+ sessionStore: this.sessionStore,
131
+ clientManager: this.clientManager,
132
+ eventBus: this.eventBus,
133
+ });
134
+
135
+ logger.info('Initializing - will attempt session restoration');
136
+ void this.restoreSession();
137
+ }
138
+
139
+ /**
140
+ * Ensure that a previously restored WalletConnect session is present in memory.
141
+ * Useful for UI flows that want to re-select a session after reload without forcing a new pairing flow.
142
+ * @param sessionKey
143
+ */
144
+ async resumeSession(sessionKey: string): Promise<boolean> {
145
+ if (this.sessionStore.hasSession(sessionKey)) {
146
+ this.sessionStore.updateAggregatedAccounts();
147
+ return true;
148
+ }
149
+
150
+ await this.restoreSession();
151
+ const exists = this.sessionStore.hasSession(sessionKey);
152
+ if (exists) {
153
+ this.sessionStore.updateAggregatedAccounts();
154
+ }
155
+ return exists;
156
+ }
157
+
158
+ /**
159
+ * Restore existing WalletConnect sessions from IndexedDB.
160
+ * Automatically called during provider initialization.
161
+ * Uses clientManager for client lifecycle.
162
+ */
163
+ private async restoreSession(): Promise<void> {
164
+ try {
165
+ logger.debug('Attempting to restore sessions...');
166
+
167
+ // Restore client from stored projectId
168
+ const client = await this.clientManager.restoreClient({
169
+ name: 'HSuite Demo',
170
+ description: 'Multi-chain wallet connection',
171
+ url: window.location.origin,
172
+ icons: [],
173
+ });
174
+
175
+ if (!client) {
176
+ return;
177
+ }
178
+
179
+ // Register session_delete listener
180
+ this.registerSessionDeleteListener();
181
+
182
+ // Get all active sessions
183
+ const activeSessions = this.clientManager.getActiveSessions();
184
+ logger.info('Found active sessions', { count: activeSessions.length });
185
+
186
+ if (activeSessions.length === 0) {
187
+ return;
188
+ }
189
+
190
+ // Restore each session
191
+ for (const session of activeSessions) {
192
+ try {
193
+ await this.restoreSingleSession(session);
194
+ } catch (error) {
195
+ logger.error('Failed to restore session', {
196
+ topic: session.topic,
197
+ error: error instanceof Error ? error.message : String(error),
198
+ });
199
+ }
200
+ }
201
+
202
+ // Update aggregated accounts
203
+ this.sessionStore.updateAggregatedAccounts();
204
+
205
+ if (this.sessionStore.size > 0) {
206
+ this._status.set('connected');
207
+ logger.info('Restored sessions', { count: this.sessionStore.size });
208
+ }
209
+ } catch (error) {
210
+ logger.error('Failed to restore sessions', {
211
+ error: error instanceof Error ? error.message : String(error),
212
+ });
213
+ }
214
+ }
215
+
216
+ /**
217
+ * Restore a single WalletConnect session.
218
+ * Internal helper for multi-session restoration.
219
+ *
220
+ * IMPORTANT: Reads user's network selection from localStorage to ensure
221
+ * restored sessions use the correct network the user originally selected.
222
+ *
223
+ * @param session - WalletConnect session object from IndexedDB
224
+ */
225
+ private async restoreSingleSession(session: any): Promise<void> {
226
+ logger.debug('Restoring session', { topic: session.topic });
227
+ logger.debug('Session namespaces', { namespaces: Object.keys(session.namespaces) });
228
+
229
+ // Determine ledger from session namespaces
230
+ let ledgerId: string | undefined;
231
+ let walletReportedNetwork: string | undefined;
232
+
233
+ if (session.namespaces.hedera) {
234
+ ledgerId = 'hedera';
235
+ walletReportedNetwork = session.namespaces.hedera.chains?.[0] || 'hedera:testnet';
236
+ logger.debug('Found Hedera namespace', { chains: session.namespaces.hedera.chains });
237
+ } else if (session.namespaces.xrpl) {
238
+ ledgerId = 'xrpl';
239
+ walletReportedNetwork = session.namespaces.xrpl.chains?.[0] || 'xrpl:testnet';
240
+ logger.debug('Found XRPL namespace', { chains: session.namespaces.xrpl.chains });
241
+ }
242
+
243
+ if (!ledgerId || !walletReportedNetwork) {
244
+ logger.warn('Could not determine ledger for session', {
245
+ topic: session.topic,
246
+ availableNamespaces: Object.keys(session.namespaces),
247
+ });
248
+ return;
249
+ }
250
+
251
+ // CRITICAL: Retrieve user's original network selection from localStorage
252
+ // This ensures we restore the session with the network the user actually selected
253
+ const userSelectedNetwork = this.getUserNetworkSelection(session.topic);
254
+ const networkId = userSelectedNetwork || walletReportedNetwork;
255
+
256
+ if (userSelectedNetwork) {
257
+ logger.debug('Restored user network selection', {
258
+ userSelectedNetwork,
259
+ walletReportedNetwork,
260
+ topic: session.topic.substring(0, 16),
261
+ });
262
+ } else {
263
+ logger.warn('No stored network selection found, using wallet-reported network', {
264
+ walletReportedNetwork,
265
+ topic: session.topic.substring(0, 16),
266
+ });
267
+ }
268
+
269
+ // Get the appropriate signer
270
+ const signer = SignerFactory.getSigner(ledgerId);
271
+
272
+ // Generate session key using the user's selected network
273
+ const sessionKey = this.sessionStore.generateSessionKey(ledgerId, networkId, session.topic);
274
+
275
+ // Parse accounts from session, filtering by user's selected network
276
+ const namespace = session.namespaces[ledgerId];
277
+ logger.debug('Namespace for restoration', {
278
+ ledgerId,
279
+ accountCount: (namespace as { accounts?: any[] })?.accounts?.length || 0,
280
+ });
281
+
282
+ // Pass the user's selected network to filter accounts appropriately
283
+ const parsedAccounts = signer.parseAccounts(namespace, userSelectedNetwork);
284
+ logger.debug('Parsed accounts from restored session', {
285
+ count: parsedAccounts.length,
286
+ userSelectedNetwork,
287
+ });
288
+
289
+ if (parsedAccounts.length === 0) {
290
+ logger.warn('Restored session has no accounts for selected network', {
291
+ userSelectedNetwork,
292
+ walletReportedNetwork,
293
+ });
294
+ }
295
+
296
+ // Create UnifiedAccount objects with user's selected network
297
+ const accounts: UnifiedAccount[] = parsedAccounts.map((acc, index) => ({
298
+ id: `${this.id}-${ledgerId}-${acc.address}`,
299
+ address: acc.address,
300
+ label: `Account ${index + 1}`,
301
+ ledgerId: ledgerId as 'hedera' | 'xrpl',
302
+ networkId: networkId, // Use user's selected network
303
+ providerId: this.id,
304
+ providerType: 'walletconnect-v2',
305
+ metadata: {
306
+ topic: session.topic,
307
+ ledger: ledgerId,
308
+ sessionKey,
309
+ peer: session.peer?.metadata,
310
+ walletReportedChainId: acc.chainId, // Keep original for debugging
311
+ userSelectedNetwork: networkId,
312
+ },
313
+ }));
314
+
315
+ // Store session data with user's network selection
316
+ this.sessionStore.setSession(sessionKey, {
317
+ session,
318
+ ledgerId,
319
+ networkId,
320
+ userSelectedNetwork: networkId,
321
+ signer,
322
+ accounts,
323
+ });
324
+
325
+ logger.info('Restored session', {
326
+ sessionKey,
327
+ ledgerId,
328
+ networkId,
329
+ userSelectedNetwork: networkId,
330
+ accountCount: accounts.length,
331
+ });
332
+
333
+ // Emit session restored event
334
+ this.eventBus.sessionRestored.emit({
335
+ providerId: this.id,
336
+ sessionKey,
337
+ accounts,
338
+ metadata: { topic: session.topic, ledgerId, networkId, userSelectedNetwork: networkId },
339
+ timestamp: Date.now(),
340
+ });
341
+ }
342
+
343
+ // NOTE: generateSessionKey and updateAggregatedAccounts have been moved to WalletConnectSessionStore
344
+
345
+ /**
346
+ * Store user's network selection in localStorage for session restoration.
347
+ * This ensures the user's network choice persists across page reloads.
348
+ *
349
+ * @param sessionTopic - WalletConnect session topic
350
+ * @param networkId - User's selected network (e.g., 'hedera:mainnet')
351
+ */
352
+ private storeUserNetworkSelection(sessionTopic: string, networkId: string): void {
353
+ try {
354
+ localStorage.setItem(`${NETWORK_SELECTION_STORAGE_KEY}${sessionTopic}`, networkId);
355
+ logger.debug('Stored user network selection', {
356
+ topic: sessionTopic.substring(0, 16),
357
+ networkId,
358
+ });
359
+ } catch (e) {
360
+ logger.warn('Failed to store network selection', { error: (e as Error).message });
361
+ }
362
+ }
363
+
364
+ /**
365
+ * Retrieve user's network selection from localStorage for session restoration.
366
+ *
367
+ * @param sessionTopic - WalletConnect session topic
368
+ * @returns User's selected network, or undefined if not found
369
+ */
370
+ private getUserNetworkSelection(sessionTopic: string): string | undefined {
371
+ try {
372
+ return localStorage.getItem(`${NETWORK_SELECTION_STORAGE_KEY}${sessionTopic}`) || undefined;
373
+ } catch (e) {
374
+ logger.warn('Failed to retrieve network selection', { error: (e as Error).message });
375
+ return undefined;
376
+ }
377
+ }
378
+
379
+ /**
380
+ * Clean up stored network selection for a session.
381
+ *
382
+ * @param sessionTopic - WalletConnect session topic
383
+ */
384
+ private clearUserNetworkSelection(sessionTopic: string): void {
385
+ try {
386
+ localStorage.removeItem(`${NETWORK_SELECTION_STORAGE_KEY}${sessionTopic}`);
387
+ } catch (_e) {
388
+ // Ignore cleanup errors
389
+ }
390
+ }
391
+
392
+ /**
393
+ * Connect to a wallet via WalletConnect QR code.
394
+ *
395
+ * Multi-session support:
396
+ * - Each connect() call creates a NEW session
397
+ * - Sessions are tracked separately in the sessions Map
398
+ * - Multiple sessions can coexist for different ledgers/networks
399
+ *
400
+ * Process:
401
+ * 1. Get appropriate signer for the ledger
402
+ * 2. Initialize WalletConnect client and modal
403
+ * 3. Build namespace configuration using signer
404
+ * 4. Generate QR code and wait for wallet approval
405
+ * 5. Store session and update aggregated accounts
406
+ *
407
+ * @param config - Connection configuration including ledger and network
408
+ */
409
+ async connect(config: ConnectionConfig): Promise<void> {
410
+ const wcConfig = config as WalletConnectV2Config;
411
+
412
+ try {
413
+ this._status.set('connecting');
414
+ this._error.set(null);
415
+
416
+ // Validate configuration
417
+ const projectId = wcConfig.projectId;
418
+ if (!projectId) {
419
+ throw new Error(
420
+ 'WalletConnect projectId is required. Get one from https://cloud.walletconnect.com',
421
+ );
422
+ }
423
+
424
+ // Get the appropriate signer for this ledger (Strategy Pattern)
425
+ const signer = SignerFactory.getSigner(wcConfig.ledgerId);
426
+ logger.debug('Using signer for ledger', { ledgerId: wcConfig.ledgerId });
427
+
428
+ // Initialize client via manager
429
+ await this.clientManager.initialize(projectId, {
430
+ name: wcConfig.appName || 'HSuite Demo',
431
+ description: wcConfig.appDescription || 'Multi-chain wallet connection',
432
+ url: window.location.origin,
433
+ icons: wcConfig.appIconUrl ? [wcConfig.appIconUrl] : [],
434
+ });
435
+ this.registerSessionDeleteListener();
436
+
437
+ // Create modal for QR code display
438
+ const modal = this.clientManager.createModal(projectId, [wcConfig.networkId]);
439
+
440
+ // Build namespace configuration using signer
441
+ const namespaceConfig = signer.buildNamespace(wcConfig.networkId);
442
+ const optionalNamespaces = { [wcConfig.ledgerId]: namespaceConfig };
443
+ logger.debug('Namespace config', { ledgerId: wcConfig.ledgerId });
444
+
445
+ // Build session properties to pass user's preferred network to wallet
446
+ // This tells the wallet which network accounts to show in the picker
447
+ const sessionProperties = {
448
+ preferredNetwork: wcConfig.networkId,
449
+ preferredLedger: wcConfig.ledgerId,
450
+ };
451
+
452
+ logger.info('Connecting with preferred network', {
453
+ preferredNetwork: wcConfig.networkId,
454
+ preferredLedger: wcConfig.ledgerId,
455
+ });
456
+
457
+ // Connect and show QR code
458
+ const { uri, approval } = await this.clientManager.connect(
459
+ optionalNamespaces,
460
+ sessionProperties,
461
+ );
462
+
463
+ if (uri) {
464
+ await modal.openModal({ uri });
465
+ }
466
+
467
+ // Wait for wallet approval
468
+ logger.info('Waiting for wallet approval...');
469
+ const session = await approval();
470
+ this.clientManager.closeModal();
471
+
472
+ logger.info('[WC:DAPP:APPROVED] Session approved by wallet', {
473
+ topic: session.topic.substring(0, 16) + '...',
474
+ fullTopic: session.topic,
475
+ namespaces: Object.keys(session.namespaces),
476
+ expiry: session.expiry,
477
+ });
478
+
479
+ // Generate session key
480
+ const sessionKey = this.sessionStore.generateSessionKey(
481
+ wcConfig.ledgerId,
482
+ wcConfig.networkId,
483
+ session.topic,
484
+ );
485
+
486
+ // Parse accounts from session
487
+ const sessionNamespace = session.namespaces[wcConfig.ledgerId];
488
+ logger.debug('Session namespace for ledger', {
489
+ ledgerId: wcConfig.ledgerId,
490
+ accountCount: (sessionNamespace as { accounts?: any[] })?.accounts?.length || 0,
491
+ });
492
+
493
+ if (!sessionNamespace) {
494
+ logger.error('No namespace found for ledger', {
495
+ ledgerId: wcConfig.ledgerId,
496
+ availableNamespaces: Object.keys(session.namespaces),
497
+ });
498
+ throw new Error(
499
+ `Wallet did not approve ${wcConfig.ledgerId} namespace. Available: ${Object.keys(session.namespaces).join(', ')}`,
500
+ );
501
+ }
502
+
503
+ // Parse accounts from session namespace, filtering by user's selected network
504
+ // This ensures we only show accounts that match the network the user selected
505
+ const parsedAccounts = signer.parseAccounts(sessionNamespace, wcConfig.networkId);
506
+ logger.debug('Parsed accounts', {
507
+ count: parsedAccounts.length,
508
+ userSelectedNetwork: wcConfig.networkId,
509
+ });
510
+
511
+ if (parsedAccounts.length === 0) {
512
+ logger.warn('No accounts returned from wallet - possible causes:', {
513
+ reason1: 'Wallet has no accounts for the requested network',
514
+ reason2: 'Wallet denied account sharing',
515
+ reason3: 'Wallet returned accounts in unexpected format',
516
+ userSelectedNetwork: wcConfig.networkId,
517
+ });
518
+ }
519
+
520
+ // Create UnifiedAccount objects
521
+ // IMPORTANT: Use wcConfig.networkId (user's selection) for account networkId
522
+ // This respects user intent rather than relying on wallet-reported chain
523
+ const accounts: UnifiedAccount[] = parsedAccounts.map((acc, index) => ({
524
+ id: `${this.id}-${wcConfig.ledgerId}-${acc.address}`,
525
+ address: acc.address,
526
+ label: `Account ${index + 1}`,
527
+ ledgerId: wcConfig.ledgerId,
528
+ networkId: wcConfig.networkId, // Use user's selected network, not wallet-reported
529
+ providerId: this.id,
530
+ providerType: 'walletconnect-v2',
531
+ metadata: {
532
+ topic: session.topic,
533
+ ledger: wcConfig.ledgerId,
534
+ sessionKey,
535
+ walletReportedChainId: acc.chainId, // Keep original for debugging
536
+ userSelectedNetwork: wcConfig.networkId, // Store for session restoration
537
+ },
538
+ }));
539
+
540
+ // Store session data with user's selected network
541
+ this.sessionStore.setSession(sessionKey, {
542
+ session,
543
+ ledgerId: wcConfig.ledgerId,
544
+ networkId: wcConfig.networkId,
545
+ userSelectedNetwork: wcConfig.networkId, // Store user's selection for restoration
546
+ signer,
547
+ accounts,
548
+ });
549
+
550
+ // Persist user's network selection for session restoration after page reload
551
+ this.storeUserNetworkSelection(session.topic, wcConfig.networkId);
552
+
553
+ // Verify session exists in WC SDK after storing
554
+ const sdkSession = this.clientManager.getSession(session.topic);
555
+
556
+ logger.info('[WC:DAPP:STORED] Session stored locally', {
557
+ sessionKey,
558
+ topic: session.topic.substring(0, 16) + '...',
559
+ fullTopic: session.topic,
560
+ accountCount: accounts.length,
561
+ totalSessions: this.sessionStore.size,
562
+ existsInSdkSession: !!sdkSession,
563
+ });
564
+
565
+ // Update aggregated accounts
566
+ this.sessionStore.updateAggregatedAccounts();
567
+ this._status.set('connected');
568
+
569
+ // Emit session created event
570
+ this.eventBus.sessionCreated.emit({
571
+ providerId: this.id,
572
+ sessionKey,
573
+ accounts,
574
+ metadata: {
575
+ topic: session.topic,
576
+ ledgerId: wcConfig.ledgerId,
577
+ networkId: wcConfig.networkId,
578
+ },
579
+ timestamp: Date.now(),
580
+ });
581
+
582
+ // Register session_delete listener (idempotent)
583
+ this.registerSessionDeleteListener();
584
+ } catch (error) {
585
+ this._status.set('error');
586
+ this._error.set(error instanceof Error ? error.message : 'Connection failed');
587
+ logger.error('Connection failed', {
588
+ error: error instanceof Error ? error.message : String(error),
589
+ });
590
+
591
+ // Emit provider error event
592
+ this.eventBus.providerError.emit({
593
+ providerId: this.id,
594
+ error: error instanceof Error ? error : String(error),
595
+ context: 'connection',
596
+ timestamp: Date.now(),
597
+ });
598
+
599
+ this.clientManager.closeModal();
600
+ throw error;
601
+ }
602
+ }
603
+
604
+ /**
605
+ * Remove a session by its WalletConnect topic.
606
+ * Internal helper for session_delete event handling.
607
+ *
608
+ * @param topic - WalletConnect session topic
609
+ */
610
+ private removeSessionByTopic(topic: string): void {
611
+ // Find and remove the session using session store
612
+ const removed = this.sessionStore.removeSessionByTopic(topic);
613
+
614
+ // Clean up stored network selection
615
+ this.clearUserNetworkSelection(topic);
616
+
617
+ // Update aggregated accounts
618
+ this.sessionStore.updateAggregatedAccounts();
619
+
620
+ // Update status
621
+ if (this.sessionStore.size === 0) {
622
+ this._status.set('disconnected');
623
+ }
624
+
625
+ // Emit events if session was found
626
+ if (removed) {
627
+ // Emit session deleted event
628
+ this.eventBus.sessionDeleted.emit({
629
+ providerId: this.id,
630
+ sessionKey: removed.sessionKey,
631
+ accounts: removed.data.accounts,
632
+ metadata: { topic, reason: 'wallet_initiated' },
633
+ timestamp: Date.now(),
634
+ });
635
+
636
+ // Emit disconnection event
637
+ this.eventBus.disconnected.emit({
638
+ providerId: this.id,
639
+ providerType: 'walletconnect-v2',
640
+ sessionKey: removed.sessionKey,
641
+ reason: 'wallet_initiated_disconnect',
642
+ timestamp: Date.now(),
643
+ });
644
+ }
645
+ }
646
+
647
+ /**
648
+ * Register session_delete event listener to handle wallet-initiated disconnects.
649
+ * Idempotent - only registers once even if called multiple times.
650
+ *
651
+ * @private
652
+ */
653
+ private registerSessionDeleteListener(): void {
654
+ if (!this.clientManager.isInitialized() || this.sessionDeleteListenerRegistered) {
655
+ return;
656
+ }
657
+
658
+ // ✅ CRITICAL: Run inside NgZone to trigger Angular's change detection
659
+ // WalletConnect events arrive outside Angular's zone
660
+ this.clientManager.on('session_delete', (event: any) => {
661
+ this.zone.run(() => {
662
+ logger.info('� Session deleted by wallet (session_delete event)', {
663
+ topic: (event as { topic: string }).topic,
664
+ });
665
+ this.removeSessionByTopic((event as { topic: string }).topic);
666
+ });
667
+ });
668
+
669
+ this.sessionDeleteListenerRegistered = true;
670
+ logger.debug('session_delete listener registered');
671
+ }
672
+
673
+ /**
674
+ * Disconnect from WalletConnect sessions.
675
+ * Supports disconnecting all sessions or a specific session.
676
+ *
677
+ * @param sessionKey - Optional session key to disconnect specific session
678
+ */
679
+ async disconnect(sessionKey?: string): Promise<void> {
680
+ if (!this.clientManager.isInitialized()) {
681
+ logger.warn('No client to disconnect');
682
+ return;
683
+ }
684
+
685
+ if (sessionKey) {
686
+ // Disconnect specific session
687
+ const sessionData = this.sessionStore.getSession(sessionKey);
688
+ if (sessionData) {
689
+ try {
690
+ await this.clientManager.disconnect(sessionData.session.topic, {
691
+ code: 6000,
692
+ message: 'User disconnected session',
693
+ });
694
+ logger.info('Disconnected session', { sessionKey });
695
+ } catch (e) {
696
+ logger.error('Disconnect error for session', {
697
+ sessionKey,
698
+ error: e instanceof Error ? e.message : String(e),
699
+ });
700
+ }
701
+
702
+ // Clean up stored network selection
703
+ this.clearUserNetworkSelection(sessionData.session.topic);
704
+
705
+ this.sessionStore.deleteSession(sessionKey);
706
+ this.sessionStore.updateAggregatedAccounts();
707
+
708
+ if (this.sessionStore.size === 0) {
709
+ this._status.set('disconnected');
710
+ }
711
+ }
712
+ } else {
713
+ // Disconnect all sessions
714
+ const disconnectPromises: Promise<void>[] = [];
715
+
716
+ for (const [_key, sessionData] of this.sessionStore.entries()) {
717
+ // Clean up stored network selection for each session
718
+ this.clearUserNetworkSelection(sessionData.session.topic);
719
+
720
+ disconnectPromises.push(
721
+ this.clientManager
722
+ .disconnect(sessionData.session.topic, {
723
+ code: 6000,
724
+ message: 'User disconnected all sessions',
725
+ })
726
+ .catch((err: Error) =>
727
+ logger.error('Disconnect error', {
728
+ error: err.message,
729
+ }),
730
+ ),
731
+ );
732
+ }
733
+
734
+ await Promise.all(disconnectPromises);
735
+
736
+ this.sessionStore.clear();
737
+ this._status.set('disconnected');
738
+
739
+ logger.info('Disconnected all sessions');
740
+ }
741
+
742
+ this.clientManager.closeModal();
743
+ }
744
+
745
+ // NOTE: findSessionForAccount and validateSessionInSdk moved to WalletConnectSigningOrchestrator
746
+
747
+ /**
748
+ * Sign a transaction without submitting (delegates to SigningOrchestrator).
749
+ * @param options
750
+ */
751
+ async signTransaction(options: SignTransactionOptions): Promise<SignResult> {
752
+ if (!this.clientManager.isInitialized()) {
753
+ throw new Error('Not connected to WalletConnect');
754
+ }
755
+ return this.signingOrchestrator.signTransaction(options);
756
+ }
757
+
758
+ /**
759
+ * Sign and submit a transaction (delegates to SigningOrchestrator).
760
+ * @param options
761
+ */
762
+ async submitTransaction(options: SubmitTransactionOptions): Promise<SubmitResult> {
763
+ if (!this.clientManager.isInitialized()) {
764
+ throw new Error('Not connected to WalletConnect');
765
+ }
766
+ return this.signingOrchestrator.submitTransaction(options);
767
+ }
768
+
769
+ /**
770
+ * Sign and execute transaction in one call (delegates to SigningOrchestrator).
771
+ * @param options
772
+ */
773
+ async signAndExecuteTransaction(options: SubmitTransactionOptions): Promise<SubmitResult> {
774
+ if (!this.clientManager.isInitialized()) {
775
+ throw new Error('Not connected to WalletConnect');
776
+ }
777
+ return this.signingOrchestrator.signAndExecuteTransaction(options);
778
+ }
779
+
780
+ /**
781
+ * Sign an arbitrary message (delegates to SigningOrchestrator).
782
+ * @param options
783
+ */
784
+ async signMessage(options: SignMessageOptions): Promise<SignMessageResult> {
785
+ if (!this.clientManager.isInitialized()) {
786
+ throw new Error('Not connected to WalletConnect');
787
+ }
788
+ return this.signingOrchestrator.signMessage(options);
789
+ }
790
+
791
+ /**
792
+ * Check if WalletConnect is available.
793
+ * Always returns true as WalletConnect is browser-based.
794
+ */
795
+ async isAvailable(): Promise<boolean> {
796
+ return true;
797
+ }
798
+
799
+ /**
800
+ * Get all active WalletConnect sessions.
801
+ * Useful for displaying session information in UI and managing multiple connections.
802
+ * Delegates to session store.
803
+ *
804
+ * @returns Array of session information objects
805
+ */
806
+ getActiveSessions(): Array<{
807
+ sessionKey: string;
808
+ ledgerId: string;
809
+ networkId: string;
810
+ userSelectedNetwork: string;
811
+ accounts: UnifiedAccount[];
812
+ topic: string;
813
+ }> {
814
+ return this.sessionStore.getActiveSessions();
815
+ }
816
+
817
+ /**
818
+ * Disconnect a specific session by session key.
819
+ * Public wrapper for the private disconnect method.
820
+ *
821
+ * @param sessionKey - The session key to disconnect
822
+ */
823
+ async disconnectSession(sessionKey: string): Promise<void> {
824
+ await this.disconnect(sessionKey);
825
+ }
826
+ }