@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,327 @@
1
+ /** eslint-env jest */
2
+ import { kvStoreInterpreter, KVContext } from '../kvStoreInterpreter'
3
+ import { kvProtocol } from '../types'
4
+ import Transaction from '../../transaction/Transaction'
5
+ import PushDrop from '../../script/templates/PushDrop'
6
+ import * as Utils from '../../primitives/utils'
7
+
8
+ // --- Module mocks -----------------------------------------------------------
9
+
10
+ jest.mock('../../script/templates/PushDrop.js', () => {
11
+ const mockPushDropDecode = jest.fn()
12
+ return Object.assign(
13
+ jest.fn(() => ({})),
14
+ { decode: mockPushDropDecode }
15
+ )
16
+ })
17
+
18
+ jest.mock('../../primitives/utils.js', () => ({
19
+ toArray: jest.fn((str: string) => Array.from(Buffer.from(str, 'utf8'))),
20
+ toUTF8: jest.fn((arr: number[] | Uint8Array) => Buffer.from(arr).toString('utf8'))
21
+ }))
22
+
23
+ // --- Typed mock refs --------------------------------------------------------
24
+
25
+ const MockedPushDrop = PushDrop as jest.MockedClass<typeof PushDrop> & {
26
+ decode: jest.Mock<any, any>
27
+ }
28
+ const MockedPushDropDecode = MockedPushDrop.decode
29
+ const MockedUtils = Utils as jest.Mocked<typeof Utils>
30
+
31
+ // --- Helpers ----------------------------------------------------------------
32
+
33
+ /**
34
+ * Number of fields in the new format (all kvProtocol keys).
35
+ * Old format has one fewer (no tags field).
36
+ */
37
+ const expectedFieldCount = Object.keys(kvProtocol).length // 6
38
+
39
+ function makeMockTransaction (outputs: Array<{ lockingScript?: any } | null>): Transaction {
40
+ return {
41
+ outputs
42
+ } as unknown as Transaction
43
+ }
44
+
45
+ function makeFieldArray (
46
+ protocolID: string,
47
+ key: string,
48
+ value: string,
49
+ controller: string = 'controller',
50
+ includeTagsField: boolean = true
51
+ ): Array<number[]> {
52
+ // Fields in kvProtocol order: protocolID(0), key(1), value(2), controller(3), tags(4), signature(5)
53
+ const fields: Array<number[]> = [
54
+ Array.from(Buffer.from(protocolID)),
55
+ Array.from(Buffer.from(key)),
56
+ Array.from(Buffer.from(value)),
57
+ Array.from(Buffer.from(controller))
58
+ ]
59
+ if (includeTagsField) {
60
+ fields.push(Array.from(Buffer.from('[]'))) // tags
61
+ fields.push(Array.from(Buffer.from('sig'))) // signature
62
+ } else {
63
+ // Old format: no tags, signature at position 4
64
+ fields.push(Array.from(Buffer.from('sig'))) // signature
65
+ }
66
+ return fields
67
+ }
68
+
69
+ import { SecurityLevel, WalletProtocol } from '../../wallet/Wallet.interfaces'
70
+
71
+ function makeCtx (key: string, protocolID: WalletProtocol = [2 as SecurityLevel, 'kvstore']): KVContext {
72
+ return { key, protocolID }
73
+ }
74
+
75
+ // --- Tests ------------------------------------------------------------------
76
+
77
+ describe('kvStoreInterpreter', () => {
78
+ const testKey = 'my-key'
79
+ const testValue = 'my-value'
80
+ const testProtocolID: WalletProtocol = [2 as SecurityLevel, 'kvstore']
81
+ const testCtx = makeCtx(testKey, testProtocolID)
82
+ const protocolIDStr = JSON.stringify(testProtocolID)
83
+
84
+ beforeEach(() => {
85
+ jest.clearAllMocks()
86
+ // Default toUTF8 implementation: convert byte array to string
87
+ MockedUtils.toUTF8.mockImplementation((arr: number[] | Uint8Array) =>
88
+ Buffer.from(arr).toString('utf8')
89
+ )
90
+ })
91
+
92
+ // --- Missing / null guard cases -------------------------------------------
93
+
94
+ describe('returns undefined for missing/invalid inputs', () => {
95
+ it('returns undefined when output at index does not exist', async () => {
96
+ const tx = makeMockTransaction([])
97
+ const result = await kvStoreInterpreter(tx, 0, testCtx)
98
+ expect(result).toBeUndefined()
99
+ })
100
+
101
+ it('returns undefined when output lockingScript is null', async () => {
102
+ const tx = makeMockTransaction([{ lockingScript: null }])
103
+ const result = await kvStoreInterpreter(tx, 0, testCtx)
104
+ expect(result).toBeUndefined()
105
+ })
106
+
107
+ it('returns undefined when output is null', async () => {
108
+ const tx = makeMockTransaction([null])
109
+ const result = await kvStoreInterpreter(tx, 0, testCtx)
110
+ expect(result).toBeUndefined()
111
+ })
112
+
113
+ it('returns undefined when ctx is undefined', async () => {
114
+ const tx = makeMockTransaction([{ lockingScript: {} }])
115
+ const result = await kvStoreInterpreter(tx, 0, undefined)
116
+ expect(result).toBeUndefined()
117
+ })
118
+
119
+ it('returns undefined when ctx is null', async () => {
120
+ const tx = makeMockTransaction([{ lockingScript: {} }])
121
+ const result = await kvStoreInterpreter(tx, 0, null as any)
122
+ expect(result).toBeUndefined()
123
+ })
124
+
125
+ it('returns undefined when ctx.key is null', async () => {
126
+ const tx = makeMockTransaction([{ lockingScript: {} }])
127
+ const result = await kvStoreInterpreter(tx, 0, { key: null as any, protocolID: testProtocolID })
128
+ expect(result).toBeUndefined()
129
+ })
130
+
131
+ it('returns undefined when ctx.key is undefined', async () => {
132
+ const tx = makeMockTransaction([{ lockingScript: {} }])
133
+ const result = await kvStoreInterpreter(tx, 0, { key: undefined as any, protocolID: testProtocolID })
134
+ expect(result).toBeUndefined()
135
+ })
136
+ })
137
+
138
+ // --- PushDrop.decode error cases ------------------------------------------
139
+
140
+ describe('returns undefined when PushDrop.decode throws', () => {
141
+ it('returns undefined when decode throws due to malformed script', async () => {
142
+ MockedPushDropDecode.mockImplementation(() => {
143
+ throw new Error('Malformed script')
144
+ })
145
+ const tx = makeMockTransaction([{ lockingScript: {} }])
146
+ const result = await kvStoreInterpreter(tx, 0, testCtx)
147
+ expect(result).toBeUndefined()
148
+ expect(MockedPushDropDecode).toHaveBeenCalledTimes(1)
149
+ })
150
+ })
151
+
152
+ // --- Wrong field count cases -----------------------------------------------
153
+
154
+ describe('returns undefined when field count is wrong', () => {
155
+ it('returns undefined when decoded fields length is too short (< expectedFieldCount - 1)', async () => {
156
+ // e.g., only 3 fields — neither old nor new format
157
+ MockedPushDropDecode.mockReturnValue({
158
+ fields: [
159
+ Array.from(Buffer.from('id')),
160
+ Array.from(Buffer.from('key')),
161
+ Array.from(Buffer.from('val'))
162
+ ]
163
+ })
164
+ const tx = makeMockTransaction([{ lockingScript: {} }])
165
+ const result = await kvStoreInterpreter(tx, 0, testCtx)
166
+ expect(result).toBeUndefined()
167
+ })
168
+
169
+ it('returns undefined when decoded fields length is too long (> expectedFieldCount)', async () => {
170
+ // More fields than the new format
171
+ const fields = makeFieldArray(protocolIDStr, testKey, testValue)
172
+ fields.push(Array.from(Buffer.from('extra')))
173
+ MockedPushDropDecode.mockReturnValue({ fields })
174
+ const tx = makeMockTransaction([{ lockingScript: {} }])
175
+ const result = await kvStoreInterpreter(tx, 0, testCtx)
176
+ expect(result).toBeUndefined()
177
+ })
178
+ })
179
+
180
+ // --- Key / protocolID mismatch cases --------------------------------------
181
+
182
+ describe('returns undefined when key or protocolID does not match ctx', () => {
183
+ it('returns undefined when key does not match ctx.key (new format)', async () => {
184
+ MockedPushDropDecode.mockReturnValue({
185
+ fields: makeFieldArray(protocolIDStr, 'different-key', testValue)
186
+ })
187
+ // toUTF8 returns the string content of the byte arrays
188
+ MockedUtils.toUTF8
189
+ .mockReturnValueOnce(protocolIDStr) // protocolID field
190
+ .mockReturnValueOnce('different-key') // key field
191
+ const tx = makeMockTransaction([{ lockingScript: {} }])
192
+ const result = await kvStoreInterpreter(tx, 0, testCtx)
193
+ expect(result).toBeUndefined()
194
+ })
195
+
196
+ it('returns undefined when key does not match ctx.key (old format)', async () => {
197
+ MockedPushDropDecode.mockReturnValue({
198
+ fields: makeFieldArray(protocolIDStr, 'wrong-key', testValue, 'controller', false)
199
+ })
200
+ MockedUtils.toUTF8
201
+ .mockReturnValueOnce('wrong-key') // key field
202
+ .mockReturnValueOnce(protocolIDStr) // protocolID field
203
+ const tx = makeMockTransaction([{ lockingScript: {} }])
204
+ const result = await kvStoreInterpreter(tx, 0, testCtx)
205
+ expect(result).toBeUndefined()
206
+ })
207
+
208
+ it('returns undefined when protocolID does not match ctx.protocolID (new format)', async () => {
209
+ const differentProtocol: [number, string] = [1, 'other']
210
+ MockedPushDropDecode.mockReturnValue({
211
+ fields: makeFieldArray(JSON.stringify(differentProtocol), testKey, testValue)
212
+ })
213
+ MockedUtils.toUTF8
214
+ .mockReturnValueOnce(testKey) // key field
215
+ .mockReturnValueOnce(JSON.stringify(differentProtocol)) // protocolID field
216
+ const tx = makeMockTransaction([{ lockingScript: {} }])
217
+ const result = await kvStoreInterpreter(tx, 0, testCtx)
218
+ expect(result).toBeUndefined()
219
+ })
220
+ })
221
+
222
+ // --- Happy path: new format (expectedFieldCount fields) --------------------
223
+
224
+ describe('returns decoded value string for matching outputs', () => {
225
+ it('returns value for new format (expectedFieldCount fields) matching key and protocolID', async () => {
226
+ const newFormatFields = makeFieldArray(protocolIDStr, testKey, testValue, 'controller', true)
227
+ expect(newFormatFields.length).toBe(expectedFieldCount)
228
+
229
+ MockedPushDropDecode.mockReturnValue({ fields: newFormatFields })
230
+ MockedUtils.toUTF8
231
+ .mockReturnValueOnce(testKey) // key field — kvProtocol.key = 1
232
+ .mockReturnValueOnce(protocolIDStr) // protocolID field — kvProtocol.protocolID = 0
233
+ .mockReturnValueOnce(testValue) // value field — kvProtocol.value = 2
234
+
235
+ const tx = makeMockTransaction([{ lockingScript: {} }])
236
+ const result = await kvStoreInterpreter(tx, 0, testCtx)
237
+
238
+ expect(result).toBe(testValue)
239
+ expect(MockedPushDropDecode).toHaveBeenCalledTimes(1)
240
+ })
241
+
242
+ it('returns value for old format (expectedFieldCount - 1 fields) matching key and protocolID', async () => {
243
+ const oldFormatFields = makeFieldArray(protocolIDStr, testKey, testValue, 'controller', false)
244
+ expect(oldFormatFields.length).toBe(expectedFieldCount - 1)
245
+
246
+ MockedPushDropDecode.mockReturnValue({ fields: oldFormatFields })
247
+ MockedUtils.toUTF8
248
+ .mockReturnValueOnce(testKey) // key field
249
+ .mockReturnValueOnce(protocolIDStr) // protocolID field
250
+ .mockReturnValueOnce(testValue) // value field
251
+
252
+ const tx = makeMockTransaction([{ lockingScript: {} }])
253
+ const result = await kvStoreInterpreter(tx, 0, testCtx)
254
+
255
+ expect(result).toBe(testValue)
256
+ expect(MockedPushDropDecode).toHaveBeenCalledTimes(1)
257
+ })
258
+
259
+ it('uses the output at the correct outputIndex', async () => {
260
+ const newFormatFields = makeFieldArray(protocolIDStr, testKey, testValue)
261
+ MockedPushDropDecode.mockReturnValue({ fields: newFormatFields })
262
+ MockedUtils.toUTF8
263
+ .mockReturnValueOnce(testKey)
264
+ .mockReturnValueOnce(protocolIDStr)
265
+ .mockReturnValueOnce(testValue)
266
+
267
+ const tx = makeMockTransaction([
268
+ null, // index 0: non-existent
269
+ { lockingScript: {} } // index 1: valid
270
+ ])
271
+ const result = await kvStoreInterpreter(tx, 1, testCtx)
272
+
273
+ expect(result).toBe(testValue)
274
+ })
275
+ })
276
+
277
+ // --- Inner catch: Utils.toUTF8 throws on value field ----------------------
278
+
279
+ describe('returns undefined when Utils.toUTF8 throws on value field', () => {
280
+ it('returns undefined when toUTF8 throws during value extraction (inner catch)', async () => {
281
+ const newFormatFields = makeFieldArray(protocolIDStr, testKey, testValue)
282
+ MockedPushDropDecode.mockReturnValue({ fields: newFormatFields })
283
+
284
+ // First two calls succeed (key and protocolID match), third throws
285
+ MockedUtils.toUTF8
286
+ .mockReturnValueOnce(testKey)
287
+ .mockReturnValueOnce(protocolIDStr)
288
+ .mockImplementationOnce(() => {
289
+ throw new Error('toUTF8 failed on value')
290
+ })
291
+
292
+ const tx = makeMockTransaction([{ lockingScript: {} }])
293
+ const result = await kvStoreInterpreter(tx, 0, testCtx)
294
+
295
+ expect(result).toBeUndefined()
296
+ })
297
+
298
+ it('returns undefined when toUTF8 throws during key extraction (outer catch)', async () => {
299
+ const newFormatFields = makeFieldArray(protocolIDStr, testKey, testValue)
300
+ MockedPushDropDecode.mockReturnValue({ fields: newFormatFields })
301
+
302
+ // First call (key extraction) throws
303
+ MockedUtils.toUTF8.mockImplementationOnce(() => {
304
+ throw new Error('toUTF8 failed on key')
305
+ })
306
+
307
+ const tx = makeMockTransaction([{ lockingScript: {} }])
308
+ const result = await kvStoreInterpreter(tx, 0, testCtx)
309
+
310
+ expect(result).toBeUndefined()
311
+ })
312
+ })
313
+
314
+ // --- Field index alignment check ------------------------------------------
315
+
316
+ describe('kvProtocol field indices', () => {
317
+ it('has the expected field indices for new format', () => {
318
+ expect(kvProtocol.protocolID).toBe(0)
319
+ expect(kvProtocol.key).toBe(1)
320
+ expect(kvProtocol.value).toBe(2)
321
+ expect(kvProtocol.controller).toBe(3)
322
+ expect(kvProtocol.tags).toBe(4)
323
+ expect(kvProtocol.signature).toBe(5)
324
+ expect(Object.keys(kvProtocol).length).toBe(6)
325
+ })
326
+ })
327
+ })