@sidhujag/sysweb3-keyring 1.0.544 → 1.0.547

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 (212) hide show
  1. package/coverage/clover.xml +2875 -0
  2. package/coverage/coverage-final.json +29468 -0
  3. package/coverage/lcov-report/base.css +354 -0
  4. package/coverage/lcov-report/block-navigation.js +85 -0
  5. package/coverage/lcov-report/favicon.png +0 -0
  6. package/coverage/lcov-report/index.html +320 -0
  7. package/coverage/lcov-report/prettify.css +101 -0
  8. package/coverage/lcov-report/prettify.js +1008 -0
  9. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  10. package/coverage/lcov-report/sorter.js +191 -0
  11. package/coverage/lcov-report/src/index.html +276 -0
  12. package/coverage/lcov-report/src/index.ts.html +114 -0
  13. package/coverage/lcov-report/src/initial-state.ts.html +558 -0
  14. package/coverage/lcov-report/src/keyring-manager.ts.html +6279 -0
  15. package/coverage/lcov-report/src/ledger/bitcoin_client/index.html +178 -0
  16. package/coverage/lcov-report/src/ledger/bitcoin_client/index.ts.html +144 -0
  17. package/coverage/lcov-report/src/ledger/bitcoin_client/lib/appClient.ts.html +1560 -0
  18. package/coverage/lcov-report/src/ledger/bitcoin_client/lib/bip32.ts.html +276 -0
  19. package/coverage/lcov-report/src/ledger/bitcoin_client/lib/buffertools.ts.html +495 -0
  20. package/coverage/lcov-report/src/ledger/bitcoin_client/lib/clientCommands.ts.html +1138 -0
  21. package/coverage/lcov-report/src/ledger/bitcoin_client/lib/index.html +363 -0
  22. package/coverage/lcov-report/src/ledger/bitcoin_client/lib/merkelizedPsbt.ts.html +289 -0
  23. package/coverage/lcov-report/src/ledger/bitcoin_client/lib/merkle.ts.html +486 -0
  24. package/coverage/lcov-report/src/ledger/bitcoin_client/lib/merkleMap.ts.html +240 -0
  25. package/coverage/lcov-report/src/ledger/bitcoin_client/lib/policy.ts.html +342 -0
  26. package/coverage/lcov-report/src/ledger/bitcoin_client/lib/psbtv2.ts.html +2388 -0
  27. package/coverage/lcov-report/src/ledger/bitcoin_client/lib/varint.ts.html +453 -0
  28. package/coverage/lcov-report/src/ledger/consts.ts.html +177 -0
  29. package/coverage/lcov-report/src/ledger/index.html +216 -0
  30. package/coverage/lcov-report/src/ledger/index.ts.html +1371 -0
  31. package/coverage/lcov-report/src/ledger/utils.ts.html +102 -0
  32. package/coverage/lcov-report/src/signers.ts.html +591 -0
  33. package/coverage/lcov-report/src/storage.ts.html +198 -0
  34. package/coverage/lcov-report/src/transactions/ethereum.ts.html +5826 -0
  35. package/coverage/lcov-report/src/transactions/index.html +216 -0
  36. package/coverage/lcov-report/src/transactions/index.ts.html +93 -0
  37. package/coverage/lcov-report/src/transactions/syscoin.ts.html +1521 -0
  38. package/coverage/lcov-report/src/trezor/index.html +176 -0
  39. package/coverage/lcov-report/src/trezor/index.ts.html +2655 -0
  40. package/coverage/lcov-report/src/types.ts.html +1443 -0
  41. package/coverage/lcov-report/src/utils/derivation-paths.ts.html +486 -0
  42. package/coverage/lcov-report/src/utils/index.html +196 -0
  43. package/coverage/lcov-report/src/utils/psbt.ts.html +159 -0
  44. package/coverage/lcov-report/test/helpers/constants.ts.html +627 -0
  45. package/coverage/lcov-report/test/helpers/index.html +176 -0
  46. package/coverage/lcov.info +4832 -0
  47. package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/appClient.js +1 -124
  48. package/dist/cjs/ledger/bitcoin_client/lib/appClient.js.map +1 -0
  49. package/{cjs → dist/cjs}/transactions/ethereum.js +24 -11
  50. package/dist/cjs/transactions/ethereum.js.map +1 -0
  51. package/dist/package.json +50 -0
  52. package/{types → dist/types}/ledger/bitcoin_client/lib/appClient.d.ts +0 -6
  53. package/examples/basic-usage.js +140 -0
  54. package/jest.config.js +32 -0
  55. package/package.json +31 -13
  56. package/readme.md +201 -0
  57. package/src/declare.d.ts +7 -0
  58. package/src/errorUtils.ts +83 -0
  59. package/src/hardware-wallet-manager.ts +655 -0
  60. package/src/index.ts +12 -0
  61. package/src/initial-state.ts +108 -0
  62. package/src/keyring-manager.ts +2698 -0
  63. package/src/ledger/bitcoin_client/index.ts +19 -0
  64. package/src/ledger/bitcoin_client/lib/appClient.ts +405 -0
  65. package/src/ledger/bitcoin_client/lib/bip32.ts +61 -0
  66. package/src/ledger/bitcoin_client/lib/buffertools.ts +134 -0
  67. package/src/ledger/bitcoin_client/lib/clientCommands.ts +356 -0
  68. package/src/ledger/bitcoin_client/lib/constants.ts +12 -0
  69. package/src/ledger/bitcoin_client/lib/merkelizedPsbt.ts +65 -0
  70. package/src/ledger/bitcoin_client/lib/merkle.ts +136 -0
  71. package/src/ledger/bitcoin_client/lib/merkleMap.ts +49 -0
  72. package/src/ledger/bitcoin_client/lib/policy.ts +91 -0
  73. package/src/ledger/bitcoin_client/lib/psbtv2.ts +768 -0
  74. package/src/ledger/bitcoin_client/lib/varint.ts +120 -0
  75. package/src/ledger/consts.ts +3 -0
  76. package/src/ledger/index.ts +685 -0
  77. package/src/ledger/types.ts +74 -0
  78. package/src/network-utils.ts +99 -0
  79. package/src/providers.ts +345 -0
  80. package/src/signers.ts +158 -0
  81. package/src/storage.ts +63 -0
  82. package/src/transactions/__tests__/integration.test.ts +303 -0
  83. package/src/transactions/__tests__/syscoin.test.ts +409 -0
  84. package/src/transactions/ethereum.ts +2503 -0
  85. package/src/transactions/index.ts +2 -0
  86. package/src/transactions/syscoin.ts +542 -0
  87. package/src/trezor/index.ts +1050 -0
  88. package/src/types.ts +366 -0
  89. package/src/utils/derivation-paths.ts +133 -0
  90. package/src/utils/psbt.ts +24 -0
  91. package/src/utils.ts +191 -0
  92. package/test/README.md +158 -0
  93. package/test/__mocks__/ledger-mock.js +20 -0
  94. package/test/__mocks__/trezor-mock.js +75 -0
  95. package/test/cleanup-summary.md +167 -0
  96. package/test/helpers/README.md +78 -0
  97. package/test/helpers/constants.ts +79 -0
  98. package/test/helpers/setup.ts +714 -0
  99. package/test/integration/import-validation.spec.ts +588 -0
  100. package/test/unit/hardware/ledger.spec.ts +869 -0
  101. package/test/unit/hardware/trezor.spec.ts +828 -0
  102. package/test/unit/keyring-manager/account-management.spec.ts +970 -0
  103. package/test/unit/keyring-manager/import-watchonly.spec.ts +181 -0
  104. package/test/unit/keyring-manager/import-wif.spec.ts +126 -0
  105. package/test/unit/keyring-manager/initialization.spec.ts +782 -0
  106. package/test/unit/keyring-manager/key-derivation.spec.ts +996 -0
  107. package/test/unit/keyring-manager/security.spec.ts +505 -0
  108. package/test/unit/keyring-manager/state-management.spec.ts +375 -0
  109. package/test/unit/network/network-management.spec.ts +372 -0
  110. package/test/unit/transactions/ethereum-transactions.spec.ts +382 -0
  111. package/test/unit/transactions/syscoin-transactions.spec.ts +615 -0
  112. package/tsconfig.json +14 -0
  113. package/cjs/ledger/bitcoin_client/lib/appClient.js.map +0 -1
  114. package/cjs/transactions/ethereum.js.map +0 -1
  115. /package/{README.md → dist/README.md} +0 -0
  116. /package/{cjs → dist/cjs}/errorUtils.js +0 -0
  117. /package/{cjs → dist/cjs}/errorUtils.js.map +0 -0
  118. /package/{cjs → dist/cjs}/hardware-wallet-manager.js +0 -0
  119. /package/{cjs → dist/cjs}/hardware-wallet-manager.js.map +0 -0
  120. /package/{cjs → dist/cjs}/index.js +0 -0
  121. /package/{cjs → dist/cjs}/index.js.map +0 -0
  122. /package/{cjs → dist/cjs}/initial-state.js +0 -0
  123. /package/{cjs → dist/cjs}/initial-state.js.map +0 -0
  124. /package/{cjs → dist/cjs}/keyring-manager.js +0 -0
  125. /package/{cjs → dist/cjs}/keyring-manager.js.map +0 -0
  126. /package/{cjs → dist/cjs}/ledger/bitcoin_client/index.js +0 -0
  127. /package/{cjs → dist/cjs}/ledger/bitcoin_client/index.js.map +0 -0
  128. /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/bip32.js +0 -0
  129. /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/bip32.js.map +0 -0
  130. /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/buffertools.js +0 -0
  131. /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/buffertools.js.map +0 -0
  132. /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/clientCommands.js +0 -0
  133. /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/clientCommands.js.map +0 -0
  134. /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/constants.js +0 -0
  135. /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/constants.js.map +0 -0
  136. /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/merkelizedPsbt.js +0 -0
  137. /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/merkelizedPsbt.js.map +0 -0
  138. /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/merkle.js +0 -0
  139. /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/merkle.js.map +0 -0
  140. /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/merkleMap.js +0 -0
  141. /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/merkleMap.js.map +0 -0
  142. /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/policy.js +0 -0
  143. /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/policy.js.map +0 -0
  144. /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/psbtv2.js +0 -0
  145. /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/psbtv2.js.map +0 -0
  146. /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/varint.js +0 -0
  147. /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/varint.js.map +0 -0
  148. /package/{cjs → dist/cjs}/ledger/consts.js +0 -0
  149. /package/{cjs → dist/cjs}/ledger/consts.js.map +0 -0
  150. /package/{cjs → dist/cjs}/ledger/index.js +0 -0
  151. /package/{cjs → dist/cjs}/ledger/index.js.map +0 -0
  152. /package/{cjs → dist/cjs}/ledger/types.js +0 -0
  153. /package/{cjs → dist/cjs}/ledger/types.js.map +0 -0
  154. /package/{cjs → dist/cjs}/network-utils.js +0 -0
  155. /package/{cjs → dist/cjs}/network-utils.js.map +0 -0
  156. /package/{cjs → dist/cjs}/providers.js +0 -0
  157. /package/{cjs → dist/cjs}/providers.js.map +0 -0
  158. /package/{cjs → dist/cjs}/signers.js +0 -0
  159. /package/{cjs → dist/cjs}/signers.js.map +0 -0
  160. /package/{cjs → dist/cjs}/storage.js +0 -0
  161. /package/{cjs → dist/cjs}/storage.js.map +0 -0
  162. /package/{cjs → dist/cjs}/transactions/__tests__/integration.test.js +0 -0
  163. /package/{cjs → dist/cjs}/transactions/__tests__/integration.test.js.map +0 -0
  164. /package/{cjs → dist/cjs}/transactions/__tests__/syscoin.test.js +0 -0
  165. /package/{cjs → dist/cjs}/transactions/__tests__/syscoin.test.js.map +0 -0
  166. /package/{cjs → dist/cjs}/transactions/index.js +0 -0
  167. /package/{cjs → dist/cjs}/transactions/index.js.map +0 -0
  168. /package/{cjs → dist/cjs}/transactions/syscoin.js +0 -0
  169. /package/{cjs → dist/cjs}/transactions/syscoin.js.map +0 -0
  170. /package/{cjs → dist/cjs}/trezor/index.js +0 -0
  171. /package/{cjs → dist/cjs}/trezor/index.js.map +0 -0
  172. /package/{cjs → dist/cjs}/types.js +0 -0
  173. /package/{cjs → dist/cjs}/types.js.map +0 -0
  174. /package/{cjs → dist/cjs}/utils/derivation-paths.js +0 -0
  175. /package/{cjs → dist/cjs}/utils/derivation-paths.js.map +0 -0
  176. /package/{cjs → dist/cjs}/utils/psbt.js +0 -0
  177. /package/{cjs → dist/cjs}/utils/psbt.js.map +0 -0
  178. /package/{cjs → dist/cjs}/utils.js +0 -0
  179. /package/{cjs → dist/cjs}/utils.js.map +0 -0
  180. /package/{types → dist/types}/errorUtils.d.ts +0 -0
  181. /package/{types → dist/types}/hardware-wallet-manager.d.ts +0 -0
  182. /package/{types → dist/types}/index.d.ts +0 -0
  183. /package/{types → dist/types}/initial-state.d.ts +0 -0
  184. /package/{types → dist/types}/keyring-manager.d.ts +0 -0
  185. /package/{types → dist/types}/ledger/bitcoin_client/index.d.ts +0 -0
  186. /package/{types → dist/types}/ledger/bitcoin_client/lib/bip32.d.ts +0 -0
  187. /package/{types → dist/types}/ledger/bitcoin_client/lib/buffertools.d.ts +0 -0
  188. /package/{types → dist/types}/ledger/bitcoin_client/lib/clientCommands.d.ts +0 -0
  189. /package/{types → dist/types}/ledger/bitcoin_client/lib/constants.d.ts +0 -0
  190. /package/{types → dist/types}/ledger/bitcoin_client/lib/merkelizedPsbt.d.ts +0 -0
  191. /package/{types → dist/types}/ledger/bitcoin_client/lib/merkle.d.ts +0 -0
  192. /package/{types → dist/types}/ledger/bitcoin_client/lib/merkleMap.d.ts +0 -0
  193. /package/{types → dist/types}/ledger/bitcoin_client/lib/policy.d.ts +0 -0
  194. /package/{types → dist/types}/ledger/bitcoin_client/lib/psbtv2.d.ts +0 -0
  195. /package/{types → dist/types}/ledger/bitcoin_client/lib/varint.d.ts +0 -0
  196. /package/{types → dist/types}/ledger/consts.d.ts +0 -0
  197. /package/{types → dist/types}/ledger/index.d.ts +0 -0
  198. /package/{types → dist/types}/ledger/types.d.ts +0 -0
  199. /package/{types → dist/types}/network-utils.d.ts +0 -0
  200. /package/{types → dist/types}/providers.d.ts +0 -0
  201. /package/{types → dist/types}/signers.d.ts +0 -0
  202. /package/{types → dist/types}/storage.d.ts +0 -0
  203. /package/{types → dist/types}/transactions/__tests__/integration.test.d.ts +0 -0
  204. /package/{types → dist/types}/transactions/__tests__/syscoin.test.d.ts +0 -0
  205. /package/{types → dist/types}/transactions/ethereum.d.ts +0 -0
  206. /package/{types → dist/types}/transactions/index.d.ts +0 -0
  207. /package/{types → dist/types}/transactions/syscoin.d.ts +0 -0
  208. /package/{types → dist/types}/trezor/index.d.ts +0 -0
  209. /package/{types → dist/types}/types.d.ts +0 -0
  210. /package/{types → dist/types}/utils/derivation-paths.d.ts +0 -0
  211. /package/{types → dist/types}/utils/psbt.d.ts +0 -0
  212. /package/{types → dist/types}/utils.d.ts +0 -0
package/src/storage.ts ADDED
@@ -0,0 +1,63 @@
1
+ import { sysweb3Di } from '@sidhujag/sysweb3-core';
2
+ import CryptoJS from 'crypto-js';
3
+
4
+ const storage = sysweb3Di.getStateStorageDb();
5
+
6
+ // Simple async mutex implementation to prevent concurrent vault operations
7
+ class AsyncMutex {
8
+ private mutex = Promise.resolve();
9
+
10
+ async runExclusive<T>(callback: () => Promise<T>): Promise<T> {
11
+ const oldMutex = this.mutex;
12
+
13
+ let release: () => void;
14
+ this.mutex = new Promise((resolve) => {
15
+ release = resolve;
16
+ });
17
+
18
+ await oldMutex;
19
+ try {
20
+ return await callback();
21
+ } finally {
22
+ release!();
23
+ }
24
+ }
25
+ }
26
+
27
+ const vaultMutex = new AsyncMutex();
28
+
29
+ // Single vault for all networks - stores the mnemonic and can derive accounts for any slip44
30
+ export const setEncryptedVault = async (decryptedVault: any, pwd: string) => {
31
+ return vaultMutex.runExclusive(async () => {
32
+ const encryptedVault = CryptoJS.AES.encrypt(
33
+ JSON.stringify(decryptedVault),
34
+ pwd
35
+ );
36
+
37
+ // Always use single 'vault' key for all networks
38
+ await storage.set('vault', encryptedVault.toString());
39
+ });
40
+ };
41
+
42
+ export const getDecryptedVault = async (pwd: string) => {
43
+ return vaultMutex.runExclusive(async () => {
44
+ // Always use single 'vault' key
45
+ const vault = await storage.get('vault');
46
+
47
+ if (!vault) {
48
+ throw new Error('Vault not found');
49
+ }
50
+
51
+ const decryptedVault = CryptoJS.AES.decrypt(vault, pwd).toString(
52
+ CryptoJS.enc.Utf8
53
+ );
54
+
55
+ if (!decryptedVault) {
56
+ throw new Error(
57
+ 'Failed to decrypt vault - invalid password or corrupted data'
58
+ );
59
+ }
60
+
61
+ return JSON.parse(decryptedVault);
62
+ });
63
+ };
@@ -0,0 +1,303 @@
1
+ import { KeyringAccountType } from '../../types';
2
+ import { SyscoinTransactions } from '../syscoin';
3
+
4
+ // Integration tests for the complete transaction flow
5
+ describe('PSBT Transaction Flow Integration', () => {
6
+ let syscoinTransactions: SyscoinTransactions;
7
+ let mockSigner: any;
8
+ let mockState: any;
9
+ let mockLedger: any;
10
+
11
+ beforeEach(() => {
12
+ // Setup comprehensive mocks
13
+ mockSigner = {
14
+ hd: {
15
+ Signer: { network: 'mainnet' },
16
+ sign: jest.fn().mockResolvedValue('signed-psbt'),
17
+ },
18
+ main: {
19
+ blockbookURL: 'https://blockbook.test',
20
+ createPSBTFromRes: jest.fn().mockResolvedValue('unsigned-psbt'),
21
+ assetAllocationSend: jest.fn().mockResolvedValue({
22
+ psbt: 'unsigned-token-psbt',
23
+ }),
24
+ send: jest.fn().mockResolvedValue({
25
+ extractTransaction: () => ({ getId: () => 'final-txid' }),
26
+ }),
27
+ },
28
+ };
29
+
30
+ mockState = {
31
+ activeAccountId: 0,
32
+ activeAccountType: KeyringAccountType.HDAccount,
33
+ accounts: {
34
+ [KeyringAccountType.HDAccount]: {
35
+ 0: { xpub: 'xpub123', id: 0 },
36
+ },
37
+ },
38
+ activeNetwork: { currency: 'sys', chainId: 57 },
39
+ };
40
+
41
+ mockLedger = {
42
+ ledgerTransport: true,
43
+ ledgerUtxoClient: {
44
+ getMasterFingerprint: jest.fn().mockResolvedValue('fingerprint'),
45
+ signPsbt: jest.fn().mockResolvedValue([[0, { signature: 'sig' }]]),
46
+ },
47
+ };
48
+
49
+ const mockGetAddress = jest.fn().mockResolvedValue('change-address');
50
+
51
+ const mockTrezor = {
52
+ init: jest.fn(),
53
+ convertToTrezorFormat: jest.fn(),
54
+ signUtxoTransaction: jest.fn(),
55
+ } as any;
56
+
57
+ syscoinTransactions = new SyscoinTransactions(
58
+ () => mockSigner,
59
+ () => mockSigner, // getReadOnlySigner - same mock for testing
60
+ () => mockState,
61
+ mockGetAddress,
62
+ mockLedger,
63
+ mockTrezor
64
+ );
65
+ });
66
+
67
+ describe('Complete Native Transaction Flow', () => {
68
+ it('should handle native transaction from creation to broadcast', async () => {
69
+ // Step 1: Create unsigned PSBT and get fee
70
+ const { fee, psbt: unsignedPsbt } =
71
+ await syscoinTransactions.getEstimateSysTransactionFee({
72
+ amount: 1,
73
+ receivingAddress: 'sys1qtest',
74
+ feeRate: 0.00001,
75
+ });
76
+
77
+ expect(fee).toBeGreaterThan(0);
78
+ expect(unsignedPsbt).toBeDefined();
79
+
80
+ // Step 2: Sign the PSBT
81
+ const signedPsbt = await syscoinTransactions.signPSBT({
82
+ psbt: unsignedPsbt,
83
+ isTrezor: false,
84
+ isLedger: false,
85
+ });
86
+
87
+ // Step 3: Send the signed PSBT
88
+ const result = await syscoinTransactions.sendTransaction(signedPsbt);
89
+
90
+ expect(result.txid).toBe('final-txid');
91
+ expect(mockSigner.main.send).toHaveBeenCalledWith(signedPsbt);
92
+ });
93
+ });
94
+
95
+ describe('Complete Token Transaction Flow', () => {
96
+ it('should handle token transaction from creation to broadcast', async () => {
97
+ // Mock token lookup
98
+ jest.doMock('@sidhujag/sysweb3-utils', () => ({
99
+ getAsset: jest.fn().mockResolvedValue({
100
+ assetGuid: 'token123',
101
+ decimals: 8,
102
+ }),
103
+ }));
104
+
105
+ // Step 1: Create unsigned token PSBT and get fee
106
+ const { fee, psbt: unsignedPsbt } =
107
+ await syscoinTransactions.getEstimateSysTransactionFee({
108
+ amount: 100,
109
+ receivingAddress: 'sys1qtest',
110
+ token: { guid: 'token123', symbol: 'TEST' },
111
+ });
112
+
113
+ expect(fee).toBeGreaterThan(0);
114
+ expect(unsignedPsbt).toBeDefined();
115
+ expect(mockSigner.main.assetAllocationSend).toHaveBeenCalledWith(
116
+ expect.any(Object),
117
+ expect.any(Map),
118
+ 'change-address',
119
+ expect.any(Object),
120
+ 'xpub123'
121
+ );
122
+
123
+ // Step 2: Sign the token PSBT
124
+ const signedPsbt = await syscoinTransactions.signPSBT({
125
+ psbt: unsignedPsbt,
126
+ isTrezor: false,
127
+ isLedger: false,
128
+ });
129
+
130
+ // Step 3: Send the signed PSBT
131
+ const result = await syscoinTransactions.sendTransaction(signedPsbt);
132
+
133
+ expect(result.txid).toBe('final-txid');
134
+ });
135
+ });
136
+
137
+ describe('Hardware Wallet Integration', () => {
138
+ it('should handle Trezor transaction flow', async () => {
139
+ const mockTrezor = {
140
+ init: jest.fn(),
141
+ convertToTrezorFormat: jest.fn().mockReturnValue('trezor-format'),
142
+ signUtxoTransaction: jest.fn().mockResolvedValue('trezor-signed-psbt'),
143
+ };
144
+ (syscoinTransactions as any).trezor = mockTrezor;
145
+
146
+ // Create unsigned PSBT
147
+ const { fee, psbt: unsignedPsbt } =
148
+ await syscoinTransactions.getEstimateSysTransactionFee({
149
+ amount: 1,
150
+ receivingAddress: 'sys1qtest',
151
+ });
152
+
153
+ expect(fee).toBeGreaterThan(0);
154
+ expect(unsignedPsbt).toBeDefined();
155
+
156
+ // Sign with Trezor
157
+ const signedPsbt = await syscoinTransactions.signPSBT({
158
+ psbt: unsignedPsbt,
159
+ isTrezor: true,
160
+ });
161
+
162
+ expect(mockTrezor.init).toHaveBeenCalled();
163
+ expect(mockTrezor.signUtxoTransaction).toHaveBeenCalled();
164
+ expect(signedPsbt).toBe('trezor-signed-psbt');
165
+
166
+ // Send
167
+ const result = await syscoinTransactions.sendTransaction(signedPsbt);
168
+
169
+ expect(result.txid).toBe('final-txid');
170
+ });
171
+
172
+ it('should handle Ledger transaction flow', async () => {
173
+ mockState.activeAccountType = KeyringAccountType.Ledger;
174
+ mockState.accounts[KeyringAccountType.Ledger] = {
175
+ 0: { xpub: 'ledger-xpub', id: 0, isLedgerWallet: true },
176
+ };
177
+
178
+ // Mock Psbt for Ledger
179
+ jest.doMock('syscoinjs-lib', () => ({
180
+ Psbt: {
181
+ fromBase64: jest.fn().mockReturnValue({
182
+ updateInput: jest.fn(),
183
+ finalizeAllInputs: jest.fn(),
184
+ toBase64: jest.fn().mockReturnValue('ledger-signed-psbt'),
185
+ }),
186
+ },
187
+ }));
188
+
189
+ // Create unsigned PSBT
190
+ const { fee, psbt: unsignedPsbt } =
191
+ await syscoinTransactions.getEstimateSysTransactionFee({
192
+ amount: 1,
193
+ receivingAddress: 'sys1qtest',
194
+ });
195
+
196
+ expect(fee).toBeGreaterThan(0);
197
+ expect(unsignedPsbt).toBeDefined();
198
+
199
+ // Sign with Ledger
200
+ const signedPsbt = await syscoinTransactions.signPSBT({
201
+ psbt: unsignedPsbt,
202
+ isLedger: true,
203
+ });
204
+
205
+ expect(mockLedger.ledgerUtxoClient.signPsbt).toHaveBeenCalled();
206
+ expect(signedPsbt).toBeDefined();
207
+
208
+ // Send
209
+ const result = await syscoinTransactions.sendTransaction(signedPsbt);
210
+
211
+ expect(result.txid).toBe('final-txid');
212
+ });
213
+ });
214
+
215
+ describe('Error Scenarios', () => {
216
+ it('should handle signing errors separately from sending errors', async () => {
217
+ // Test signing error
218
+ mockSigner.hd.sign = jest
219
+ .fn()
220
+ .mockRejectedValue(new Error('Device disconnected'));
221
+
222
+ await expect(
223
+ syscoinTransactions.getEstimateSysTransactionFee({
224
+ amount: 1,
225
+ receivingAddress: 'sys1qtest',
226
+ })
227
+ ).rejects.toThrow('Failed to sign transaction: Device disconnected');
228
+
229
+ // Test sending error
230
+ mockSigner.main.send = jest
231
+ .fn()
232
+ .mockRejectedValue(new Error('Network error'));
233
+
234
+ await expect(
235
+ syscoinTransactions.sendTransaction('valid-psbt')
236
+ ).rejects.toThrow('Failed to send transaction');
237
+ });
238
+
239
+ it('should require PSBT for sendTransaction', async () => {
240
+ await expect(syscoinTransactions.sendTransaction('')).rejects.toThrow(
241
+ 'Pre-signed PSBT is required'
242
+ );
243
+ });
244
+ });
245
+
246
+ describe('Fee Calculation', () => {
247
+ it('should calculate correct fees for multi-input transactions', async () => {
248
+ // Mock multiple UTXOs
249
+ const mockUtxos = [
250
+ { txid: 'tx1', vout: 0, value: '50000000' },
251
+ { txid: 'tx2', vout: 1, value: '30000000' },
252
+ { txid: 'tx3', vout: 0, value: '20000000' },
253
+ ];
254
+
255
+ jest.doMock('syscoinjs-lib', () => ({
256
+ utils: {
257
+ fetchBackendUTXOS: jest.fn().mockResolvedValue(mockUtxos),
258
+ sanitizeBlockbookUTXOs: jest.fn().mockReturnValue(mockUtxos),
259
+ },
260
+ }));
261
+
262
+ jest.doMock('coinselectsyscoin', () => ({
263
+ utils: {
264
+ transactionBytes: jest.fn().mockReturnValue(500), // Larger tx with multiple inputs
265
+ },
266
+ }));
267
+
268
+ const { fee } = await syscoinTransactions.getEstimateSysTransactionFee({
269
+ amount: 0.8, // Amount that requires multiple UTXOs
270
+ receivingAddress: 'sys1qtest',
271
+ feeRate: 0.00001,
272
+ });
273
+
274
+ // Fee should be proportional to transaction size
275
+ expect(fee).toBeGreaterThan(0.00001); // More than minimum
276
+ });
277
+ });
278
+
279
+ describe('RBF Support', () => {
280
+ it('should create RBF-enabled transactions by default', async () => {
281
+ await syscoinTransactions.getEstimateSysTransactionFee({
282
+ amount: 1,
283
+ receivingAddress: 'sys1qtest',
284
+ });
285
+
286
+ // Check that RBF was enabled in the transaction options
287
+ expect(mockSigner.main.createPSBTFromRes).toHaveBeenCalled();
288
+ const callArgs = mockSigner.main.createPSBTFromRes.mock.calls[0];
289
+ expect(callArgs[0]).toMatchObject({ rbf: true });
290
+ });
291
+
292
+ it('should disable RBF when requested', async () => {
293
+ await syscoinTransactions.getEstimateSysTransactionFee({
294
+ amount: 1,
295
+ receivingAddress: 'sys1qtest',
296
+ txOptions: { rbf: false },
297
+ });
298
+
299
+ const callArgs = mockSigner.main.createPSBTFromRes.mock.calls[0];
300
+ expect(callArgs[0]).toMatchObject({ rbf: false });
301
+ });
302
+ });
303
+ });