@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,585 @@
|
|
|
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 Abstract base class for transaction builder services.
|
|
13
|
+
*
|
|
14
|
+
* @file base-transaction-builder.service.ts
|
|
15
|
+
* @description Provides common functionality for building blockchain transactions
|
|
16
|
+
* across different ledger types (Hedera, XRPL, etc.).
|
|
17
|
+
*
|
|
18
|
+
* This abstract base class extracts shared patterns from ledger-specific
|
|
19
|
+
* transaction builders, including:
|
|
20
|
+
* - Common validation logic for accounts, amounts, and parameters
|
|
21
|
+
* - Error handling patterns with standardized error types
|
|
22
|
+
* - Amount parsing utilities for different decimal formats
|
|
23
|
+
* - Base64/hex encoding utilities
|
|
24
|
+
*
|
|
25
|
+
* Ledger-specific builders should extend this class and implement
|
|
26
|
+
* the abstract methods for their specific blockchain.
|
|
27
|
+
*
|
|
28
|
+
* @Injectable({ providedIn: 'root' })
|
|
29
|
+
* export class MyLedgerTransactionBuilderService extends BaseTransactionBuilderService {
|
|
30
|
+
* protected readonly ledgerType = 'my-ledger';
|
|
31
|
+
*
|
|
32
|
+
* protected async serializeTransactionImpl(tx: unknown): Promise<string> {
|
|
33
|
+
* // Ledger-specific serialization
|
|
34
|
+
* return btoa(JSON.stringify(tx));
|
|
35
|
+
* }
|
|
36
|
+
* }
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
import { inject } from '@angular/core';
|
|
41
|
+
import type { Logger } from '@hsuite/native-connect-sdk';
|
|
42
|
+
|
|
43
|
+
import { LoggerService } from '../logger.service';
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Error codes for transaction builder errors.
|
|
47
|
+
*
|
|
48
|
+
* Standardized error codes for identifying specific error conditions
|
|
49
|
+
* in transaction building operations.
|
|
50
|
+
*/
|
|
51
|
+
export enum TransactionBuilderErrorCode {
|
|
52
|
+
/** Invalid account ID format */
|
|
53
|
+
INVALID_ACCOUNT = 'INVALID_ACCOUNT',
|
|
54
|
+
/** Invalid amount (negative, NaN, or exceeds limits) */
|
|
55
|
+
INVALID_AMOUNT = 'INVALID_AMOUNT',
|
|
56
|
+
/** Invalid token ID format */
|
|
57
|
+
INVALID_TOKEN_ID = 'INVALID_TOKEN_ID',
|
|
58
|
+
/** Missing required parameter */
|
|
59
|
+
MISSING_PARAMETER = 'MISSING_PARAMETER',
|
|
60
|
+
/** No active wallet session */
|
|
61
|
+
NO_ACTIVE_SESSION = 'NO_ACTIVE_SESSION',
|
|
62
|
+
/** Transaction serialization failed */
|
|
63
|
+
SERIALIZATION_FAILED = 'SERIALIZATION_FAILED',
|
|
64
|
+
/** Network-related error */
|
|
65
|
+
NETWORK_ERROR = 'NETWORK_ERROR',
|
|
66
|
+
/** General validation error */
|
|
67
|
+
VALIDATION_ERROR = 'VALIDATION_ERROR',
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Structured error for transaction builder operations.
|
|
72
|
+
*
|
|
73
|
+
* Provides detailed error information including error code, message,
|
|
74
|
+
* and optional context for debugging.
|
|
75
|
+
*/
|
|
76
|
+
export class TransactionBuilderError extends Error {
|
|
77
|
+
/**
|
|
78
|
+
* Creates a new TransactionBuilderError.
|
|
79
|
+
*
|
|
80
|
+
* @param code - The error code identifying the error type
|
|
81
|
+
* @param message - Human-readable error message
|
|
82
|
+
* @param context - Optional context object with additional details
|
|
83
|
+
*/
|
|
84
|
+
constructor(
|
|
85
|
+
public readonly code: TransactionBuilderErrorCode,
|
|
86
|
+
message: string,
|
|
87
|
+
public readonly context?: Record<string, unknown>,
|
|
88
|
+
) {
|
|
89
|
+
super(message);
|
|
90
|
+
this.name = 'TransactionBuilderError';
|
|
91
|
+
|
|
92
|
+
// Maintains proper stack trace for where error was thrown (V8 engines)
|
|
93
|
+
if (Error.captureStackTrace) {
|
|
94
|
+
Error.captureStackTrace(this, TransactionBuilderError);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Creates an error for invalid account format.
|
|
100
|
+
* @param account
|
|
101
|
+
* @param ledgerType
|
|
102
|
+
*/
|
|
103
|
+
static invalidAccount(account: string, ledgerType: string): TransactionBuilderError {
|
|
104
|
+
return new TransactionBuilderError(
|
|
105
|
+
TransactionBuilderErrorCode.INVALID_ACCOUNT,
|
|
106
|
+
`Invalid ${ledgerType} account format: ${account}`,
|
|
107
|
+
{ account, ledgerType },
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Creates an error for invalid amount.
|
|
113
|
+
* @param amount
|
|
114
|
+
* @param reason
|
|
115
|
+
*/
|
|
116
|
+
static invalidAmount(amount: unknown, reason: string): TransactionBuilderError {
|
|
117
|
+
return new TransactionBuilderError(
|
|
118
|
+
TransactionBuilderErrorCode.INVALID_AMOUNT,
|
|
119
|
+
`Invalid amount: ${reason}`,
|
|
120
|
+
{ amount, reason },
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Creates an error for invalid token ID.
|
|
126
|
+
* @param tokenId
|
|
127
|
+
* @param ledgerType
|
|
128
|
+
*/
|
|
129
|
+
static invalidTokenId(tokenId: string, ledgerType: string): TransactionBuilderError {
|
|
130
|
+
return new TransactionBuilderError(
|
|
131
|
+
TransactionBuilderErrorCode.INVALID_TOKEN_ID,
|
|
132
|
+
`Invalid ${ledgerType} token ID format: ${tokenId}`,
|
|
133
|
+
{ tokenId, ledgerType },
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Creates an error for missing required parameter.
|
|
139
|
+
* @param paramName
|
|
140
|
+
* @param operation
|
|
141
|
+
*/
|
|
142
|
+
static missingParameter(paramName: string, operation: string): TransactionBuilderError {
|
|
143
|
+
return new TransactionBuilderError(
|
|
144
|
+
TransactionBuilderErrorCode.MISSING_PARAMETER,
|
|
145
|
+
`Missing required parameter '${paramName}' for ${operation}`,
|
|
146
|
+
{ paramName, operation },
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Creates an error for no active session.
|
|
152
|
+
*/
|
|
153
|
+
static noActiveSession(): TransactionBuilderError {
|
|
154
|
+
return new TransactionBuilderError(
|
|
155
|
+
TransactionBuilderErrorCode.NO_ACTIVE_SESSION,
|
|
156
|
+
'No active wallet session. Please connect your wallet first.',
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Creates an error for serialization failure.
|
|
162
|
+
* @param reason
|
|
163
|
+
* @param cause
|
|
164
|
+
*/
|
|
165
|
+
static serializationFailed(reason: string, cause?: unknown): TransactionBuilderError {
|
|
166
|
+
return new TransactionBuilderError(
|
|
167
|
+
TransactionBuilderErrorCode.SERIALIZATION_FAILED,
|
|
168
|
+
`Transaction serialization failed: ${reason}`,
|
|
169
|
+
{ reason, cause: cause instanceof Error ? cause.message : String(cause) },
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Result of amount parsing with normalized values.
|
|
176
|
+
*
|
|
177
|
+
* Contains the parsed amount in different formats for flexibility
|
|
178
|
+
* in different ledger transaction requirements.
|
|
179
|
+
*/
|
|
180
|
+
export interface ParsedAmount {
|
|
181
|
+
/** Original input value */
|
|
182
|
+
original: number | string;
|
|
183
|
+
/** Amount as a floating-point number */
|
|
184
|
+
asNumber: number;
|
|
185
|
+
/** Amount as a string (for precision-sensitive operations) */
|
|
186
|
+
asString: string;
|
|
187
|
+
/** Amount in smallest unit (e.g., tinybars, drops) */
|
|
188
|
+
inSmallestUnit: bigint;
|
|
189
|
+
/** Number of decimals used */
|
|
190
|
+
decimals: number;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Configuration for amount parsing.
|
|
195
|
+
*/
|
|
196
|
+
export interface AmountParseOptions {
|
|
197
|
+
/** Number of decimal places for the asset (default: 0) */
|
|
198
|
+
decimals?: number;
|
|
199
|
+
/** Whether to allow negative amounts (default: false) */
|
|
200
|
+
allowNegative?: boolean;
|
|
201
|
+
/** Maximum allowed amount (optional) */
|
|
202
|
+
maxAmount?: number | bigint;
|
|
203
|
+
/** Minimum allowed amount (optional, default: 0 unless allowNegative) */
|
|
204
|
+
minAmount?: number | bigint;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Abstract base class for transaction builder services.
|
|
209
|
+
*
|
|
210
|
+
* Provides common functionality for building blockchain transactions
|
|
211
|
+
* including validation, error handling, and amount parsing utilities.
|
|
212
|
+
*
|
|
213
|
+
* Ledger-specific builders (Hedera, XRPL, etc.) should extend this class
|
|
214
|
+
* and implement the abstract methods for their specific requirements.
|
|
215
|
+
*/
|
|
216
|
+
export abstract class BaseTransactionBuilderService {
|
|
217
|
+
/**
|
|
218
|
+
* Logger instance for this service.
|
|
219
|
+
* Injected via Angular DI and scoped to the ledger type.
|
|
220
|
+
*/
|
|
221
|
+
protected readonly logger: Logger;
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* The type of ledger this builder supports (e.g., 'hedera', 'xrpl').
|
|
225
|
+
* Used for error messages and logging context.
|
|
226
|
+
*/
|
|
227
|
+
protected abstract readonly ledgerType: string;
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
*
|
|
231
|
+
*/
|
|
232
|
+
constructor() {
|
|
233
|
+
// Inject LoggerService and create scoped logger
|
|
234
|
+
// Note: Subclasses should call super() and the logger will be set up
|
|
235
|
+
const loggerService = inject(LoggerService);
|
|
236
|
+
this.logger = loggerService.scoped(this.constructor.name);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// ============================================================================
|
|
240
|
+
// Validation Methods
|
|
241
|
+
// ============================================================================
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Validates that a string is a non-empty, valid account identifier.
|
|
245
|
+
*
|
|
246
|
+
* Override in subclasses for ledger-specific account format validation.
|
|
247
|
+
*
|
|
248
|
+
* @param account - The account identifier to validate
|
|
249
|
+
* @param paramName - Parameter name for error messages
|
|
250
|
+
* @throws TransactionBuilderError if validation fails
|
|
251
|
+
*/
|
|
252
|
+
protected validateAccount(account: string, paramName = 'account'): void {
|
|
253
|
+
if (!account || typeof account !== 'string') {
|
|
254
|
+
throw TransactionBuilderError.missingParameter(paramName, 'transaction');
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const trimmed = account.trim();
|
|
258
|
+
if (trimmed.length === 0) {
|
|
259
|
+
throw TransactionBuilderError.invalidAccount(account, this.ledgerType);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Subclasses should override for specific format validation
|
|
263
|
+
this.validateAccountFormat(trimmed);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Validates the account format specific to the ledger type.
|
|
268
|
+
* Override in subclasses for ledger-specific validation.
|
|
269
|
+
*
|
|
270
|
+
* @param account - The trimmed account identifier
|
|
271
|
+
* @throws TransactionBuilderError if format is invalid
|
|
272
|
+
*/
|
|
273
|
+
protected validateAccountFormat(account: string): void {
|
|
274
|
+
// Default implementation - subclasses should override
|
|
275
|
+
this.logger.debug('Using default account format validation', { account });
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Validates that an amount is a valid positive number.
|
|
280
|
+
*
|
|
281
|
+
* Checks for NaN, Infinity, and negative values (unless allowed).
|
|
282
|
+
*
|
|
283
|
+
* @param amount - The amount to validate
|
|
284
|
+
* @param options - Validation options
|
|
285
|
+
* @throws TransactionBuilderError if validation fails
|
|
286
|
+
*/
|
|
287
|
+
protected validateAmount(amount: number | string, options: AmountParseOptions = {}): void {
|
|
288
|
+
const { allowNegative = false, maxAmount, minAmount } = options;
|
|
289
|
+
|
|
290
|
+
const numAmount = typeof amount === 'string' ? parseFloat(amount) : amount;
|
|
291
|
+
|
|
292
|
+
if (typeof numAmount !== 'number' || isNaN(numAmount)) {
|
|
293
|
+
throw TransactionBuilderError.invalidAmount(amount, 'must be a valid number');
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
if (!isFinite(numAmount)) {
|
|
297
|
+
throw TransactionBuilderError.invalidAmount(amount, 'must be a finite number');
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
if (!allowNegative && numAmount < 0) {
|
|
301
|
+
throw TransactionBuilderError.invalidAmount(amount, 'must be non-negative');
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
const effectiveMin =
|
|
305
|
+
minAmount !== undefined ? Number(minAmount) : allowNegative ? -Infinity : 0;
|
|
306
|
+
if (numAmount < effectiveMin) {
|
|
307
|
+
throw TransactionBuilderError.invalidAmount(amount, `must be at least ${effectiveMin}`);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
if (maxAmount !== undefined && numAmount > Number(maxAmount)) {
|
|
311
|
+
throw TransactionBuilderError.invalidAmount(amount, `must not exceed ${maxAmount}`);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Validates that a token ID is valid for the ledger type.
|
|
317
|
+
*
|
|
318
|
+
* @param tokenId - The token identifier to validate
|
|
319
|
+
* @throws TransactionBuilderError if validation fails
|
|
320
|
+
*/
|
|
321
|
+
protected validateTokenId(tokenId: string): void {
|
|
322
|
+
if (!tokenId || typeof tokenId !== 'string') {
|
|
323
|
+
throw TransactionBuilderError.missingParameter('tokenId', 'token transaction');
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
const trimmed = tokenId.trim();
|
|
327
|
+
if (trimmed.length === 0) {
|
|
328
|
+
throw TransactionBuilderError.invalidTokenId(tokenId, this.ledgerType);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// Subclasses should override for specific format validation
|
|
332
|
+
this.validateTokenIdFormat(trimmed);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Validates the token ID format specific to the ledger type.
|
|
337
|
+
* Override in subclasses for ledger-specific validation.
|
|
338
|
+
*
|
|
339
|
+
* @param tokenId - The trimmed token identifier
|
|
340
|
+
* @throws TransactionBuilderError if format is invalid
|
|
341
|
+
*/
|
|
342
|
+
protected validateTokenIdFormat(tokenId: string): void {
|
|
343
|
+
// Default implementation - subclasses should override
|
|
344
|
+
this.logger.debug('Using default token ID format validation', { tokenId });
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Validates that a required parameter is present.
|
|
349
|
+
*
|
|
350
|
+
* @param value - The value to check
|
|
351
|
+
* @param paramName - The parameter name for error messages
|
|
352
|
+
* @param operation - The operation name for error messages
|
|
353
|
+
* @throws TransactionBuilderError if the value is null/undefined
|
|
354
|
+
*/
|
|
355
|
+
protected requireParam<T>(
|
|
356
|
+
value: T | null | undefined,
|
|
357
|
+
paramName: string,
|
|
358
|
+
operation: string,
|
|
359
|
+
): asserts value is T {
|
|
360
|
+
if (value === null || value === undefined) {
|
|
361
|
+
throw TransactionBuilderError.missingParameter(paramName, operation);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// ============================================================================
|
|
366
|
+
// Amount Parsing Utilities
|
|
367
|
+
// ============================================================================
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Parses an amount into various formats needed for transactions.
|
|
371
|
+
*
|
|
372
|
+
* Converts amounts between display format and smallest unit format,
|
|
373
|
+
* handling decimal precision correctly to avoid floating-point errors.
|
|
374
|
+
*
|
|
375
|
+
* @param amount - The amount to parse (number or string)
|
|
376
|
+
* @param options - Parsing options including decimals
|
|
377
|
+
* @returns Parsed amount in multiple formats
|
|
378
|
+
* @throws TransactionBuilderError if amount is invalid
|
|
379
|
+
*/
|
|
380
|
+
protected parseAmount(amount: number | string, options: AmountParseOptions = {}): ParsedAmount {
|
|
381
|
+
const { decimals = 0 } = options;
|
|
382
|
+
|
|
383
|
+
// Validate the amount first
|
|
384
|
+
this.validateAmount(amount, options);
|
|
385
|
+
|
|
386
|
+
const numAmount = typeof amount === 'string' ? parseFloat(amount) : amount;
|
|
387
|
+
const strAmount = String(amount);
|
|
388
|
+
|
|
389
|
+
// Calculate smallest unit using precise arithmetic
|
|
390
|
+
// Multiply by 10^decimals to get smallest unit
|
|
391
|
+
const _multiplier = BigInt(Math.pow(10, decimals));
|
|
392
|
+
|
|
393
|
+
// Handle the conversion carefully to avoid precision issues
|
|
394
|
+
// Split the number into integer and fractional parts
|
|
395
|
+
const [intPart, fracPart = ''] = strAmount.split('.');
|
|
396
|
+
const paddedFrac = fracPart.padEnd(decimals, '0').slice(0, decimals);
|
|
397
|
+
const combinedStr = intPart + paddedFrac;
|
|
398
|
+
|
|
399
|
+
// Remove leading zeros but keep at least one digit
|
|
400
|
+
const normalizedStr = combinedStr.replace(/^0+/, '') || '0';
|
|
401
|
+
const inSmallestUnit = BigInt(normalizedStr);
|
|
402
|
+
|
|
403
|
+
return {
|
|
404
|
+
original: amount,
|
|
405
|
+
asNumber: numAmount,
|
|
406
|
+
asString: strAmount,
|
|
407
|
+
inSmallestUnit,
|
|
408
|
+
decimals,
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* Converts an amount from smallest unit to display format.
|
|
414
|
+
*
|
|
415
|
+
* @param smallestUnit - Amount in smallest unit (bigint or number)
|
|
416
|
+
* @param decimals - Number of decimal places
|
|
417
|
+
* @returns Formatted string with proper decimal places
|
|
418
|
+
*/
|
|
419
|
+
protected formatFromSmallestUnit(smallestUnit: bigint | number, decimals: number): string {
|
|
420
|
+
const bigVal =
|
|
421
|
+
typeof smallestUnit === 'number' ? BigInt(Math.floor(smallestUnit)) : smallestUnit;
|
|
422
|
+
|
|
423
|
+
if (decimals === 0) {
|
|
424
|
+
return bigVal.toString();
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
const divisor = BigInt(Math.pow(10, decimals));
|
|
428
|
+
const intPart = bigVal / divisor;
|
|
429
|
+
const fracPart = bigVal % divisor;
|
|
430
|
+
|
|
431
|
+
if (fracPart === 0n) {
|
|
432
|
+
return intPart.toString();
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
const fracStr = fracPart.toString().padStart(decimals, '0');
|
|
436
|
+
// Trim trailing zeros from fraction
|
|
437
|
+
const trimmedFrac = fracStr.replace(/0+$/, '');
|
|
438
|
+
|
|
439
|
+
return `${intPart}.${trimmedFrac}`;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
// ============================================================================
|
|
443
|
+
// Encoding Utilities
|
|
444
|
+
// ============================================================================
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* Converts a Uint8Array to a base64 string.
|
|
448
|
+
*
|
|
449
|
+
* @param bytes - The byte array to encode
|
|
450
|
+
* @returns Base64 encoded string
|
|
451
|
+
*/
|
|
452
|
+
protected uint8ArrayToBase64(bytes: Uint8Array): string {
|
|
453
|
+
let binary = '';
|
|
454
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
455
|
+
binary += String.fromCharCode(bytes[i]);
|
|
456
|
+
}
|
|
457
|
+
return btoa(binary);
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* Converts a base64 string to a Uint8Array.
|
|
462
|
+
*
|
|
463
|
+
* @param base64 - The base64 string to decode
|
|
464
|
+
* @returns Decoded byte array
|
|
465
|
+
*/
|
|
466
|
+
protected base64ToUint8Array(base64: string): Uint8Array {
|
|
467
|
+
const binary = atob(base64);
|
|
468
|
+
const bytes = new Uint8Array(binary.length);
|
|
469
|
+
for (let i = 0; i < binary.length; i++) {
|
|
470
|
+
bytes[i] = binary.charCodeAt(i);
|
|
471
|
+
}
|
|
472
|
+
return bytes;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
/**
|
|
476
|
+
* Converts a Uint8Array to a hex string.
|
|
477
|
+
*
|
|
478
|
+
* @param bytes - The byte array to encode
|
|
479
|
+
* @returns Hex encoded string (lowercase, no prefix)
|
|
480
|
+
*/
|
|
481
|
+
protected uint8ArrayToHex(bytes: Uint8Array): string {
|
|
482
|
+
return Array.from(bytes)
|
|
483
|
+
.map((b) => b.toString(16).padStart(2, '0'))
|
|
484
|
+
.join('');
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
/**
|
|
488
|
+
* Converts a hex string to a Uint8Array.
|
|
489
|
+
*
|
|
490
|
+
* @param hex - The hex string to decode (with or without 0x prefix)
|
|
491
|
+
* @returns Decoded byte array
|
|
492
|
+
*/
|
|
493
|
+
protected hexToUint8Array(hex: string): Uint8Array {
|
|
494
|
+
const cleanHex = hex.startsWith('0x') ? hex.slice(2) : hex;
|
|
495
|
+
const bytes = new Uint8Array(cleanHex.length / 2);
|
|
496
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
497
|
+
bytes[i] = parseInt(cleanHex.substr(i * 2, 2), 16);
|
|
498
|
+
}
|
|
499
|
+
return bytes;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* Converts a string to a hex-encoded string.
|
|
504
|
+
*
|
|
505
|
+
* @param str - The string to encode
|
|
506
|
+
* @returns Hex encoded string
|
|
507
|
+
*/
|
|
508
|
+
protected stringToHex(str: string): string {
|
|
509
|
+
const encoder = new TextEncoder();
|
|
510
|
+
return this.uint8ArrayToHex(encoder.encode(str));
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
/**
|
|
514
|
+
* Converts a hex-encoded string back to a regular string.
|
|
515
|
+
*
|
|
516
|
+
* @param hex - The hex string to decode
|
|
517
|
+
* @returns Decoded string
|
|
518
|
+
*/
|
|
519
|
+
protected hexToString(hex: string): string {
|
|
520
|
+
const bytes = this.hexToUint8Array(hex);
|
|
521
|
+
const decoder = new TextDecoder();
|
|
522
|
+
return decoder.decode(bytes);
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
// ============================================================================
|
|
526
|
+
// Error Handling
|
|
527
|
+
// ============================================================================
|
|
528
|
+
|
|
529
|
+
/**
|
|
530
|
+
* Wraps an async operation with standardized error handling.
|
|
531
|
+
*
|
|
532
|
+
* Catches errors from the operation and wraps them in
|
|
533
|
+
* TransactionBuilderError with appropriate context.
|
|
534
|
+
*
|
|
535
|
+
* @param operation - Name of the operation for error context
|
|
536
|
+
* @param fn - The async function to execute
|
|
537
|
+
* @returns The result of the function
|
|
538
|
+
* @throws TransactionBuilderError with context if operation fails
|
|
539
|
+
*/
|
|
540
|
+
protected async withErrorHandling<T>(operation: string, fn: () => Promise<T>): Promise<T> {
|
|
541
|
+
try {
|
|
542
|
+
return await fn();
|
|
543
|
+
} catch (error) {
|
|
544
|
+
// If it's already a TransactionBuilderError, re-throw
|
|
545
|
+
if (error instanceof TransactionBuilderError) {
|
|
546
|
+
this.logger.error(`${operation} failed`, {
|
|
547
|
+
code: error.code,
|
|
548
|
+
message: error.message,
|
|
549
|
+
context: error.context,
|
|
550
|
+
});
|
|
551
|
+
throw error;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
// Wrap other errors
|
|
555
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
556
|
+
this.logger.error(`${operation} failed with unexpected error`, {
|
|
557
|
+
operation,
|
|
558
|
+
error: message,
|
|
559
|
+
});
|
|
560
|
+
|
|
561
|
+
throw new TransactionBuilderError(
|
|
562
|
+
TransactionBuilderErrorCode.VALIDATION_ERROR,
|
|
563
|
+
`${operation} failed: ${message}`,
|
|
564
|
+
{ operation, originalError: message },
|
|
565
|
+
);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
// ============================================================================
|
|
570
|
+
// Abstract Methods (to be implemented by subclasses)
|
|
571
|
+
// ============================================================================
|
|
572
|
+
|
|
573
|
+
/**
|
|
574
|
+
* Serializes a transaction to a base64-encoded string.
|
|
575
|
+
* Must be implemented by ledger-specific subclasses.
|
|
576
|
+
*
|
|
577
|
+
* @param transaction - The transaction object to serialize
|
|
578
|
+
* @param payerAccount - The account paying for the transaction
|
|
579
|
+
* @returns Base64 encoded transaction bytes
|
|
580
|
+
*/
|
|
581
|
+
protected abstract serializeTransaction(
|
|
582
|
+
transaction: unknown,
|
|
583
|
+
payerAccount: string,
|
|
584
|
+
): Promise<string>;
|
|
585
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
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
|
+
* Scale a whole-token amount up to base units using the token's decimals
|
|
13
|
+
* value, with bigint arithmetic so 10^decimals never overflows JS number
|
|
14
|
+
* precision.
|
|
15
|
+
*
|
|
16
|
+
* Mirror of the canonical helper at
|
|
17
|
+
* `packages/transaction-builders/src/lib/hedera-amount-utils.ts`. Kept in
|
|
18
|
+
* sync deliberately — the angular-sdk does not depend on the
|
|
19
|
+
* transaction-builders package (each maintains its own builder copy), so a
|
|
20
|
+
* shared re-export is not currently possible without introducing a new
|
|
21
|
+
* workspace dep. The canonical file carries the vitest spec; this copy
|
|
22
|
+
* exists solely so consumers importing from `@hsuite/native-connect-angular`
|
|
23
|
+
* have a single import surface.
|
|
24
|
+
*
|
|
25
|
+
* @param amount
|
|
26
|
+
* @param decimals
|
|
27
|
+
* @see packages/transaction-builders/src/lib/hedera-amount-utils.ts
|
|
28
|
+
*/
|
|
29
|
+
// SYNC-START: scaleHederaAmountToBaseUnits — see __tests__/sync.spec.ts
|
|
30
|
+
export function scaleHederaAmountToBaseUnits(amount: number, decimals: number): bigint {
|
|
31
|
+
if (!Number.isFinite(amount)) {
|
|
32
|
+
throw new RangeError(
|
|
33
|
+
`scaleHederaAmountToBaseUnits: amount must be a finite number, got ${amount}`,
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
if (amount < 0) {
|
|
37
|
+
throw new RangeError(
|
|
38
|
+
`scaleHederaAmountToBaseUnits: amount must be non-negative, got ${amount}`,
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
if (!Number.isInteger(decimals)) {
|
|
42
|
+
throw new RangeError(
|
|
43
|
+
`scaleHederaAmountToBaseUnits: decimals must be an integer, got ${decimals}`,
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
if (decimals < 0) {
|
|
47
|
+
throw new RangeError(
|
|
48
|
+
`scaleHederaAmountToBaseUnits: decimals must be non-negative, got ${decimals}`,
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
if (amount === 0) return 0n;
|
|
52
|
+
const whole = Math.trunc(amount);
|
|
53
|
+
const fraction = amount - whole;
|
|
54
|
+
const scale = 10n ** BigInt(decimals);
|
|
55
|
+
const wholePart = BigInt(whole) * scale;
|
|
56
|
+
if (fraction === 0) return wholePart;
|
|
57
|
+
const fractionalPart = BigInt(Math.round(fraction * Number(scale)));
|
|
58
|
+
return wholePart + fractionalPart;
|
|
59
|
+
}
|
|
60
|
+
// SYNC-END: scaleHederaAmountToBaseUnits
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Narrow a `bigint` to a JS `number` after asserting it fits within
|
|
64
|
+
* `Number.MAX_SAFE_INTEGER`. Throws `RangeError` with the supplied context
|
|
65
|
+
* on overflow.
|
|
66
|
+
*
|
|
67
|
+
* Mirror of the canonical helper at
|
|
68
|
+
* `packages/transaction-builders/src/lib/hedera-amount-utils.ts`. Kept in
|
|
69
|
+
* sync deliberately — see the SYNC note above.
|
|
70
|
+
* @param value
|
|
71
|
+
* @param context
|
|
72
|
+
*/
|
|
73
|
+
// SYNC-START: assertSafeInteger — see __tests__/sync.spec.ts
|
|
74
|
+
export function assertSafeInteger(value: bigint, context: string): number {
|
|
75
|
+
const max = BigInt(Number.MAX_SAFE_INTEGER);
|
|
76
|
+
const min = BigInt(Number.MIN_SAFE_INTEGER);
|
|
77
|
+
if (value > max || value < min) {
|
|
78
|
+
throw new RangeError(
|
|
79
|
+
`${context}: value ${value.toString()} exceeds JS safe-integer range (${Number.MIN_SAFE_INTEGER}..${Number.MAX_SAFE_INTEGER}). The Hedera SDK accepts Long for larger values; if you need >2^53 base units, the builder signature must widen to accept Long/bigint.`,
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
return Number(value);
|
|
83
|
+
}
|
|
84
|
+
// SYNC-END: assertSafeInteger
|