@bsv/wallet-toolbox 1.1.56 → 1.1.57

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bsv/wallet-toolbox",
3
- "version": "1.1.56",
3
+ "version": "1.1.57",
4
4
  "description": "BRC100 conforming wallet, wallet storage and wallet signer components",
5
5
  "main": "./out/src/index.js",
6
6
  "types": "./out/src/index.d.ts",
@@ -30,9 +30,9 @@
30
30
  },
31
31
  "homepage": "https://github.com/bitcoin-sv/wallet-toolbox#readme",
32
32
  "dependencies": {
33
- "@bsv/auth-express-middleware": "^1.0.6",
33
+ "@bsv/auth-express-middleware": "^1.0.9",
34
34
  "@bsv/payment-express-middleware": "^1.0.3",
35
- "@bsv/sdk": "^1.3.28",
35
+ "@bsv/sdk": "^1.3.29",
36
36
  "axios": "^0.29.0",
37
37
  "express": "^4.21.2",
38
38
  "knex": "^3.1.0",
package/src/sdk/types.ts CHANGED
@@ -135,7 +135,7 @@ export type ReqHistoryNote = {
135
135
  /**
136
136
  * `listOutputs` special operation basket name value.
137
137
  *
138
- * Returns wallets current change balance in the `totalOutputs` result property.
138
+ * Returns wallet's current change balance in the `totalOutputs` result property.
139
139
  * The `outputs` result property will always be an empty array.
140
140
  */
141
141
  export const specOpWalletBalance =
@@ -70,12 +70,12 @@ export class Services implements sdk.WalletServices {
70
70
  })
71
71
 
72
72
  this.postBeefServices = new ServiceCollection<sdk.PostBeefService>()
73
- .add({ name: 'TaalArcBeef', service: this.arc.postBeef.bind(this.arc) })
73
+ //.add({ name: 'TaalArcBeef', service: this.arc.postBeef.bind(this.arc) })
74
+ //.add({ name: 'WhatsOnChain', service: this.whatsonchain.postBeef.bind(this.whatsonchain) })
74
75
  .add({
75
- name: 'WhatsOnChain',
76
- service: this.whatsonchain.postBeef.bind(this.whatsonchain)
76
+ name: 'Bitails',
77
+ service: this.bitails.postBeef.bind(this.bitails)
77
78
  })
78
- //.add({ name: 'Bitails', service: this.bitails.postBeef.bind(this.bitails) })
79
79
 
80
80
  this.getUtxoStatusServices =
81
81
  new ServiceCollection<sdk.GetUtxoStatusService>().add({
@@ -0,0 +1,62 @@
1
+ import {
2
+ convertProofToMerklePath,
3
+ sdk,
4
+ Services,
5
+ TscMerkleProofApi
6
+ } from '../../index.client'
7
+ import { Bitails, BitailsMerkleProof } from '../providers/Bitails'
8
+
9
+ describe('bitrails tests', () => {
10
+ jest.setTimeout(99999999)
11
+
12
+ test('0 verify merkle proof to merkle path', async () => {
13
+ const mp = convertProofToMerklePath(
14
+ '068f2ce0d01b5f1e7c7a07c209c3c67d583aeae83e11e92801b51c36f81d6b67',
15
+ proof2
16
+ )
17
+ const root = mp.computeRoot(
18
+ '068f2ce0d01b5f1e7c7a07c209c3c67d583aeae83e11e92801b51c36f81d6b67'
19
+ )
20
+ expect(root).toBe(proof2merkleRoot)
21
+ })
22
+
23
+ test('1 ', async () => {
24
+ const chain: sdk.Chain = 'main'
25
+ const bitails = new Bitails(chain)
26
+ const services = new Services(chain)
27
+
28
+ for (const txid of [
29
+ '068f2ce0d01b5f1e7c7a07c209c3c67d583aeae83e11e92801b51c36f81d6b67',
30
+ 'a65c2663d817da6474f7805cf103be6259aae16b01468711552b737c41768c30',
31
+ '243fb25b94b5ef2f8554cd10d105005f51ff543d8b7a498c4e46ed304c3da24a'
32
+ ]) {
33
+ const mp = await bitails.getMerklePath(txid, services)
34
+ const root = mp.merklePath!.computeRoot(txid)
35
+ expect(root).toBe(proof2merkleRoot)
36
+ }
37
+ })
38
+ })
39
+
40
+ const proof2merkleRoot =
41
+ '22b294aac4c3f6f4fdae30dc4f46f68f90feb94f03531c32bcf2ce33be5d4cb0'
42
+
43
+ const proof2: TscMerkleProofApi = {
44
+ index: 9443,
45
+ height: 742198,
46
+ nodes: [
47
+ '463c37bf0ccde321b1dc8ee857e03b8eafe76e6b1803cc3a774cfef61c50c37b',
48
+ 'debba259db996d6ca7c4fcfd168d3afe6bfdddab93298466d53ed0421634f405',
49
+ '6335d744771789ef69545b0f449bcde92ae7b9920e775a591fecc7fcfa37846e',
50
+ '38366b3723e8f166fbfe5d7528a57885f47aa25a8296c0679832a95c1e6d2f61',
51
+ '5a999d2186d10a787c3397938fd97a4b3e833aab8cff2ce24cfce7589b9b706b',
52
+ 'db97fbd581b8769602c6079e7fe10eb34cd99b844598b31441018ac21babd7e7',
53
+ '583e044e2bbc6b19993e73c3363a8ce3b4580a54510524489daadc6c82205f5a',
54
+ 'ba5d97e4fbedb84682f65b254c56f5826f1dc65bd376dc1660f23b81c4035b1d',
55
+ 'bfa39460ee7a8293698e41134a53cfc5ba0054416ca092d79ecbf93ae2b8b71b',
56
+ '8f3d186687f3f8186c4cbddcf263bbb4b58e3c279e55f9def048076faff0cc83',
57
+ '287790c47a0044e8e51ee60df33d4d23b972b5a51d8e9be7ac8b635b9f1e7ffc',
58
+ '19444e7ad68681d847d4d88989efa5f13afa46d7cbb47e8ce91876555c3e414d',
59
+ '6d71f472dabd52216a3cb24090d580baed96497b449876c199f48ed07f5ea2b0',
60
+ 'af4c17b677b0c7b4d85e7331b4e43fc16f9a7024c9417d7854c55a096ac098b3'
61
+ ]
62
+ }
@@ -1,5 +1,17 @@
1
- import { Beef, defaultHttpClient, HexString, HttpClient, Utils } from '@bsv/sdk'
2
- import { doubleSha256BE, sdk, wait } from '../../index.client'
1
+ import {
2
+ Beef,
3
+ defaultHttpClient,
4
+ HexString,
5
+ HttpClient,
6
+ MerklePath,
7
+ Utils
8
+ } from '@bsv/sdk'
9
+ import {
10
+ convertProofToMerklePath,
11
+ doubleSha256BE,
12
+ sdk,
13
+ wait
14
+ } from '../../index.client'
3
15
  import { ReqHistoryNote } from '../../sdk'
4
16
 
5
17
  export interface BitailsConfig {
@@ -188,6 +200,101 @@ export class Bitails {
188
200
  })
189
201
  return r
190
202
  }
203
+
204
+ /**
205
+ *
206
+ * @param txid
207
+ * @param services
208
+ * @returns
209
+ */
210
+ async getMerklePath(
211
+ txid: string,
212
+ services: sdk.WalletServices
213
+ ): Promise<sdk.GetMerklePathResult> {
214
+ const r: sdk.GetMerklePathResult = { name: 'BitailsTsc', notes: [] }
215
+
216
+ const url = `${this.URL}/tx/${txid}/proof/tsc`
217
+
218
+ const nn = () => ({
219
+ name: 'BitailsProofTsc',
220
+ when: new Date().toISOString(),
221
+ txid,
222
+ url
223
+ })
224
+
225
+ const headers = this.getHttpHeaders()
226
+ const requestOptions = {
227
+ method: 'GET',
228
+ headers
229
+ }
230
+
231
+ for (let retry = 0; retry < 2; retry++) {
232
+ try {
233
+ const response = await this.httpClient.request<BitailsMerkleProof>(
234
+ url,
235
+ requestOptions
236
+ )
237
+
238
+ const nne = () => ({
239
+ ...nn(),
240
+ txid,
241
+ url,
242
+ status: response.status,
243
+ statusText: response.statusText
244
+ })
245
+
246
+ if (response.statusText === 'Too Many Requests' && retry < 2) {
247
+ r.notes!.push({ ...nne(), what: 'getMerklePathRetry' })
248
+ await wait(2000)
249
+ continue
250
+ }
251
+
252
+ if (response.status === 404 && response.statusText === 'Not Found') {
253
+ r.notes!.push({ ...nne(), what: 'getMerklePathNotFound' })
254
+ } else if (
255
+ !response.ok ||
256
+ response.status !== 200 ||
257
+ response.statusText !== 'OK'
258
+ ) {
259
+ r.notes!.push({ ...nne(), what: 'getMerklePathBadStatus' })
260
+ } else if (!response.data) {
261
+ // Unmined, proof not yet available.
262
+ r.notes!.push({ ...nne(), what: 'getMerklePathNoData' })
263
+ } else {
264
+ const p = response.data
265
+ const header = await services.hashToHeader(p.target)
266
+ if (header) {
267
+ const proof = {
268
+ index: p.index,
269
+ nodes: p.nodes,
270
+ height: header.height
271
+ }
272
+ r.merklePath = convertProofToMerklePath(txid, proof)
273
+ r.header = header
274
+ r.notes!.push({ ...nne(), what: 'getMerklePathSuccess' })
275
+ } else {
276
+ r.notes!.push({
277
+ ...nne(),
278
+ what: 'getMerklePathNoHeader',
279
+ target: p.target
280
+ })
281
+ }
282
+ }
283
+ } catch (eu: unknown) {
284
+ const e = sdk.WalletError.fromUnknown(eu)
285
+ r.notes!.push({
286
+ ...nn(),
287
+ what: 'getMerklePathError',
288
+ code: e.code,
289
+ description: e.description
290
+ })
291
+ r.error = e
292
+ }
293
+ return r
294
+ }
295
+ r.notes!.push({ ...nn(), what: 'getMerklePathInternal' })
296
+ return r
297
+ }
191
298
  }
192
299
 
193
300
  interface BitailsPostRawsResult {
@@ -197,3 +304,10 @@ interface BitailsPostRawsResult {
197
304
  message: string
198
305
  }
199
306
  }
307
+
308
+ export interface BitailsMerkleProof {
309
+ index: number
310
+ txOrId: string
311
+ target: string
312
+ nodes: string[]
313
+ }
@@ -3,6 +3,7 @@ import {
3
3
  CreateActionArgs,
4
4
  CreateActionOptions,
5
5
  CreateActionResult,
6
+ OutpointString,
6
7
  P2PKH,
7
8
  PrivateKey,
8
9
  PublicKey,
@@ -26,6 +27,10 @@ import {
26
27
  } from '../../../src'
27
28
  import { _tu, TestWalletNoSetup } from '../../utils/TestUtilsWalletStorage'
28
29
  import { monitorEventLoopDelay } from 'perf_hooks'
30
+ import {
31
+ validateCreateActionArgs,
32
+ ValidCreateActionArgs
33
+ } from '../../../src/sdk'
29
34
 
30
35
  describe('localWallet tests', () => {
31
36
  jest.setTimeout(99999999)
@@ -39,7 +44,7 @@ describe('localWallet tests', () => {
39
44
 
40
45
  const car = await createOneSatTestOutput(setup, {}, 1)
41
46
 
42
- await trackReqByTxid(setup, car.txid!)
47
+ //await trackReqByTxid(setup, car.txid!)
43
48
 
44
49
  await setup.wallet.destroy()
45
50
  })
@@ -58,6 +63,16 @@ describe('localWallet tests', () => {
58
63
  await setup.wallet.destroy()
59
64
  })
60
65
 
66
+ test('0b create 2 nosend and sendWith', async () => {
67
+ const setup = await createSetup('test')
68
+
69
+ const car = await createOneSatTestOutput(setup, { noSend: true }, 2)
70
+
71
+ //await trackReqByTxid(setup, car.txid!)
72
+
73
+ await setup.wallet.destroy()
74
+ })
75
+
61
76
  test('1 recover 1 sat outputs', async () => {
62
77
  const setup = await createSetup('test')
63
78
 
@@ -178,8 +193,14 @@ async function createOneSatTestOutput(
178
193
  options: CreateActionOptions = {},
179
194
  howMany: number = 1
180
195
  ): Promise<CreateActionResult> {
196
+ if (howMany < 1) throw new sdk.WERR_INVALID_PARAMETER('howMany', 'at least 1')
197
+
181
198
  let car: CreateActionResult = {}
182
199
 
200
+ let noSendChange: OutpointString[] | undefined = undefined
201
+ let txids: string[] = []
202
+ let vargs: ValidCreateActionArgs
203
+
183
204
  for (let i = 0; i < howMany; i++) {
184
205
  const args: CreateActionArgs = {
185
206
  outputs: [
@@ -198,11 +219,15 @@ async function createOneSatTestOutput(
198
219
  ],
199
220
  description: 'create test output',
200
221
  options: {
201
- ...options
222
+ ...options,
223
+ noSendChange
202
224
  }
203
225
  }
226
+ vargs = validateCreateActionArgs(args)
204
227
  car = await setup.wallet.createAction(args)
205
228
  expect(car.txid)
229
+ txids.push(car.txid!)
230
+ noSendChange = car.noSendChange
206
231
 
207
232
  const req = await EntityProvenTxReq.fromStorageTxid(
208
233
  setup.activeStorage,
@@ -210,12 +235,33 @@ async function createOneSatTestOutput(
210
235
  )
211
236
  expect(req !== undefined && req.history.notes !== undefined)
212
237
  if (req && req.history.notes) {
213
- expect(req.status === 'unsent')
214
- expect(req.history.notes.length === 1)
215
- const n = req.history.notes[0]
216
- expect(n.what === 'status' && n.status_now === 'unsent')
238
+ if (vargs.isNoSend) {
239
+ expect(req.status === 'nosend').toBe(true)
240
+ expect(req.history.notes.length).toBe(1)
241
+ const n = req.history.notes[0]
242
+ expect(n.what === 'status' && n.status_now === 'nosend').toBe(true)
243
+ } else {
244
+ expect(req.status === 'unsent').toBe(true)
245
+ expect(req.history.notes.length).toBe(1)
246
+ const n = req.history.notes[0]
247
+ expect(n.what === 'status' && n.status_now === 'unsent').toBe(true)
248
+ }
249
+ }
250
+ }
251
+
252
+ if (vargs!.isNoSend) {
253
+ // Create final sending transaction
254
+ const args: CreateActionArgs = {
255
+ description: 'send batch',
256
+ options: {
257
+ ...options,
258
+ sendWith: txids
259
+ }
217
260
  }
261
+ vargs = validateCreateActionArgs(args)
262
+ car = await setup.wallet.createAction(args)
218
263
  }
264
+
219
265
  return car
220
266
  }
221
267