@bsv/wallet-toolbox 1.1.12 → 1.1.14

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 (157) hide show
  1. package/.github/workflows/push.yaml +2 -2
  2. package/README.md +3 -22
  3. package/docs/README.md +16 -10
  4. package/docs/client.md +490 -382
  5. package/docs/open-rpc/index.html +46 -0
  6. package/docs/services.md +236 -211
  7. package/docs/setup.md +51 -34
  8. package/docs/storage.md +30 -5
  9. package/docs/wallet.md +490 -382
  10. package/out/src/SetupClient.d.ts +9 -0
  11. package/out/src/SetupClient.d.ts.map +1 -1
  12. package/out/src/SetupClient.js +34 -18
  13. package/out/src/SetupClient.js.map +1 -1
  14. package/out/src/Wallet.d.ts +6 -0
  15. package/out/src/Wallet.d.ts.map +1 -1
  16. package/out/src/Wallet.js +57 -0
  17. package/out/src/Wallet.js.map +1 -1
  18. package/out/src/sdk/WalletServices.interfaces.d.ts +18 -13
  19. package/out/src/sdk/WalletServices.interfaces.d.ts.map +1 -1
  20. package/out/src/services/Services.d.ts +4 -11
  21. package/out/src/services/Services.d.ts.map +1 -1
  22. package/out/src/services/Services.js +19 -37
  23. package/out/src/services/Services.js.map +1 -1
  24. package/out/src/services/__tests/ARC.test.d.ts +2 -0
  25. package/out/src/services/__tests/ARC.test.d.ts.map +1 -0
  26. package/out/src/services/__tests/ARC.test.js +98 -0
  27. package/out/src/services/__tests/ARC.test.js.map +1 -0
  28. package/out/src/services/__tests/arcServices.test.d.ts +2 -0
  29. package/out/src/services/__tests/arcServices.test.d.ts.map +1 -0
  30. package/out/src/services/__tests/arcServices.test.js +7 -0
  31. package/out/src/services/__tests/arcServices.test.js.map +1 -0
  32. package/out/src/services/__tests/postBeef.test.js +45 -7
  33. package/out/src/services/__tests/postBeef.test.js.map +1 -1
  34. package/out/src/services/createDefaultWalletServicesOptions.d.ts +1 -0
  35. package/out/src/services/createDefaultWalletServicesOptions.d.ts.map +1 -1
  36. package/out/src/services/createDefaultWalletServicesOptions.js +16 -4
  37. package/out/src/services/createDefaultWalletServicesOptions.js.map +1 -1
  38. package/out/src/services/providers/ARC.d.ts +91 -0
  39. package/out/src/services/providers/ARC.d.ts.map +1 -0
  40. package/out/src/services/providers/ARC.js +192 -0
  41. package/out/src/services/providers/ARC.js.map +1 -0
  42. package/out/src/services/providers/SdkWhatsOnChain.d.ts +21 -0
  43. package/out/src/services/providers/SdkWhatsOnChain.d.ts.map +1 -0
  44. package/out/src/services/providers/SdkWhatsOnChain.js +67 -0
  45. package/out/src/services/providers/SdkWhatsOnChain.js.map +1 -0
  46. package/out/src/services/providers/WhatsOnChain.d.ts +35 -0
  47. package/out/src/services/providers/WhatsOnChain.d.ts.map +1 -0
  48. package/out/src/services/providers/WhatsOnChain.js +266 -0
  49. package/out/src/services/providers/WhatsOnChain.js.map +1 -0
  50. package/out/src/services/providers/__tests/WhatsOnChain.test.d.ts +2 -0
  51. package/out/src/services/providers/__tests/WhatsOnChain.test.d.ts.map +1 -0
  52. package/out/src/services/providers/__tests/WhatsOnChain.test.js +176 -0
  53. package/out/src/services/providers/__tests/WhatsOnChain.test.js.map +1 -0
  54. package/out/src/signer/methods/createAction.js +3 -3
  55. package/out/src/signer/methods/createAction.js.map +1 -1
  56. package/out/src/signer/methods/signAction.js +1 -1
  57. package/out/src/signer/methods/signAction.js.map +1 -1
  58. package/out/src/storage/methods/createAction.d.ts.map +1 -1
  59. package/out/src/storage/methods/createAction.js +9 -2
  60. package/out/src/storage/methods/createAction.js.map +1 -1
  61. package/out/src/storage/methods/generateChange.d.ts +12 -1
  62. package/out/src/storage/methods/generateChange.d.ts.map +1 -1
  63. package/out/src/storage/methods/generateChange.js +24 -1
  64. package/out/src/storage/methods/generateChange.js.map +1 -1
  65. package/out/src/storage/methods/processAction.d.ts.map +1 -1
  66. package/out/src/storage/methods/processAction.js +1 -1
  67. package/out/src/storage/methods/processAction.js.map +1 -1
  68. package/out/src/storage/schema/entities/__tests/ProvenTxTests.test.js +0 -1
  69. package/out/src/storage/schema/entities/__tests/ProvenTxTests.test.js.map +1 -1
  70. package/out/src/storage/sync/StorageMySQLDojoReader.js +1 -1
  71. package/out/src/storage/sync/StorageMySQLDojoReader.js.map +1 -1
  72. package/out/src/utility/{ScriptTemplateSABPPP.d.ts → ScriptTemplateBRC29.d.ts} +6 -6
  73. package/out/src/utility/ScriptTemplateBRC29.d.ts.map +1 -0
  74. package/out/src/utility/{ScriptTemplateSABPPP.js → ScriptTemplateBRC29.js} +4 -4
  75. package/out/src/utility/ScriptTemplateBRC29.js.map +1 -0
  76. package/out/src/utility/index.all.d.ts +1 -1
  77. package/out/src/utility/index.all.d.ts.map +1 -1
  78. package/out/src/utility/index.all.js +1 -1
  79. package/out/src/utility/index.all.js.map +1 -1
  80. package/out/src/utility/index.client.d.ts +1 -1
  81. package/out/src/utility/index.client.d.ts.map +1 -1
  82. package/out/src/utility/index.client.js +1 -1
  83. package/out/src/utility/index.client.js.map +1 -1
  84. package/out/src/utility/utilityHelpers.js +1 -1
  85. package/out/src/utility/utilityHelpers.js.map +1 -1
  86. package/out/test/Wallet/StorageClient/storageClient.man.test.js +22 -3
  87. package/out/test/Wallet/StorageClient/storageClient.man.test.js.map +1 -1
  88. package/out/test/Wallet/live/walletLive.man.test.js +2 -2
  89. package/out/test/Wallet/live/walletLive.man.test.js.map +1 -1
  90. package/out/test/Wallet/sync/Wallet.updateWalletLegacyTestData.man.test.js +40 -0
  91. package/out/test/Wallet/sync/Wallet.updateWalletLegacyTestData.man.test.js.map +1 -1
  92. package/out/test/services/Services.test.js +0 -31
  93. package/out/test/services/Services.test.js.map +1 -1
  94. package/out/test/utils/TestUtilsWalletStorage.d.ts +26 -18
  95. package/out/test/utils/TestUtilsWalletStorage.d.ts.map +1 -1
  96. package/out/test/utils/TestUtilsWalletStorage.js +135 -27
  97. package/out/test/utils/TestUtilsWalletStorage.js.map +1 -1
  98. package/out/test/wallet/list/listActions2.test.js +36 -2
  99. package/out/test/wallet/list/listActions2.test.js.map +1 -1
  100. package/out/tsconfig.all.tsbuildinfo +1 -1
  101. package/package.json +5 -7
  102. package/src/SetupClient.ts +41 -21
  103. package/src/Wallet.ts +66 -2
  104. package/src/sdk/WalletServices.interfaces.ts +19 -14
  105. package/src/services/Services.ts +23 -62
  106. package/src/services/__tests/ARC.test.ts +110 -0
  107. package/src/services/__tests/arcServices.test.ts +8 -0
  108. package/src/services/__tests/postBeef.test.ts +47 -9
  109. package/src/services/createDefaultWalletServicesOptions.ts +19 -6
  110. package/src/services/providers/ARC.ts +289 -0
  111. package/src/services/providers/SdkWhatsOnChain.ts +96 -0
  112. package/src/services/providers/WhatsOnChain.ts +369 -0
  113. package/src/services/providers/__tests/WhatsOnChain.test.ts +227 -0
  114. package/src/signer/methods/createAction.ts +4 -4
  115. package/src/signer/methods/signAction.ts +2 -2
  116. package/src/storage/methods/createAction.ts +26 -4
  117. package/src/storage/methods/generateChange.ts +42 -2
  118. package/src/storage/methods/processAction.ts +2 -1
  119. package/src/storage/schema/entities/__tests/ProvenTxTests.test.ts +0 -1
  120. package/src/storage/sync/StorageMySQLDojoReader.ts +1 -1
  121. package/src/utility/{ScriptTemplateSABPPP.ts → ScriptTemplateBRC29.ts} +6 -8
  122. package/src/utility/index.all.ts +1 -1
  123. package/src/utility/index.client.ts +1 -1
  124. package/src/utility/utilityHelpers.ts +1 -1
  125. package/test/Wallet/StorageClient/storageClient.man.test.ts +30 -4
  126. package/test/Wallet/live/walletLive.man.test.ts +3 -3
  127. package/test/Wallet/sync/Wallet.updateWalletLegacyTestData.man.test.ts +54 -0
  128. package/test/services/Services.test.ts +0 -30
  129. package/test/utils/TestUtilsWalletStorage.ts +175 -45
  130. package/test/wallet/list/listActions2.test.ts +4 -7
  131. package/out/src/services/__tests/postBeefToArcTaal.test.d.ts +0 -2
  132. package/out/src/services/__tests/postBeefToArcTaal.test.d.ts.map +0 -1
  133. package/out/src/services/__tests/postBeefToArcTaal.test.js +0 -479
  134. package/out/src/services/__tests/postBeefToArcTaal.test.js.map +0 -1
  135. package/out/src/services/__tests/postTxs.test.d.ts +0 -2
  136. package/out/src/services/__tests/postTxs.test.d.ts.map +0 -1
  137. package/out/src/services/__tests/postTxs.test.js +0 -28
  138. package/out/src/services/__tests/postTxs.test.js.map +0 -1
  139. package/out/src/services/providers/arcServices.d.ts +0 -62
  140. package/out/src/services/providers/arcServices.d.ts.map +0 -1
  141. package/out/src/services/providers/arcServices.js +0 -375
  142. package/out/src/services/providers/arcServices.js.map +0 -1
  143. package/out/src/services/providers/whatsonchain.d.ts +0 -17
  144. package/out/src/services/providers/whatsonchain.d.ts.map +0 -1
  145. package/out/src/services/providers/whatsonchain.js +0 -130
  146. package/out/src/services/providers/whatsonchain.js.map +0 -1
  147. package/out/src/utility/ScriptTemplateSABPPP.d.ts.map +0 -1
  148. package/out/src/utility/ScriptTemplateSABPPP.js.map +0 -1
  149. package/out/test/examples/README.man.test.d.ts +0 -2
  150. package/out/test/examples/README.man.test.d.ts.map +0 -1
  151. package/out/test/examples/README.man.test.js +0 -47
  152. package/out/test/examples/README.man.test.js.map +0 -1
  153. package/src/services/__tests/postBeefToArcTaal.test.ts +0 -487
  154. package/src/services/__tests/postTxs.test.ts +0 -28
  155. package/src/services/providers/arcServices.ts +0 -578
  156. package/src/services/providers/whatsonchain.ts +0 -170
  157. package/test/examples/README.man.test.ts +0 -53
@@ -0,0 +1,369 @@
1
+ import { HexString, WhatsOnChainConfig } from '@bsv/sdk'
2
+ import {
3
+ asArray,
4
+ asString,
5
+ sdk,
6
+ validateScriptHash,
7
+ wait
8
+ } from '../../index.client'
9
+ import { convertProofToMerklePath } from '../../utility/tscProofToMerklePath'
10
+ import SdkWhatsOnChain from './SdkWhatsOnChain'
11
+
12
+ /**
13
+ *
14
+ */
15
+ export class WhatsOnChain extends SdkWhatsOnChain {
16
+ constructor(chain: sdk.Chain = 'main', config: WhatsOnChainConfig = {}) {
17
+ super(chain, config)
18
+ }
19
+
20
+ /**
21
+ * 2025-02-16 throwing internal server error 500.
22
+ * @param txid
23
+ * @returns
24
+ */
25
+ async getTxPropagation(txid: string): Promise<number> {
26
+ const requestOptions = {
27
+ method: 'GET',
28
+ headers: this.getHttpHeaders()
29
+ }
30
+
31
+ const response = await this.httpClient.request<string>(
32
+ `${this.URL}/tx/hash/${txid}/propagation`,
33
+ requestOptions
34
+ )
35
+
36
+ if (
37
+ !response.data ||
38
+ !response.ok ||
39
+ response.status !== 200 ||
40
+ response.statusText !== 'OK'
41
+ )
42
+ throw new sdk.WERR_INVALID_PARAMETER(
43
+ 'txid',
44
+ `valid transaction. '${txid}' response ${response.statusText}`
45
+ )
46
+
47
+ return 0
48
+ }
49
+
50
+ /**
51
+ * May return undefined for unmined transactions that are in the mempool.
52
+ * @param txid
53
+ * @returns raw transaction as hex string or undefined if txid not found in mined block.
54
+ */
55
+ async getRawTx(txid: string): Promise<string | undefined> {
56
+ const headers = this.getHttpHeaders()
57
+ headers['Cache-Control'] = 'no-cache'
58
+
59
+ const requestOptions = {
60
+ method: 'GET',
61
+ headers
62
+ }
63
+
64
+ for (let retry = 0; retry < 2; retry++) {
65
+ const response = await this.httpClient.request<string>(
66
+ `${this.URL}/tx/${txid}/hex`,
67
+ requestOptions
68
+ )
69
+ if (response.statusText === 'Too Many Requests' && retry < 2) {
70
+ await wait(2000)
71
+ continue
72
+ }
73
+
74
+ if (response.status === 404 && response.statusText === 'Not Found')
75
+ return undefined
76
+
77
+ if (
78
+ !response.data ||
79
+ !response.ok ||
80
+ response.status !== 200 ||
81
+ response.statusText !== 'OK'
82
+ )
83
+ throw new sdk.WERR_INVALID_PARAMETER(
84
+ 'txid',
85
+ `valid transaction. '${txid}' response ${response.statusText}`
86
+ )
87
+
88
+ return response.data
89
+ }
90
+ throw new sdk.WERR_INTERNAL()
91
+ }
92
+
93
+ async getRawTxResult(txid: string): Promise<sdk.GetRawTxResult> {
94
+ const r: sdk.GetRawTxResult = { name: 'WoC', txid: asString(txid) }
95
+
96
+ try {
97
+ const rawTxHex = await this.getRawTx(txid)
98
+ if (rawTxHex) r.rawTx = asArray(rawTxHex)
99
+ } catch (err: unknown) {
100
+ r.error = sdk.WalletError.fromUnknown(err)
101
+ }
102
+
103
+ return r
104
+ }
105
+
106
+ /**
107
+ * @param rawTx raw transaction to broadcast as hex string
108
+ * @returns txid returned by transaction processor of transaction broadcast
109
+ */
110
+ async postRawTx(rawTx: HexString): Promise<string> {
111
+ const headers = this.getHttpHeaders()
112
+ headers['Content-Type'] = 'application/json'
113
+ headers['Accept'] = 'text/plain'
114
+
115
+ const requestOptions = {
116
+ method: 'POST',
117
+ headers,
118
+ data: { txhex: rawTx }
119
+ }
120
+
121
+ for (let retry = 0; retry < 2; retry++) {
122
+ try {
123
+ const response = await this.httpClient.request<string>(
124
+ `${this.URL}/tx/raw`,
125
+ requestOptions
126
+ )
127
+ if (response.statusText === 'Too Many Requests' && retry < 2) {
128
+ await wait(2000)
129
+ continue
130
+ }
131
+ if (response.ok) {
132
+ const txid = response.data
133
+ return txid
134
+ } else {
135
+ if (typeof response.data === 'string')
136
+ throw new sdk.WERR_INVALID_PARAMETER(
137
+ 'rawTx',
138
+ `valid. ${response.data}`
139
+ )
140
+ else
141
+ throw new sdk.WERR_INVALID_PARAMETER(
142
+ 'rawTx',
143
+ `valid. ${response.status} ${response.statusText}`
144
+ )
145
+ }
146
+ } catch (eu: unknown) {
147
+ if (eu instanceof sdk.WERR_INVALID_PARAMETER) throw eu
148
+ const e = sdk.WalletError.fromUnknown(eu)
149
+ throw new sdk.WERR_INVALID_PARAMETER(
150
+ 'rawTx',
151
+ `valid rawTx. error ${e.code} ${e.message} ${rawTx}`
152
+ )
153
+ }
154
+ }
155
+ throw new sdk.WERR_INTERNAL()
156
+ }
157
+
158
+ /**
159
+ * @param txid
160
+ * @returns
161
+ */
162
+ async getMerklePath(
163
+ txid: string,
164
+ services: sdk.WalletServices
165
+ ): Promise<sdk.GetMerklePathResult> {
166
+ const r: sdk.GetMerklePathResult = { name: 'WoCTsc' }
167
+
168
+ const headers = this.getHttpHeaders()
169
+ const requestOptions = {
170
+ method: 'GET',
171
+ headers
172
+ }
173
+
174
+ for (let retry = 0; retry < 2; retry++) {
175
+ try {
176
+ const response = await this.httpClient.request<
177
+ WhatsOnChainTscProof | WhatsOnChainTscProof[]
178
+ >(`${this.URL}/tx/${txid}/proof/tsc`, requestOptions)
179
+ if (response.statusText === 'Too Many Requests' && retry < 2) {
180
+ await wait(2000)
181
+ continue
182
+ }
183
+
184
+ if (response.status === 404 && response.statusText === 'Not Found')
185
+ return r
186
+
187
+ if (
188
+ !response.ok ||
189
+ response.status !== 200 ||
190
+ response.statusText !== 'OK'
191
+ )
192
+ throw new sdk.WERR_INVALID_PARAMETER(
193
+ 'txid',
194
+ `valid transaction. '${txid}' response ${response.statusText}`
195
+ )
196
+
197
+ if (!response.data) {
198
+ // Unmined, proof not yet available.
199
+ return r
200
+ }
201
+
202
+ if (!Array.isArray(response.data)) response.data = [response.data]
203
+
204
+ if (response.data.length != 1) return r
205
+
206
+ const p = response.data[0]
207
+ const header = await services.hashToHeader(p.target)
208
+ if (header) {
209
+ const proof = {
210
+ index: p.index,
211
+ nodes: p.nodes,
212
+ height: header.height
213
+ }
214
+ r.merklePath = convertProofToMerklePath(txid, proof)
215
+ r.header = header
216
+ } else {
217
+ throw new sdk.WERR_INVALID_PARAMETER(
218
+ 'blockhash',
219
+ 'a valid on-chain block hash'
220
+ )
221
+ }
222
+ } catch (err: unknown) {
223
+ r.error = sdk.WalletError.fromUnknown(err)
224
+ }
225
+ return r
226
+ }
227
+ throw new sdk.WERR_INTERNAL()
228
+ }
229
+
230
+ async updateBsvExchangeRate(
231
+ rate?: sdk.BsvExchangeRate,
232
+ updateMsecs?: number
233
+ ): Promise<sdk.BsvExchangeRate> {
234
+ if (rate) {
235
+ // Check if the rate we know is stale enough to update.
236
+ updateMsecs ||= 1000 * 60 * 15
237
+ if (new Date(Date.now() - updateMsecs) < rate.timestamp) return rate
238
+ }
239
+
240
+ const requestOptions = {
241
+ method: 'GET',
242
+ headers: this.getHttpHeaders()
243
+ }
244
+
245
+ for (let retry = 0; retry < 2; retry++) {
246
+ const response = await this.httpClient.request<{
247
+ rate: number
248
+ time: number
249
+ currency: string
250
+ }>(`${this.URL}/exchangerate`, requestOptions)
251
+ if (response.statusText === 'Too Many Requests' && retry < 2) {
252
+ await wait(2000)
253
+ continue
254
+ }
255
+
256
+ if (
257
+ !response.data ||
258
+ !response.ok ||
259
+ response.status !== 200 ||
260
+ response.statusText !== 'OK'
261
+ )
262
+ throw new sdk.WERR_INVALID_OPERATION(
263
+ `WoC exchangerate response ${response.statusText}`
264
+ )
265
+
266
+ const wocrate = response.data
267
+ if (wocrate.currency !== 'USD') wocrate.rate = NaN
268
+
269
+ const newRate: sdk.BsvExchangeRate = {
270
+ timestamp: new Date(),
271
+ base: 'USD',
272
+ rate: wocrate.rate
273
+ }
274
+
275
+ return newRate
276
+ }
277
+ throw new sdk.WERR_INTERNAL()
278
+ }
279
+
280
+ async getUtxoStatus(
281
+ output: string,
282
+ outputFormat?: sdk.GetUtxoStatusOutputFormat
283
+ ): Promise<sdk.GetUtxoStatusResult> {
284
+ const r: sdk.GetUtxoStatusResult = {
285
+ name: 'WoC',
286
+ status: 'error',
287
+ error: new sdk.WERR_INTERNAL(),
288
+ details: []
289
+ }
290
+
291
+ for (let retry = 0; ; retry++) {
292
+ let url: string = ''
293
+
294
+ try {
295
+ const scriptHash = validateScriptHash(output, outputFormat)
296
+
297
+ const requestOptions = {
298
+ method: 'GET',
299
+ headers: this.getHttpHeaders()
300
+ }
301
+
302
+ const response = await this.httpClient.request<
303
+ WhatsOnChainUtxoStatus[]
304
+ >(`${this.URL}/script/${scriptHash}/unspent`, requestOptions)
305
+ if (response.statusText === 'Too Many Requests' && retry < 2) {
306
+ await wait(2000)
307
+ continue
308
+ }
309
+
310
+ if (
311
+ !response.data ||
312
+ !response.ok ||
313
+ response.status !== 200 ||
314
+ response.statusText !== 'OK'
315
+ )
316
+ throw new sdk.WERR_INVALID_OPERATION(
317
+ `WoC exchangerate response ${response.statusText}`
318
+ )
319
+
320
+ if (Array.isArray(response.data)) {
321
+ const data = response.data
322
+ if (data.length === 0) {
323
+ r.status = 'success'
324
+ r.error = undefined
325
+ r.isUtxo = false
326
+ } else {
327
+ r.status = 'success'
328
+ r.error = undefined
329
+ r.isUtxo = true
330
+ for (const s of data) {
331
+ r.details.push({
332
+ txid: s.tx_hash,
333
+ satoshis: s.value,
334
+ height: s.height,
335
+ index: s.tx_pos
336
+ })
337
+ }
338
+ }
339
+ } else {
340
+ throw new sdk.WERR_INTERNAL('data is not an array')
341
+ }
342
+
343
+ return r
344
+ } catch (eu: unknown) {
345
+ const e = sdk.WalletError.fromUnknown(eu)
346
+ if (e.code !== 'ECONNRESET' || retry > 2) {
347
+ r.error = new sdk.WERR_INTERNAL(
348
+ `service failure: ${url}, error: ${JSON.stringify(sdk.WalletError.fromUnknown(eu))}`
349
+ )
350
+ return r
351
+ }
352
+ }
353
+ }
354
+ }
355
+ }
356
+
357
+ interface WhatsOnChainTscProof {
358
+ index: number
359
+ nodes: string[]
360
+ target: string
361
+ txOrId: string
362
+ }
363
+
364
+ interface WhatsOnChainUtxoStatus {
365
+ value: number
366
+ height: number
367
+ tx_pos: number
368
+ tx_hash: string
369
+ }
@@ -0,0 +1,227 @@
1
+ import { WhatsOnChainBroadcaster, WhatsOnChainConfig } from '@bsv/sdk'
2
+ import { _tu } from '../../../../test/utils/TestUtilsWalletStorage'
3
+ import { WhatsOnChain } from '../WhatsOnChain'
4
+ import { Services } from '../../Services'
5
+ import { sdk, wait } from '../../../index.client'
6
+ import { Setup, StorageKnex } from '../../../index.all'
7
+ describe('whatsonchain tests', () => {
8
+ jest.setTimeout(99999999)
9
+
10
+ const envTest = _tu.getEnv('test')
11
+ const wocTest = new WhatsOnChain(envTest.chain, {
12
+ apiKey: envTest.taalApiKey
13
+ })
14
+ const envMain = _tu.getEnv('main')
15
+ const wocMain = new WhatsOnChain(envMain.chain, {
16
+ apiKey: envMain.taalApiKey
17
+ })
18
+
19
+ test('0 getRawTx testnet', async () => {
20
+ const rawTx = await wocTest.getRawTx(
21
+ '7e5b797b86abd31a654bf296900d6cb14d04ef0811568ff4675494af2d92166b'
22
+ )
23
+ expect(
24
+ rawTx ===
25
+ '010000000158EED5DBBB7E2F7D70C79A11B9B61AABEECFA5A7CEC679BEDD00F42C48A4BD45010000006B483045022100AE8BB45498A40E2AC797775C405C108168804CD84E8C09A9D42D280D18EDDB6D022024863BFAAC5FF3C24CA65E2F3677EDA092BC3CC5D2EFABA73264B8FF55CF416B412102094AAF520E14E1C4D68496822800BCC7D3B3B26CA368E004A2CB70B398D82FACFFFFFFFF0203000000000000007421020A624B72B34BC192851C5D8890926BBB70B31BC10FDD4E3BC6534E41B1C81B93AC03010203030405064630440220013B4984F4054C2FBCD2F448AB896CCA5C4E234BF765B0C7FB27EDE572A7F7DA02201A5C8D0D023F94C209046B9A2B96B2882C5E43B72D8115561DF8C07442010EEA6D7592090000000000001976A9146511FCE2F7EF785A2102142FBF381AD1291C918688AC00000000'
26
+ )
27
+
28
+ expect(await wocTest.getRawTx('1'.repeat(64))).toBeUndefined()
29
+ })
30
+
31
+ test('1 getRawTx mainnet', async () => {
32
+ const rawTx = await wocMain.getRawTx(
33
+ 'd9978ffc6676523208f7b33bebf1b176388bbeace2c7ef67ce35c2eababa1805'
34
+ )
35
+ expect(
36
+ rawTx ===
37
+ '0100000001026A66A5F724EB490A55E0E08553286F08AD57E92C4BF34B5C44EA6BC0A49828020000006B483045022100C3D9A5ACA30C1F2E1A54532162E7AFE5AA69150E4C06D760414A16D1EA1BABD602205E0D9191838B0911A1E7328554A2B22EFAA80CF52B15FBA37C3046A0996C7AAD412103FA3CF488CA98D9F2DB91843F36BAF6BE39F6C947976C02394602D09FBC5F4CF4FFFFFFFF0210270000000000001976A91444C04354E88975C4BEF30CFE89D300CC7659F7E588AC96BC0000000000001976A9149A53E5CF5F1876924D98A8B35CA0BC693618682488AC00000000'
38
+ )
39
+
40
+ expect(await wocMain.getRawTx('1'.repeat(64))).toBeUndefined()
41
+ })
42
+
43
+ test('2 getMerklePath testnet', async () => {
44
+ const services = new Services(envTest.chain)
45
+ {
46
+ const r = await wocTest.getMerklePath(
47
+ '7e5b797b86abd31a654bf296900d6cb14d04ef0811568ff4675494af2d92166b',
48
+ services
49
+ )
50
+ const s = JSON.stringify(r)
51
+ expect(s).toBe(
52
+ '{"name":"WoCTsc","merklePath":{"blockHeight":1661398,"path":[[{"offset":6,"hash":"7e5b797b86abd31a654bf296900d6cb14d04ef0811568ff4675494af2d92166b","txid":true},{"offset":7,"hash":"97dd9d9080394d52338588732d9f84e1debca93f171f674ac3beac1e75495568"}],[{"offset":2,"hash":"81beedcd219d9e03255bde2ee479db34b9fed04d30373ba8bc264a64af2515b9"}],[{"offset":0,"hash":"9965f9aaeea33f6878335e6f7e6bdb544c3a8550c84e2f0daca54e9cd912111c"}]]},"header":{"version":536870912,"previousHash":"000000000688340a14b77e49bb0fca5ac7b624f7f79a5517583d1aae61c4e658","merkleRoot":"edbc07082ca0a31d5ec89d1f503a9cd41112c0d8f3221a96acfb8a9d16f8e82b","time":1739624725,"bits":486604799,"nonce":1437884974,"height":1661398,"hash":"00000000d8a73bf9a37272a71886ea92a25376bed1c1916f2b5cfbec4d6f6a25"}}'
53
+ )
54
+ }
55
+
56
+ {
57
+ const r = await wocTest.getMerklePath('1'.repeat(64), services)
58
+ const s = JSON.stringify(r)
59
+ expect(s).toBe('{"name":"WoCTsc"}')
60
+ }
61
+ })
62
+
63
+ test('3 getMerklePath mainnet', async () => {
64
+ const services = new Services(envMain.chain)
65
+ {
66
+ const r = await wocMain.getMerklePath(
67
+ 'd9978ffc6676523208f7b33bebf1b176388bbeace2c7ef67ce35c2eababa1805',
68
+ services
69
+ )
70
+ const s = JSON.stringify(r)
71
+ expect(s).toBe(
72
+ '{"name":"WoCTsc","merklePath":{"blockHeight":883637,"path":[[{"offset":46,"hash":"d9978ffc6676523208f7b33bebf1b176388bbeace2c7ef67ce35c2eababa1805","txid":true},{"offset":47,"hash":"066f6fa6fa988f2e3a9d6fe35fa0d3666c652dac35cabaeebff3738a4e67f68f"}],[{"offset":22,"hash":"232089a6f77c566151bc4701fda394b5cc5bf17073140d46a73c4c3ed0a7b911"}],[{"offset":10,"hash":"c639b3a6ce127f67dbd01c7331a6fca62a4b429830387bd68ac6ac05e162116d"}],[{"offset":4,"hash":"730cec44be97881530947d782bb328d25f1122fdae206296937fffb03e936d48"}],[{"offset":3,"hash":"28b681f8ab8db0fa4d5d20cb1532b95184a155346b0b8447bde580b2406d51e6"}],[{"offset":0,"hash":"c49a18028e230dd1439b26794c08c339506f24a450f067c4facd4e0d5a346490"}],[{"offset":1,"hash":"0ba57d1b1fad6874de3640c01088e3dedad3507e5b3a3102b9a8a8055f3df88b"}],[{"offset":1,"hash":"c830edebe5565c19ba584ec73d49129344d17539f322509b7c314ae641c2fcdb"}],[{"offset":1,"hash":"ff62d5ed2a94eb93a2b7d084b8f15b12083573896b6a58cf871507e3352c75f5"}]]},"header":{"version":1040187392,"previousHash":"00000000000000000d9f6889dd6743500adee204ea25d8a57225ecd48b111769","merkleRoot":"59c1efd79fae0d9c29dd8da63f8eeec0aadde048f4491c6bfa324fcfd537156d","time":1739329877,"bits":403818359,"nonce":596827153,"height":883637,"hash":"0000000000000000060ac8d63b78d41f58c9aba0b09f81db7d51fa4905a47263"}}'
73
+ )
74
+ }
75
+
76
+ {
77
+ const r = await wocMain.getMerklePath('1'.repeat(64), services)
78
+ const s = JSON.stringify(r)
79
+ expect(s).toBe('{"name":"WoCTsc"}')
80
+ }
81
+ })
82
+
83
+ test('4 updateBsvExchangeRate', async () => {
84
+ {
85
+ const r = await wocMain.updateBsvExchangeRate()
86
+ expect(r.base).toBe('USD')
87
+ expect(r.rate).toBeGreaterThan(0)
88
+ expect(r.timestamp).toBeTruthy()
89
+ }
90
+ })
91
+
92
+ test('5 getTxPropagation testnet', async () => {
93
+ return
94
+ // throwing internal server error 500 when tested.
95
+ const count = await wocTest.getTxPropagation(
96
+ '7e5b797b86abd31a654bf296900d6cb14d04ef0811568ff4675494af2d92166b'
97
+ )
98
+ expect(count > 0)
99
+
100
+ expect((await wocTest.getTxPropagation('1'.repeat(64))) === 0)
101
+ })
102
+
103
+ test('6 getTxPropagation mainnet', async () => {})
104
+
105
+ test.skip('7 postRawTx testnet', async () => {
106
+ if (Setup.noEnv('test')) return
107
+ const woc = wocTest
108
+ const c = await _tu.createNoSendTxPair('test')
109
+
110
+ const rawTxDo = c.beef.findTxid(c.txidDo)!.tx!.toHex()
111
+ const rawTxUndo = c.beef.findTxid(c.txidUndo)!.tx!.toHex()
112
+
113
+ const txidDo = await woc.postRawTx(rawTxDo)
114
+ expect(txidDo).toBe(c.txidDo)
115
+
116
+ await wait(1000)
117
+
118
+ const txidUndo = await woc.postRawTx(rawTxUndo)
119
+ expect(txidUndo).toBe(c.txidUndo)
120
+ })
121
+
122
+ test.skip('7a nosend cleanup testnet', async () => {
123
+ const c = await _tu.createWalletSetupEnv('test')
124
+
125
+ const actions = await c.wallet.listActions({ labels: [], limit: 1000 })
126
+ const nosends = actions.actions.filter(a => a.status === 'nosend')
127
+
128
+ const refs = ['yUfgNVaFcBNyP2Xv']
129
+ for (const ref of refs) {
130
+ try {
131
+ await c.wallet.abortAction({ reference: ref })
132
+ } catch (eu: unknown) {
133
+ const e = sdk.WalletError.fromUnknown(eu)
134
+ }
135
+ }
136
+ })
137
+
138
+ test.skip('8 postRawTx mainnet', async () => {
139
+ if (Setup.noEnv('main')) return
140
+ const woc = wocMain
141
+ const c = await _tu.createNoSendTxPair('main')
142
+
143
+ const rawTxDo = c.beef.findTxid(c.txidDo)!.tx!.toHex()
144
+ const rawTxUndo = c.beef.findTxid(c.txidUndo)!.tx!.toHex()
145
+
146
+ const txidDo = await woc.postRawTx(rawTxDo)
147
+ expect(txidDo).toBe(c.txidDo)
148
+
149
+ /*
150
+ try {
151
+ // This method is broken as of 2025-02-16
152
+ const count = await woc.getTxPropagation(txidDo)
153
+ } catch {}
154
+ // getRawTx returns undefined for unmined transactions, sometimes.
155
+ let rawTx = await woc.getRawTx(txidDo)
156
+ let i = 0
157
+ while (!rawTx) {
158
+ console.log(`${i++} waiting for WhatsOnChain to acknowledge new transaction exists.`)
159
+ await wait(5000)
160
+ rawTx = await woc.getRawTx(txidDo)
161
+ }
162
+ expect(rawTx).toBe(rawTxDo)
163
+ */
164
+
165
+ // allow for propagation...
166
+ await wait(1000)
167
+
168
+ const txidUndo = await woc.postRawTx(rawTxUndo)
169
+ expect(txidUndo).toBe(c.txidUndo)
170
+
171
+ await wait(1000)
172
+
173
+ // Confirm double spend detection.
174
+ // 'The rawTx parameter must be valid. unexpected response code 500: 258: txn-mempool-conflict'
175
+ // 'The rawTx parameter must be valid. unexpected response code 500: Missing inputs'
176
+ try {
177
+ await woc.postRawTx(c.doubleSpendTx.toHex())
178
+ expect(false)
179
+ } catch (eu: unknown) {
180
+ const e = sdk.WalletError.fromUnknown(eu)
181
+ expect(
182
+ e.message ===
183
+ 'The rawTx parameter must be valid. unexpected response code 500: 258: txn-mempool-conflict' ||
184
+ 'The rawTx parameter must be valid. unexpected response code 500: Missing inputs'
185
+ )
186
+ }
187
+ })
188
+
189
+ test.skip('8a nosend cleanup mainnet', async () => {
190
+ const c = await _tu.createWalletSetupEnv('main')
191
+
192
+ const actions = await c.wallet.listActions({ labels: [], limit: 1000 })
193
+ const nosends = actions.actions.filter(a => a.status === 'nosend')
194
+ // No way to get from actions to reference string values for use with abortAction...
195
+
196
+ if (c['activeStorage']) {
197
+ const s = c['activeStorage'] as StorageKnex
198
+ const userId = c['userId'] as number
199
+ const txs = await s.findTransactions({
200
+ partial: { userId, status: 'nosend' }
201
+ })
202
+ const refs = txs.map(tx => tx.reference)
203
+ for (const ref of refs) {
204
+ try {
205
+ await c.wallet.abortAction({ reference: ref })
206
+ } catch (eu: unknown) {
207
+ const e = sdk.WalletError.fromUnknown(eu)
208
+ }
209
+ }
210
+ }
211
+
212
+ await c.wallet.destroy()
213
+ })
214
+
215
+ test.skip('8b run monitor mainnet', async () => {
216
+ if (Setup.noEnv('main')) return
217
+ if (!Setup.getEnv('main').filePath) return
218
+
219
+ // Only run if `Setup` style .env is present with a sqlite filePath...
220
+
221
+ const c = await _tu.createWalletSetupEnv('main')
222
+
223
+ await c.monitor.runOnce()
224
+
225
+ await c.wallet.destroy()
226
+ })
227
+ })
@@ -10,7 +10,7 @@ import {
10
10
  makeAtomicBeef,
11
11
  PendingSignAction,
12
12
  PendingStorageInput,
13
- ScriptTemplateSABPPP,
13
+ ScriptTemplateBRC29,
14
14
  sdk,
15
15
  verifyTruthy,
16
16
  Wallet
@@ -100,7 +100,7 @@ function makeChangeLock(
100
100
  ): Script {
101
101
  const derivationPrefix = dctr.derivationPrefix
102
102
  const derivationSuffix = verifyTruthy(out.derivationSuffix)
103
- const sabppp = new ScriptTemplateSABPPP({
103
+ const sabppp = new ScriptTemplateBRC29({
104
104
  derivationPrefix,
105
105
  derivationSuffix,
106
106
  keyDeriver: wallet.keyDeriver
@@ -149,7 +149,7 @@ export async function completeSignedTransaction(
149
149
  // Insert SABPPP unlock templates for storage signed inputs
150
150
  /////////////////////
151
151
  for (const pdi of prior.pdi) {
152
- const sabppp = new ScriptTemplateSABPPP({
152
+ const sabppp = new ScriptTemplateBRC29({
153
153
  derivationPrefix: pdi.derivationPrefix,
154
154
  derivationSuffix: pdi.derivationSuffix,
155
155
  keyDeriver: wallet.keyDeriver
@@ -321,7 +321,7 @@ function buildSignableTransaction(
321
321
  }
322
322
  tx.addInput(inputToAdd)
323
323
  } else {
324
- // Type2: SABPPP protocol inputs which are signed using ScriptTemplateSABPPP.
324
+ // Type2: SABPPP protocol inputs which are signed using ScriptTemplateBRC29.
325
325
  if (storageInput.type !== 'P2PKH')
326
326
  throw new sdk.WERR_INVALID_PARAMETER(
327
327
  'type',
@@ -9,7 +9,7 @@ import {
9
9
  import {
10
10
  asBsvSdkScript,
11
11
  PendingSignAction,
12
- ScriptTemplateSABPPP,
12
+ ScriptTemplateBRC29,
13
13
  sdk,
14
14
  Wallet
15
15
  } from '../../index.client'
@@ -92,7 +92,7 @@ export async function completeSignedTransaction(
92
92
  // Insert SABPPP unlock templates for wallet signed inputs
93
93
  /////////////////////
94
94
  for (const pdi of prior.pdi) {
95
- const sabppp = new ScriptTemplateSABPPP({
95
+ const sabppp = new ScriptTemplateBRC29({
96
96
  derivationPrefix: pdi.derivationPrefix,
97
97
  derivationSuffix: pdi.derivationSuffix,
98
98
  keyDeriver: wallet.keyDeriver