@bsv/sdk 2.0.12 → 2.0.13

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 (77) hide show
  1. package/dist/cjs/package.json +1 -1
  2. package/dist/cjs/src/auth/clients/__tests__/AuthFetch.additional.test.js +827 -0
  3. package/dist/cjs/src/auth/clients/__tests__/AuthFetch.additional.test.js.map +1 -0
  4. package/dist/cjs/src/auth/transports/__tests__/SimplifiedFetchTransport.additional.test.js +654 -0
  5. package/dist/cjs/src/auth/transports/__tests__/SimplifiedFetchTransport.additional.test.js.map +1 -0
  6. package/dist/cjs/src/transaction/MerklePath.js +132 -0
  7. package/dist/cjs/src/transaction/MerklePath.js.map +1 -1
  8. package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
  9. package/dist/esm/src/auth/clients/__tests__/AuthFetch.additional.test.js +825 -0
  10. package/dist/esm/src/auth/clients/__tests__/AuthFetch.additional.test.js.map +1 -0
  11. package/dist/esm/src/auth/transports/__tests__/SimplifiedFetchTransport.additional.test.js +619 -0
  12. package/dist/esm/src/auth/transports/__tests__/SimplifiedFetchTransport.additional.test.js.map +1 -0
  13. package/dist/esm/src/transaction/MerklePath.js +132 -0
  14. package/dist/esm/src/transaction/MerklePath.js.map +1 -1
  15. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  16. package/dist/types/src/auth/clients/__tests__/AuthFetch.additional.test.d.ts +21 -0
  17. package/dist/types/src/auth/clients/__tests__/AuthFetch.additional.test.d.ts.map +1 -0
  18. package/dist/types/src/auth/transports/__tests__/SimplifiedFetchTransport.additional.test.d.ts +2 -0
  19. package/dist/types/src/auth/transports/__tests__/SimplifiedFetchTransport.additional.test.d.ts.map +1 -0
  20. package/dist/types/src/transaction/MerklePath.d.ts +27 -0
  21. package/dist/types/src/transaction/MerklePath.d.ts.map +1 -1
  22. package/dist/types/tsconfig.types.tsbuildinfo +1 -1
  23. package/dist/umd/bundle.js +1 -1
  24. package/dist/umd/bundle.js.map +1 -1
  25. package/docs/reference/storage.md +1 -1
  26. package/docs/reference/transaction.md +40 -0
  27. package/package.json +1 -1
  28. package/src/auth/clients/__tests__/AuthFetch.additional.test.ts +1131 -0
  29. package/src/auth/transports/__tests__/SimplifiedFetchTransport.additional.test.ts +770 -0
  30. package/src/compat/__tests/Mnemonic.additional.test.ts +64 -0
  31. package/src/identity/__tests/IdentityClient.additional.test.ts +767 -0
  32. package/src/kvstore/__tests/LocalKVStore.additional.test.ts +611 -0
  33. package/src/kvstore/__tests/kvStoreInterpreter.test.ts +327 -0
  34. package/src/overlay-tools/__tests/HostReputationTracker.additional.test.ts +561 -0
  35. package/src/overlay-tools/__tests/LookupResolver.additional.test.ts +612 -0
  36. package/src/overlay-tools/__tests/withDoubleSpendRetry.test.ts +278 -0
  37. package/src/primitives/__tests/BigNumber.additional.test.ts +79 -0
  38. package/src/primitives/__tests/Curve.additional.test.ts +208 -0
  39. package/src/primitives/__tests/ECDSA.additional.test.ts +122 -0
  40. package/src/primitives/__tests/Hash.additional.test.ts +59 -0
  41. package/src/primitives/__tests/JacobianPoint.test.ts +308 -0
  42. package/src/primitives/__tests/Point.additional.test.ts +503 -0
  43. package/src/primitives/__tests/PublicKey.additional.test.ts +383 -0
  44. package/src/primitives/__tests/Random.additional.test.ts +262 -0
  45. package/src/primitives/__tests/Signature.test.ts +333 -0
  46. package/src/primitives/__tests/TransactionSignature.additional.test.ts +241 -0
  47. package/src/registry/__tests/RegistryClient.additional.test.ts +750 -0
  48. package/src/remittance/__tests/BasicBRC29.additional.test.ts +657 -0
  49. package/src/remittance/__tests/RemittanceManager.additional.test.ts +1272 -0
  50. package/src/script/__tests/LockingUnlockingScript.test.ts +79 -0
  51. package/src/script/__tests/Script.additional.test.ts +100 -0
  52. package/src/script/__tests/ScriptEvaluationError.test.ts +98 -0
  53. package/src/script/__tests/Spend.additional.test.ts +837 -0
  54. package/src/script/templates/__tests/RPuzzle.test.ts +134 -0
  55. package/src/transaction/MerklePath.ts +155 -0
  56. package/src/transaction/__tests/BeefParty.additional.test.ts +22 -0
  57. package/src/transaction/__tests/Broadcaster.test.ts +159 -0
  58. package/src/transaction/__tests/MerklePath.bench.test.ts +105 -0
  59. package/src/transaction/__tests/MerklePath.test.ts +80 -0
  60. package/src/transaction/__tests/Transaction.additional.test.ts +225 -0
  61. package/src/transaction/broadcasters/__tests/ARC.additional.test.ts +585 -0
  62. package/src/transaction/broadcasters/__tests/Teranode.test.ts +349 -0
  63. package/src/transaction/chaintrackers/__tests/BlockHeadersService.test.ts +253 -0
  64. package/src/transaction/chaintrackers/__tests/DefaultChainTracker.test.ts +44 -0
  65. package/src/transaction/chaintrackers/__tests/WhatsOnChain.additional.test.ts +193 -0
  66. package/src/transaction/fee-models/__tests/SatoshisPerKilobyte.test.ts +262 -0
  67. package/src/transaction/http/__tests/BinaryFetchClient.test.ts +212 -0
  68. package/src/transaction/http/__tests/DefaultHttpClient.additional.test.ts +192 -0
  69. package/src/transaction/http/__tests/DefaultHttpClient.test.ts +71 -0
  70. package/src/wallet/__tests/ProtoWallet.additional.test.ts +134 -0
  71. package/src/wallet/__tests/WERR.test.ts +212 -0
  72. package/src/wallet/__tests/WalletClient.additional.test.ts +699 -0
  73. package/src/wallet/__tests/WalletClient.substrate.test.ts +759 -0
  74. package/src/wallet/__tests/WalletError.test.ts +290 -0
  75. package/src/wallet/__tests/validationHelpers.test.ts +1218 -0
  76. package/src/wallet/substrates/__tests/HTTPWalletJSON.test.ts +496 -0
  77. package/src/wallet/substrates/__tests/HTTPWalletWire.test.ts +273 -0
@@ -0,0 +1,759 @@
1
+ /**
2
+ * WalletClient substrate delegation tests.
3
+ *
4
+ * These tests exercise every public method that ultimately delegates to the
5
+ * substrate object (lines 215-370 and 446-499 of WalletClient.ts). Each test
6
+ * bypasses the real `connectToSubstrate()` logic by pre-injecting a mock
7
+ * substrate directly onto the instance, which avoids any real network I/O.
8
+ */
9
+
10
+ import WalletClient from '../WalletClient'
11
+ import type { WalletInterface } from '../Wallet.interfaces'
12
+
13
+ // ---------------------------------------------------------------------------
14
+ // Helper: create a fully-mocked substrate and an already-connected WalletClient
15
+ // ---------------------------------------------------------------------------
16
+
17
+ function buildMockSubstrate (): jest.Mocked<WalletInterface> {
18
+ return {
19
+ createAction: jest.fn(),
20
+ signAction: jest.fn(),
21
+ abortAction: jest.fn(),
22
+ listActions: jest.fn(),
23
+ internalizeAction: jest.fn(),
24
+ listOutputs: jest.fn(),
25
+ relinquishOutput: jest.fn(),
26
+ getPublicKey: jest.fn(),
27
+ revealCounterpartyKeyLinkage: jest.fn(),
28
+ revealSpecificKeyLinkage: jest.fn(),
29
+ encrypt: jest.fn(),
30
+ decrypt: jest.fn(),
31
+ createHmac: jest.fn(),
32
+ verifyHmac: jest.fn(),
33
+ createSignature: jest.fn(),
34
+ verifySignature: jest.fn(),
35
+ acquireCertificate: jest.fn(),
36
+ listCertificates: jest.fn(),
37
+ proveCertificate: jest.fn(),
38
+ relinquishCertificate: jest.fn(),
39
+ discoverByIdentityKey: jest.fn(),
40
+ discoverByAttributes: jest.fn(),
41
+ isAuthenticated: jest.fn(),
42
+ waitForAuthentication: jest.fn(),
43
+ getHeight: jest.fn(),
44
+ getHeaderForHeight: jest.fn(),
45
+ getNetwork: jest.fn(),
46
+ getVersion: jest.fn(),
47
+ } as jest.Mocked<WalletInterface>
48
+ }
49
+
50
+ /** Creates a WalletClient whose substrate is already the given mock object. */
51
+ function clientWith (mock: jest.Mocked<WalletInterface>, originator = 'test.origin'): WalletClient {
52
+ const client = new WalletClient(mock, originator)
53
+ return client
54
+ }
55
+
56
+ // ---------------------------------------------------------------------------
57
+ // relinquishOutput
58
+ // ---------------------------------------------------------------------------
59
+
60
+ describe('WalletClient.relinquishOutput – substrate delegation', () => {
61
+ it('delegates to substrate.relinquishOutput and returns its result', async () => {
62
+ const mock = buildMockSubstrate()
63
+ mock.relinquishOutput.mockResolvedValue({ relinquished: true })
64
+ const client = clientWith(mock)
65
+
66
+ const result = await client.relinquishOutput({
67
+ basket: 'default',
68
+ output: 'a'.repeat(64) + '.0',
69
+ })
70
+
71
+ expect(result).toEqual({ relinquished: true })
72
+ expect(mock.relinquishOutput).toHaveBeenCalledTimes(1)
73
+ expect(mock.relinquishOutput).toHaveBeenCalledWith(
74
+ { basket: 'default', output: 'a'.repeat(64) + '.0' },
75
+ 'test.origin'
76
+ )
77
+ })
78
+
79
+ it('propagates errors thrown by the substrate', async () => {
80
+ const mock = buildMockSubstrate()
81
+ mock.relinquishOutput.mockRejectedValue(new Error('substrate error'))
82
+ const client = clientWith(mock)
83
+
84
+ await expect(
85
+ client.relinquishOutput({ basket: 'default', output: 'a'.repeat(64) + '.0' })
86
+ ).rejects.toThrow('substrate error')
87
+ })
88
+ })
89
+
90
+ // ---------------------------------------------------------------------------
91
+ // getPublicKey
92
+ // ---------------------------------------------------------------------------
93
+
94
+ describe('WalletClient.getPublicKey – substrate delegation', () => {
95
+ it('returns the public key from the substrate', async () => {
96
+ const mock = buildMockSubstrate()
97
+ const expectedKey = 'aa'.repeat(33)
98
+ mock.getPublicKey.mockResolvedValue({ publicKey: expectedKey })
99
+ const client = clientWith(mock)
100
+
101
+ const result = await client.getPublicKey({ identityKey: true })
102
+
103
+ expect(result).toEqual({ publicKey: expectedKey })
104
+ expect(mock.getPublicKey).toHaveBeenCalledWith({ identityKey: true }, 'test.origin')
105
+ })
106
+
107
+ it('passes protocolID and keyID through to the substrate', async () => {
108
+ const mock = buildMockSubstrate()
109
+ mock.getPublicKey.mockResolvedValue({ publicKey: 'bb'.repeat(33) })
110
+ const client = clientWith(mock)
111
+
112
+ await client.getPublicKey({
113
+ protocolID: [2, 'my-protocol'],
114
+ keyID: '1',
115
+ counterparty: 'self',
116
+ })
117
+
118
+ expect(mock.getPublicKey).toHaveBeenCalledWith(
119
+ { protocolID: [2, 'my-protocol'], keyID: '1', counterparty: 'self' },
120
+ 'test.origin'
121
+ )
122
+ })
123
+ })
124
+
125
+ // ---------------------------------------------------------------------------
126
+ // revealCounterpartyKeyLinkage
127
+ // ---------------------------------------------------------------------------
128
+
129
+ describe('WalletClient.revealCounterpartyKeyLinkage – substrate delegation', () => {
130
+ it('delegates and returns the linkage result', async () => {
131
+ const mock = buildMockSubstrate()
132
+ const fakeResult = {
133
+ prover: 'aa'.repeat(33),
134
+ verifier: 'bb'.repeat(33),
135
+ counterparty: 'cc'.repeat(33),
136
+ revelationTime: '2024-01-01T00:00:00.000Z',
137
+ encryptedLinkage: [1, 2, 3],
138
+ encryptedLinkageProof: [4, 5, 6],
139
+ }
140
+ mock.revealCounterpartyKeyLinkage.mockResolvedValue(fakeResult)
141
+ const client = clientWith(mock)
142
+
143
+ const args = {
144
+ counterparty: 'cc'.repeat(33),
145
+ verifier: 'bb'.repeat(33),
146
+ }
147
+ const result = await client.revealCounterpartyKeyLinkage(args)
148
+
149
+ expect(result).toEqual(fakeResult)
150
+ expect(mock.revealCounterpartyKeyLinkage).toHaveBeenCalledWith(args, 'test.origin')
151
+ })
152
+ })
153
+
154
+ // ---------------------------------------------------------------------------
155
+ // revealSpecificKeyLinkage
156
+ // ---------------------------------------------------------------------------
157
+
158
+ describe('WalletClient.revealSpecificKeyLinkage – substrate delegation', () => {
159
+ it('delegates and returns the specific linkage result', async () => {
160
+ const mock = buildMockSubstrate()
161
+ const fakeResult = {
162
+ prover: 'aa'.repeat(33),
163
+ verifier: 'bb'.repeat(33),
164
+ counterparty: 'cc'.repeat(33),
165
+ protocolID: [1, 'proto'] as [0 | 1 | 2, string],
166
+ keyID: '1',
167
+ encryptedLinkage: [1],
168
+ encryptedLinkageProof: [2],
169
+ proofType: 1,
170
+ }
171
+ mock.revealSpecificKeyLinkage.mockResolvedValue(fakeResult)
172
+ const client = clientWith(mock)
173
+
174
+ const args = {
175
+ counterparty: 'cc'.repeat(33),
176
+ verifier: 'bb'.repeat(33),
177
+ protocolID: [1, 'proto'] as [0 | 1 | 2, string],
178
+ keyID: '1',
179
+ }
180
+ const result = await client.revealSpecificKeyLinkage(args)
181
+
182
+ expect(result).toEqual(fakeResult)
183
+ expect(mock.revealSpecificKeyLinkage).toHaveBeenCalledWith(args, 'test.origin')
184
+ })
185
+ })
186
+
187
+ // ---------------------------------------------------------------------------
188
+ // encrypt / decrypt
189
+ // ---------------------------------------------------------------------------
190
+
191
+ describe('WalletClient.encrypt – substrate delegation', () => {
192
+ it('returns ciphertext from the substrate', async () => {
193
+ const mock = buildMockSubstrate()
194
+ mock.encrypt.mockResolvedValue({ ciphertext: [9, 8, 7] })
195
+ const client = clientWith(mock)
196
+
197
+ const args = {
198
+ plaintext: [1, 2, 3],
199
+ protocolID: [1, 'enc-proto'] as [0 | 1 | 2, string],
200
+ keyID: '1',
201
+ }
202
+ const result = await client.encrypt(args)
203
+
204
+ expect(result).toEqual({ ciphertext: [9, 8, 7] })
205
+ expect(mock.encrypt).toHaveBeenCalledWith(args, 'test.origin')
206
+ })
207
+ })
208
+
209
+ describe('WalletClient.decrypt – substrate delegation', () => {
210
+ it('returns plaintext from the substrate', async () => {
211
+ const mock = buildMockSubstrate()
212
+ mock.decrypt.mockResolvedValue({ plaintext: [42] })
213
+ const client = clientWith(mock)
214
+
215
+ const args = {
216
+ ciphertext: [9, 8, 7],
217
+ protocolID: [1, 'enc-proto'] as [0 | 1 | 2, string],
218
+ keyID: '1',
219
+ }
220
+ const result = await client.decrypt(args)
221
+
222
+ expect(result).toEqual({ plaintext: [42] })
223
+ expect(mock.decrypt).toHaveBeenCalledWith(args, 'test.origin')
224
+ })
225
+ })
226
+
227
+ // ---------------------------------------------------------------------------
228
+ // createHmac / verifyHmac
229
+ // ---------------------------------------------------------------------------
230
+
231
+ describe('WalletClient.createHmac – substrate delegation', () => {
232
+ it('returns hmac bytes from the substrate', async () => {
233
+ const mock = buildMockSubstrate()
234
+ mock.createHmac.mockResolvedValue({ hmac: [0, 1, 2, 3] })
235
+ const client = clientWith(mock)
236
+
237
+ const args = {
238
+ data: [10, 20],
239
+ protocolID: [2, 'hmac-proto'] as [0 | 1 | 2, string],
240
+ keyID: '1',
241
+ }
242
+ const result = await client.createHmac(args)
243
+
244
+ expect(result).toEqual({ hmac: [0, 1, 2, 3] })
245
+ expect(mock.createHmac).toHaveBeenCalledWith(args, 'test.origin')
246
+ })
247
+ })
248
+
249
+ describe('WalletClient.verifyHmac – substrate delegation', () => {
250
+ it('returns { valid: true } from the substrate', async () => {
251
+ const mock = buildMockSubstrate()
252
+ mock.verifyHmac.mockResolvedValue({ valid: true })
253
+ const client = clientWith(mock)
254
+
255
+ const args = {
256
+ data: [10, 20],
257
+ hmac: [0, 1, 2, 3],
258
+ protocolID: [2, 'hmac-proto'] as [0 | 1 | 2, string],
259
+ keyID: '1',
260
+ }
261
+ const result = await client.verifyHmac(args)
262
+
263
+ expect(result).toEqual({ valid: true })
264
+ expect(mock.verifyHmac).toHaveBeenCalledWith(args, 'test.origin')
265
+ })
266
+ })
267
+
268
+ // ---------------------------------------------------------------------------
269
+ // createSignature / verifySignature
270
+ // ---------------------------------------------------------------------------
271
+
272
+ describe('WalletClient.createSignature – substrate delegation', () => {
273
+ it('returns signature bytes from the substrate', async () => {
274
+ const mock = buildMockSubstrate()
275
+ mock.createSignature.mockResolvedValue({ signature: [5, 6, 7] })
276
+ const client = clientWith(mock)
277
+
278
+ const args = {
279
+ data: [1, 2],
280
+ protocolID: [1, 'sig-proto'] as [0 | 1 | 2, string],
281
+ keyID: '1',
282
+ }
283
+ const result = await client.createSignature(args)
284
+
285
+ expect(result).toEqual({ signature: [5, 6, 7] })
286
+ expect(mock.createSignature).toHaveBeenCalledWith(args, 'test.origin')
287
+ })
288
+ })
289
+
290
+ describe('WalletClient.verifySignature – substrate delegation', () => {
291
+ it('returns { valid: true } from the substrate', async () => {
292
+ const mock = buildMockSubstrate()
293
+ mock.verifySignature.mockResolvedValue({ valid: true })
294
+ const client = clientWith(mock)
295
+
296
+ const args = {
297
+ data: [1, 2],
298
+ signature: [5, 6, 7],
299
+ protocolID: [1, 'sig-proto'] as [0 | 1 | 2, string],
300
+ keyID: '1',
301
+ }
302
+ const result = await client.verifySignature(args)
303
+
304
+ expect(result).toEqual({ valid: true })
305
+ expect(mock.verifySignature).toHaveBeenCalledWith(args, 'test.origin')
306
+ })
307
+ })
308
+
309
+ // ---------------------------------------------------------------------------
310
+ // acquireCertificate
311
+ // ---------------------------------------------------------------------------
312
+
313
+ describe('WalletClient.acquireCertificate – substrate delegation', () => {
314
+ const baseCert = {
315
+ type: 'dHlwZQ==',
316
+ certifier: 'aa'.repeat(33),
317
+ fields: { name: 'alice' },
318
+ acquisitionProtocol: 'direct' as const,
319
+ serialNumber: 'c2VyaWFs',
320
+ revocationOutpoint: 'a'.repeat(64) + '.0',
321
+ signature: 'aabb',
322
+ keyringRevealer: 'certifier' as const,
323
+ keyringForSubject: {},
324
+ }
325
+
326
+ it('delegates direct acquisition to substrate and returns result', async () => {
327
+ const mock = buildMockSubstrate()
328
+ mock.acquireCertificate.mockResolvedValue({ ...baseCert } as any)
329
+ const client = clientWith(mock)
330
+
331
+ const result = await client.acquireCertificate(baseCert)
332
+
333
+ expect(result).toMatchObject({ type: 'dHlwZQ==' })
334
+ expect(mock.acquireCertificate).toHaveBeenCalledWith(baseCert, 'test.origin')
335
+ })
336
+
337
+ it('delegates issuance acquisition to substrate', async () => {
338
+ const mock = buildMockSubstrate()
339
+ const issuanceCert = {
340
+ type: 'dHlwZQ==',
341
+ certifier: 'aa'.repeat(33),
342
+ fields: {},
343
+ acquisitionProtocol: 'issuance' as const,
344
+ certifierUrl: 'https://certifier.example.com',
345
+ }
346
+ mock.acquireCertificate.mockResolvedValue(issuanceCert as any)
347
+ const client = clientWith(mock)
348
+
349
+ const result = await client.acquireCertificate(issuanceCert)
350
+
351
+ expect(mock.acquireCertificate).toHaveBeenCalledWith(issuanceCert, 'test.origin')
352
+ expect(result).toMatchObject({ acquisitionProtocol: 'issuance' })
353
+ })
354
+ })
355
+
356
+ // ---------------------------------------------------------------------------
357
+ // listCertificates
358
+ // ---------------------------------------------------------------------------
359
+
360
+ describe('WalletClient.listCertificates – substrate delegation', () => {
361
+ it('delegates to substrate and returns the certificate list', async () => {
362
+ const mock = buildMockSubstrate()
363
+ const fakeList = { certificates: [], totalCertificates: 0 }
364
+ mock.listCertificates.mockResolvedValue(fakeList)
365
+ const client = clientWith(mock)
366
+
367
+ const args = { certifiers: ['aa'.repeat(33)], types: ['dHlwZQ=='] }
368
+ const result = await client.listCertificates(args)
369
+
370
+ expect(result).toEqual(fakeList)
371
+ expect(mock.listCertificates).toHaveBeenCalledWith(args, 'test.origin')
372
+ })
373
+ })
374
+
375
+ // ---------------------------------------------------------------------------
376
+ // proveCertificate
377
+ // ---------------------------------------------------------------------------
378
+
379
+ describe('WalletClient.proveCertificate – substrate delegation', () => {
380
+ it('delegates to substrate and returns prove result', async () => {
381
+ const mock = buildMockSubstrate()
382
+ const fakeResult = { keyringForVerifier: {} }
383
+ mock.proveCertificate.mockResolvedValue(fakeResult as any)
384
+ const client = clientWith(mock)
385
+
386
+ const args = {
387
+ certificate: {
388
+ type: 'dHlwZQ==',
389
+ certifier: 'aa'.repeat(33),
390
+ serialNumber: 'c2VyaWFs',
391
+ fields: {},
392
+ subject: 'bb'.repeat(33),
393
+ revocationOutpoint: 'a'.repeat(64) + '.0',
394
+ signature: 'aabb',
395
+ } as any,
396
+ fieldsToReveal: ['name'],
397
+ verifier: 'cc'.repeat(33),
398
+ }
399
+ const result = await client.proveCertificate(args)
400
+
401
+ expect(result).toEqual(fakeResult)
402
+ expect(mock.proveCertificate).toHaveBeenCalledWith(args, 'test.origin')
403
+ })
404
+ })
405
+
406
+ // ---------------------------------------------------------------------------
407
+ // relinquishCertificate
408
+ // ---------------------------------------------------------------------------
409
+
410
+ describe('WalletClient.relinquishCertificate – substrate delegation', () => {
411
+ it('delegates to substrate and returns relinquished result', async () => {
412
+ const mock = buildMockSubstrate()
413
+ mock.relinquishCertificate.mockResolvedValue({ relinquished: true })
414
+ const client = clientWith(mock)
415
+
416
+ const args = {
417
+ type: 'dHlwZQ==',
418
+ serialNumber: 'c2VyaWFs',
419
+ certifier: 'aa'.repeat(33),
420
+ }
421
+ const result = await client.relinquishCertificate(args)
422
+
423
+ expect(result).toEqual({ relinquished: true })
424
+ expect(mock.relinquishCertificate).toHaveBeenCalledWith(args, 'test.origin')
425
+ })
426
+ })
427
+
428
+ // ---------------------------------------------------------------------------
429
+ // discoverByIdentityKey
430
+ // ---------------------------------------------------------------------------
431
+
432
+ describe('WalletClient.discoverByIdentityKey – substrate delegation', () => {
433
+ it('delegates to substrate and returns discovered certificates', async () => {
434
+ const mock = buildMockSubstrate()
435
+ const fakeResult = { certificates: [], totalCertificates: 0 }
436
+ mock.discoverByIdentityKey.mockResolvedValue(fakeResult)
437
+ const client = clientWith(mock)
438
+
439
+ const args = { identityKey: 'aa'.repeat(33) }
440
+ const result = await client.discoverByIdentityKey(args)
441
+
442
+ expect(result).toEqual(fakeResult)
443
+ expect(mock.discoverByIdentityKey).toHaveBeenCalledWith(args, 'test.origin')
444
+ })
445
+ })
446
+
447
+ // ---------------------------------------------------------------------------
448
+ // discoverByAttributes
449
+ // ---------------------------------------------------------------------------
450
+
451
+ describe('WalletClient.discoverByAttributes – substrate delegation', () => {
452
+ it('delegates to substrate and returns discovered certificates', async () => {
453
+ const mock = buildMockSubstrate()
454
+ const fakeResult = { certificates: [], totalCertificates: 0 }
455
+ mock.discoverByAttributes.mockResolvedValue(fakeResult)
456
+ const client = clientWith(mock)
457
+
458
+ const args = { attributes: { name: 'alice' } }
459
+ const result = await client.discoverByAttributes(args)
460
+
461
+ expect(result).toEqual(fakeResult)
462
+ expect(mock.discoverByAttributes).toHaveBeenCalledWith(args, 'test.origin')
463
+ })
464
+ })
465
+
466
+ // ---------------------------------------------------------------------------
467
+ // isAuthenticated
468
+ // ---------------------------------------------------------------------------
469
+
470
+ describe('WalletClient.isAuthenticated – substrate delegation', () => {
471
+ it('delegates to substrate and returns authenticated status', async () => {
472
+ const mock = buildMockSubstrate()
473
+ mock.isAuthenticated.mockResolvedValue({ authenticated: true })
474
+ const client = clientWith(mock)
475
+
476
+ const result = await client.isAuthenticated({})
477
+
478
+ expect(result).toEqual({ authenticated: true })
479
+ expect(mock.isAuthenticated).toHaveBeenCalledWith({}, 'test.origin')
480
+ })
481
+
482
+ it('uses default empty object when no args provided', async () => {
483
+ const mock = buildMockSubstrate()
484
+ mock.isAuthenticated.mockResolvedValue({ authenticated: false } as any)
485
+ const client = clientWith(mock)
486
+
487
+ const result = await client.isAuthenticated()
488
+
489
+ expect(result).toEqual({ authenticated: false })
490
+ expect(mock.isAuthenticated).toHaveBeenCalledWith({}, 'test.origin')
491
+ })
492
+ })
493
+
494
+ // ---------------------------------------------------------------------------
495
+ // waitForAuthentication
496
+ // ---------------------------------------------------------------------------
497
+
498
+ describe('WalletClient.waitForAuthentication – substrate delegation', () => {
499
+ it('delegates to substrate and resolves when authenticated', async () => {
500
+ const mock = buildMockSubstrate()
501
+ mock.waitForAuthentication.mockResolvedValue({ authenticated: true })
502
+ const client = clientWith(mock)
503
+
504
+ const result = await client.waitForAuthentication({})
505
+
506
+ expect(result).toEqual({ authenticated: true })
507
+ expect(mock.waitForAuthentication).toHaveBeenCalledWith({}, 'test.origin')
508
+ })
509
+ })
510
+
511
+ // ---------------------------------------------------------------------------
512
+ // getHeight
513
+ // ---------------------------------------------------------------------------
514
+
515
+ describe('WalletClient.getHeight – substrate delegation', () => {
516
+ it('returns current block height from substrate', async () => {
517
+ const mock = buildMockSubstrate()
518
+ mock.getHeight.mockResolvedValue({ height: 800000 })
519
+ const client = clientWith(mock)
520
+
521
+ const result = await client.getHeight({})
522
+
523
+ expect(result).toEqual({ height: 800000 })
524
+ expect(mock.getHeight).toHaveBeenCalledWith({}, 'test.origin')
525
+ })
526
+
527
+ it('uses default empty object when no args provided', async () => {
528
+ const mock = buildMockSubstrate()
529
+ mock.getHeight.mockResolvedValue({ height: 1 })
530
+ const client = clientWith(mock)
531
+
532
+ await client.getHeight()
533
+
534
+ expect(mock.getHeight).toHaveBeenCalledWith({}, 'test.origin')
535
+ })
536
+ })
537
+
538
+ // ---------------------------------------------------------------------------
539
+ // getHeaderForHeight
540
+ // ---------------------------------------------------------------------------
541
+
542
+ describe('WalletClient.getHeaderForHeight – substrate delegation', () => {
543
+ it('returns block header hex from substrate', async () => {
544
+ const mock = buildMockSubstrate()
545
+ mock.getHeaderForHeight.mockResolvedValue({ header: 'deadbeef' })
546
+ const client = clientWith(mock)
547
+
548
+ const result = await client.getHeaderForHeight({ height: 800000 })
549
+
550
+ expect(result).toEqual({ header: 'deadbeef' })
551
+ expect(mock.getHeaderForHeight).toHaveBeenCalledWith({ height: 800000 }, 'test.origin')
552
+ })
553
+ })
554
+
555
+ // ---------------------------------------------------------------------------
556
+ // getNetwork
557
+ // ---------------------------------------------------------------------------
558
+
559
+ describe('WalletClient.getNetwork – substrate delegation', () => {
560
+ it('returns mainnet from substrate', async () => {
561
+ const mock = buildMockSubstrate()
562
+ mock.getNetwork.mockResolvedValue({ network: 'mainnet' })
563
+ const client = clientWith(mock)
564
+
565
+ const result = await client.getNetwork({})
566
+
567
+ expect(result).toEqual({ network: 'mainnet' })
568
+ expect(mock.getNetwork).toHaveBeenCalledWith({}, 'test.origin')
569
+ })
570
+
571
+ it('returns testnet from substrate', async () => {
572
+ const mock = buildMockSubstrate()
573
+ mock.getNetwork.mockResolvedValue({ network: 'testnet' })
574
+ const client = clientWith(mock)
575
+
576
+ const result = await client.getNetwork()
577
+
578
+ expect(result).toEqual({ network: 'testnet' })
579
+ expect(mock.getNetwork).toHaveBeenCalledWith({}, 'test.origin')
580
+ })
581
+ })
582
+
583
+ // ---------------------------------------------------------------------------
584
+ // getVersion
585
+ // ---------------------------------------------------------------------------
586
+
587
+ describe('WalletClient.getVersion – substrate delegation', () => {
588
+ it('returns version string from substrate', async () => {
589
+ const mock = buildMockSubstrate()
590
+ mock.getVersion.mockResolvedValue({ version: '1.0.0.0.0.0.0' })
591
+ const client = clientWith(mock)
592
+
593
+ const result = await client.getVersion({})
594
+
595
+ expect(result).toEqual({ version: '1.0.0.0.0.0.0' })
596
+ expect(mock.getVersion).toHaveBeenCalledWith({}, 'test.origin')
597
+ })
598
+
599
+ it('uses default empty object when no args provided', async () => {
600
+ const mock = buildMockSubstrate()
601
+ mock.getVersion.mockResolvedValue({ version: '2.0.0.0.0.0.0' })
602
+ const client = clientWith(mock)
603
+
604
+ await client.getVersion()
605
+
606
+ expect(mock.getVersion).toHaveBeenCalledWith({}, 'test.origin')
607
+ })
608
+ })
609
+
610
+ // ---------------------------------------------------------------------------
611
+ // createAction – successful delegation
612
+ // ---------------------------------------------------------------------------
613
+
614
+ describe('WalletClient.createAction – substrate delegation', () => {
615
+ it('delegates a valid createAction call to the substrate', async () => {
616
+ const mock = buildMockSubstrate()
617
+ const fakeResult = { txid: 'abc123', tx: [1, 2, 3] }
618
+ mock.createAction.mockResolvedValue(fakeResult as any)
619
+ const client = clientWith(mock)
620
+
621
+ const args = { description: 'hello world' }
622
+ const result = await client.createAction(args)
623
+
624
+ expect(result).toEqual(fakeResult)
625
+ expect(mock.createAction).toHaveBeenCalledWith(args, 'test.origin')
626
+ })
627
+
628
+ it('passes originator undefined when no originator was set', async () => {
629
+ const mock = buildMockSubstrate()
630
+ mock.createAction.mockResolvedValue({ txid: 'xyz' } as any)
631
+ // Create the client by passing the mock object directly (no originator)
632
+ const client = new WalletClient(mock)
633
+
634
+ await client.createAction({ description: 'hello world' })
635
+
636
+ expect(mock.createAction).toHaveBeenCalledWith({ description: 'hello world' }, undefined)
637
+ })
638
+ })
639
+
640
+ // ---------------------------------------------------------------------------
641
+ // signAction – successful delegation
642
+ // ---------------------------------------------------------------------------
643
+
644
+ describe('WalletClient.signAction – substrate delegation', () => {
645
+ it('delegates a valid signAction call to the substrate', async () => {
646
+ const mock = buildMockSubstrate()
647
+ const fakeResult = { txid: 'signed123', tx: [1, 2, 3] }
648
+ mock.signAction.mockResolvedValue(fakeResult as any)
649
+ const client = clientWith(mock)
650
+
651
+ const args = { spends: {}, reference: 'cmVm' }
652
+ const result = await client.signAction(args)
653
+
654
+ expect(result).toEqual(fakeResult)
655
+ expect(mock.signAction).toHaveBeenCalledWith(args, 'test.origin')
656
+ })
657
+ })
658
+
659
+ // ---------------------------------------------------------------------------
660
+ // abortAction – successful delegation
661
+ // ---------------------------------------------------------------------------
662
+
663
+ describe('WalletClient.abortAction – substrate delegation', () => {
664
+ it('delegates a valid abortAction call to the substrate', async () => {
665
+ const mock = buildMockSubstrate()
666
+ mock.abortAction.mockResolvedValue({ aborted: true })
667
+ const client = clientWith(mock)
668
+
669
+ const result = await client.abortAction({ reference: 'cmVm' })
670
+
671
+ expect(result).toEqual({ aborted: true })
672
+ expect(mock.abortAction).toHaveBeenCalledWith({ reference: 'cmVm' }, 'test.origin')
673
+ })
674
+ })
675
+
676
+ // ---------------------------------------------------------------------------
677
+ // listActions – successful delegation
678
+ // ---------------------------------------------------------------------------
679
+
680
+ describe('WalletClient.listActions – substrate delegation', () => {
681
+ it('delegates to substrate and returns action list', async () => {
682
+ const mock = buildMockSubstrate()
683
+ const fakeResult = { actions: [], totalActions: 0 }
684
+ mock.listActions.mockResolvedValue(fakeResult)
685
+ const client = clientWith(mock)
686
+
687
+ const args = { labels: ['my-label'] }
688
+ const result = await client.listActions(args)
689
+
690
+ expect(result).toEqual(fakeResult)
691
+ expect(mock.listActions).toHaveBeenCalledWith(args, 'test.origin')
692
+ })
693
+ })
694
+
695
+ // ---------------------------------------------------------------------------
696
+ // internalizeAction – successful delegation
697
+ // ---------------------------------------------------------------------------
698
+
699
+ describe('WalletClient.internalizeAction – substrate delegation', () => {
700
+ it('delegates to substrate and returns accepted result', async () => {
701
+ const mock = buildMockSubstrate()
702
+ mock.internalizeAction.mockResolvedValue({ accepted: true })
703
+ const client = clientWith(mock)
704
+
705
+ // Minimal valid AtomicBEEF: BEEF_V2 header + 0 bumps + 1 txid-only tx
706
+ // BEEF_V2 = 4022206466 (0xEFBE0002) in little-endian = [2, 0, 190, 239]
707
+ // TX_DATA_FORMAT.TXID_ONLY = 2, followed by 32-byte txid
708
+ const minimalBeef: number[] = [
709
+ 2, 0, 190, 239, // BEEF_V2 version LE
710
+ 0, // 0 bumps (varint)
711
+ 1, // 1 tx (varint)
712
+ 2, // TX_DATA_FORMAT.TXID_ONLY
713
+ ...new Array(32).fill(0) // 32-byte zero txid
714
+ ]
715
+ const args = {
716
+ tx: minimalBeef,
717
+ outputs: [{ outputIndex: 0, protocol: 'wallet payment' as const }],
718
+ description: 'Internalize tx',
719
+ }
720
+ const result = await client.internalizeAction(args)
721
+
722
+ expect(result).toEqual({ accepted: true })
723
+ expect(mock.internalizeAction).toHaveBeenCalledWith(args, 'test.origin')
724
+ })
725
+ })
726
+
727
+ // ---------------------------------------------------------------------------
728
+ // listOutputs – successful delegation
729
+ // ---------------------------------------------------------------------------
730
+
731
+ describe('WalletClient.listOutputs – substrate delegation', () => {
732
+ it('delegates to substrate and returns output list', async () => {
733
+ const mock = buildMockSubstrate()
734
+ const fakeResult = { outputs: [], totalOutputs: 0 }
735
+ mock.listOutputs.mockResolvedValue(fakeResult as any)
736
+ const client = clientWith(mock)
737
+
738
+ const args = { basket: 'default' }
739
+ const result = await client.listOutputs(args)
740
+
741
+ expect(result).toEqual(fakeResult)
742
+ expect(mock.listOutputs).toHaveBeenCalledWith(args, 'test.origin')
743
+ })
744
+ })
745
+
746
+ // ---------------------------------------------------------------------------
747
+ // connectToSubstrate – auto-selection error path
748
+ // ---------------------------------------------------------------------------
749
+
750
+ describe('WalletClient.connectToSubstrate – error when no substrate available', () => {
751
+ it('throws a descriptive error when auto-substrate fails to connect', async () => {
752
+ // The 'auto' substrate string means connectToSubstrate will try real substrates.
753
+ // All of them will fail in a test environment, so an error should be thrown.
754
+ const client = new WalletClient('auto', 'test.origin')
755
+ await expect(client.connectToSubstrate()).rejects.toThrow(
756
+ 'No wallet available over any communication substrate'
757
+ )
758
+ }, 10000)
759
+ })