@bsv/wallet-toolbox 1.3.6 → 1.3.9

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 (55) hide show
  1. package/docs/client.md +1360 -133
  2. package/docs/storage.md +14 -10
  3. package/docs/wallet.md +1346 -119
  4. package/out/src/Wallet.d.ts +2 -2
  5. package/out/src/Wallet.d.ts.map +1 -1
  6. package/out/src/Wallet.js +15 -8
  7. package/out/src/Wallet.js.map +1 -1
  8. package/out/src/index.client.d.ts +2 -0
  9. package/out/src/index.client.d.ts.map +1 -1
  10. package/out/src/index.client.js +2 -0
  11. package/out/src/index.client.js.map +1 -1
  12. package/out/src/sdk/WalletStorage.interfaces.d.ts +14 -0
  13. package/out/src/sdk/WalletStorage.interfaces.d.ts.map +1 -1
  14. package/out/src/storage/StorageIdb.d.ts +5 -1
  15. package/out/src/storage/StorageIdb.d.ts.map +1 -1
  16. package/out/src/storage/StorageIdb.js +7 -3
  17. package/out/src/storage/StorageIdb.js.map +1 -1
  18. package/out/src/storage/StorageKnex.js +8 -8
  19. package/out/src/storage/StorageKnex.js.map +1 -1
  20. package/out/src/storage/WalletStorageManager.d.ts +1 -0
  21. package/out/src/storage/WalletStorageManager.d.ts.map +1 -1
  22. package/out/src/storage/WalletStorageManager.js +40 -0
  23. package/out/src/storage/WalletStorageManager.js.map +1 -1
  24. package/out/src/storage/__test/adminStats.man.test.js +45 -1
  25. package/out/src/storage/__test/adminStats.man.test.js.map +1 -1
  26. package/out/src/storage/index.all.d.ts +1 -0
  27. package/out/src/storage/index.all.d.ts.map +1 -1
  28. package/out/src/storage/index.all.js +1 -0
  29. package/out/src/storage/index.all.js.map +1 -1
  30. package/out/src/storage/index.client.d.ts +1 -0
  31. package/out/src/storage/index.client.d.ts.map +1 -1
  32. package/out/src/storage/index.client.js +1 -0
  33. package/out/src/storage/index.client.js.map +1 -1
  34. package/out/test/Wallet/local/localWallet2.man.test.js +58 -37
  35. package/out/test/Wallet/local/localWallet2.man.test.js.map +1 -1
  36. package/out/test/Wallet/support/operations.man.test.js +5 -3
  37. package/out/test/Wallet/support/operations.man.test.js.map +1 -1
  38. package/out/test/utils/localWalletMethods.d.ts +7 -2
  39. package/out/test/utils/localWalletMethods.d.ts.map +1 -1
  40. package/out/test/utils/localWalletMethods.js +19 -0
  41. package/out/test/utils/localWalletMethods.js.map +1 -1
  42. package/out/tsconfig.all.tsbuildinfo +1 -1
  43. package/package.json +1 -1
  44. package/src/Wallet.ts +10 -7
  45. package/src/index.client.ts +2 -0
  46. package/src/sdk/WalletStorage.interfaces.ts +16 -0
  47. package/src/storage/StorageIdb.ts +8 -4
  48. package/src/storage/StorageKnex.ts +8 -8
  49. package/src/storage/WalletStorageManager.ts +41 -0
  50. package/src/storage/__test/adminStats.man.test.ts +56 -2
  51. package/src/storage/index.all.ts +1 -0
  52. package/src/storage/index.client.ts +1 -0
  53. package/test/Wallet/local/localWallet2.man.test.ts +66 -40
  54. package/test/Wallet/support/operations.man.test.ts +5 -3
  55. package/test/utils/localWalletMethods.ts +34 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bsv/wallet-toolbox",
3
- "version": "1.3.6",
3
+ "version": "1.3.9",
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",
package/src/Wallet.ts CHANGED
@@ -635,26 +635,28 @@ export class Wallet implements WalletInterface, ProtoWallet {
635
635
  return transformVerifiableCertificatesWithTrust(trustSettings, results)
636
636
  }
637
637
 
638
- verifyReturnedTxidOnly(beef: Beef): Beef {
638
+ verifyReturnedTxidOnly(beef: Beef, knownTxids?: string[]): Beef {
639
639
  if (this.returnTxidOnly) return beef
640
640
  const onlyTxids = beef.txs.filter(btx => btx.isTxidOnly).map(btx => btx.txid)
641
641
  for (const txid of onlyTxids) {
642
+ if (knownTxids && knownTxids.indexOf(txid) >= 0) continue
642
643
  const btx = beef.findTxid(txid)
643
644
  const tx = this.beef.findAtomicTransaction(txid)
644
- if (!tx) throw new sdk.WERR_INTERNAL()
645
+ if (!tx) throw new sdk.WERR_INTERNAL(`unable to merge txid ${txid} into beef`)
645
646
  beef.mergeTransaction(tx)
646
647
  }
647
648
  for (const btx of beef.txs) {
648
- if (btx.isTxidOnly) throw new sdk.WERR_INTERNAL()
649
+ if (knownTxids && knownTxids.indexOf(btx.txid) >= 0) continue
650
+ if (btx.isTxidOnly) throw new sdk.WERR_INTERNAL(`remaining txidOnly ${btx.txid} is not known`)
649
651
  }
650
652
  return beef
651
653
  }
652
654
 
653
- verifyReturnedTxidOnlyAtomicBEEF(beef: AtomicBEEF): AtomicBEEF {
655
+ verifyReturnedTxidOnlyAtomicBEEF(beef: AtomicBEEF, knownTxids?: string[]): AtomicBEEF {
654
656
  if (this.returnTxidOnly) return beef
655
657
  const b = Beef.fromBinary(beef)
656
658
  if (!b.atomicTxid) throw new sdk.WERR_INTERNAL()
657
- return this.verifyReturnedTxidOnly(b).toBinaryAtomic(b.atomicTxid!)
659
+ return this.verifyReturnedTxidOnly(b, knownTxids).toBinaryAtomic(b.atomicTxid!)
658
660
  }
659
661
 
660
662
  verifyReturnedTxidOnlyBEEF(beef: BEEF): BEEF {
@@ -694,7 +696,7 @@ export class Wallet implements WalletInterface, ProtoWallet {
694
696
  this.beef.mergeBeefFromParty(this.storageParty, r.tx)
695
697
  }
696
698
 
697
- if (r.tx) r.tx = this.verifyReturnedTxidOnlyAtomicBEEF(r.tx)
699
+ if (r.tx) r.tx = this.verifyReturnedTxidOnlyAtomicBEEF(r.tx, args.options?.knownTxids)
698
700
 
699
701
  if (!vargs.isDelayed) throwIfAnyUnsuccessfulCreateActions(r)
700
702
 
@@ -713,7 +715,8 @@ export class Wallet implements WalletInterface, ProtoWallet {
713
715
 
714
716
  if (!vargs.isDelayed) throwIfAnyUnsuccessfulSignActions(r)
715
717
 
716
- if (r.tx) r.tx = this.verifyReturnedTxidOnlyAtomicBEEF(r.tx)
718
+ const prior = this.pendingSignActions[args.reference]
719
+ if (r.tx) r.tx = this.verifyReturnedTxidOnlyAtomicBEEF(r.tx, prior.args.options?.knownTxids)
717
720
 
718
721
  return r
719
722
  }
@@ -1,5 +1,7 @@
1
1
  export * as sdk from './sdk/index'
2
2
  export * from './utility/index.client'
3
+ export * from './SetupClient'
4
+ export * from './SetupWallet'
3
5
  export * from './signer/WalletSigner'
4
6
  export * from './WalletPermissionsManager'
5
7
  export * from './CWIStyleWalletManager'
@@ -88,6 +88,22 @@ export interface WalletStorage {
88
88
 
89
89
  relinquishCertificate(args: RelinquishCertificateArgs): Promise<number>
90
90
  relinquishOutput(args: RelinquishOutputArgs): Promise<number>
91
+
92
+ getStores(): WalletStorageInfo[]
93
+ }
94
+
95
+ /**
96
+ * Snapshot of the current state of a storage provider configured for an `WalletStorageManager`.
97
+ */
98
+ export interface WalletStorageInfo {
99
+ isActive: boolean
100
+ isEnabled: boolean
101
+ isBackup: boolean
102
+ isConflicting: boolean
103
+ userId: number
104
+ storageIdentityKey: string
105
+ storageName: string
106
+ storageClass: string
91
107
  }
92
108
 
93
109
  /**
@@ -33,6 +33,10 @@ import { purgeDataIdb } from './methods/purgeDataIdb'
33
33
 
34
34
  export interface StorageIdbOptions extends StorageProviderOptions {}
35
35
 
36
+ /**
37
+ * This class implements the `StorageProvider` interface using IndexedDB,
38
+ * via the promises wrapper package `idb`.
39
+ */
36
40
  export class StorageIdb extends StorageProvider implements sdk.WalletStorageProvider {
37
41
  dbName: string
38
42
  db?: IDBPDatabase<StorageIdbSchema>
@@ -42,10 +46,6 @@ export class StorageIdb extends StorageProvider implements sdk.WalletStorageProv
42
46
  this.dbName = `wallet-toolbox-${this.chain}net`
43
47
  }
44
48
 
45
- override adminStats(adminIdentityKey: string): Promise<StorageAdminStats> {
46
- throw new Error('Method not implemented.')
47
- }
48
-
49
49
  /**
50
50
  * This method must be called at least once before any other method accesses the database,
51
51
  * and each time the schema may have updated.
@@ -2299,4 +2299,8 @@ export class StorageIdb extends StorageProvider implements sdk.WalletStorageProv
2299
2299
  if (!rawTx) return
2300
2300
  t.rawTx = rawTx
2301
2301
  }
2302
+
2303
+ async adminStats(adminIdentityKey: string): Promise<StorageAdminStats> {
2304
+ throw new Error('Method intentionally not implemented for personal storage.')
2305
+ }
2302
2306
  }
@@ -1317,14 +1317,14 @@ select
1317
1317
  txUnfailWeek,
1318
1318
  txUnfailMonth,
1319
1319
  txUnfailTotal,
1320
- satoshisDefaultDay,
1321
- satoshisDefaultWeek,
1322
- satoshisDefaultMonth,
1323
- satoshisDefaultTotal,
1324
- satoshisOtherDay,
1325
- satoshisOtherWeek,
1326
- satoshisOtherMonth,
1327
- satoshisOtherTotal,
1320
+ satoshisDefaultDay: Number(satoshisDefaultDay),
1321
+ satoshisDefaultWeek: Number(satoshisDefaultWeek),
1322
+ satoshisDefaultMonth: Number(satoshisDefaultMonth),
1323
+ satoshisDefaultTotal: Number(satoshisDefaultTotal),
1324
+ satoshisOtherDay: Number(satoshisOtherDay),
1325
+ satoshisOtherWeek: Number(satoshisOtherWeek),
1326
+ satoshisOtherMonth: Number(satoshisOtherMonth),
1327
+ satoshisOtherTotal: Number(satoshisOtherTotal),
1328
1328
  basketsDay,
1329
1329
  basketsWeek,
1330
1330
  basketsMonth,
@@ -703,4 +703,45 @@ export class WalletStorageManager implements sdk.WalletStorage {
703
703
 
704
704
  return log
705
705
  }
706
+
707
+ getStores(): sdk.WalletStorageInfo[] {
708
+ const stores: sdk.WalletStorageInfo[] = []
709
+ if (this._active) {
710
+ stores.push({
711
+ isActive: true,
712
+ isEnabled: this.isActiveEnabled,
713
+ isBackup: false,
714
+ isConflicting: false,
715
+ userId: this._active.user!.userId,
716
+ storageIdentityKey: this._active.settings!.storageIdentityKey,
717
+ storageName: this._active.settings!.storageName,
718
+ storageClass: this._active.storage.constructor.name
719
+ })
720
+ }
721
+ for (const store of this._conflictingActives || []) {
722
+ stores.push({
723
+ isActive: true,
724
+ isEnabled: false,
725
+ isBackup: false,
726
+ isConflicting: true,
727
+ userId: store.user!.userId,
728
+ storageIdentityKey: store.settings!.storageIdentityKey,
729
+ storageName: store.settings!.storageName,
730
+ storageClass: store.storage.constructor.name
731
+ })
732
+ }
733
+ for (const store of this._backups || []) {
734
+ stores.push({
735
+ isActive: false,
736
+ isEnabled: false,
737
+ isBackup: true,
738
+ isConflicting: false,
739
+ userId: store.user!.userId,
740
+ storageIdentityKey: store.settings!.storageIdentityKey,
741
+ storageName: store.settings!.storageName,
742
+ storageClass: store.storage.constructor.name
743
+ })
744
+ }
745
+ return stores
746
+ }
706
747
  }
@@ -1,7 +1,9 @@
1
1
  import { before } from 'node:test'
2
- import { _tu } from '../../../test/utils/TestUtilsWalletStorage'
2
+ import { _tu, TestWalletOnly } from '../../../test/utils/TestUtilsWalletStorage'
3
3
  import { Setup } from '../../Setup'
4
4
  import { StorageKnex } from '../StorageKnex'
5
+ import { AuthFetch, WalletInterface } from '@bsv/sdk'
6
+ import { StorageAdminStats, StorageClient } from '../index.client'
5
7
 
6
8
  describe('storage adminStats tests', () => {
7
9
  jest.setTimeout(99999999)
@@ -16,16 +18,68 @@ describe('storage adminStats tests', () => {
16
18
  feeModel: { model: 'sat/kb', value: 1 }
17
19
  })
18
20
 
21
+ let setup: TestWalletOnly
22
+ let nextId = 0
23
+
19
24
  beforeAll(async () => {
20
25
  await storage.makeAvailable()
26
+
27
+ setup = await _tu.createTestWalletWithStorageClient({
28
+ chain: 'main',
29
+ rootKeyHex: env.devKeys[env.identityKey]
30
+ })
21
31
  })
22
32
  afterAll(async () => {
23
33
  await storage.destroy()
34
+ await setup.wallet.destroy()
24
35
  })
25
36
 
26
- test('0 adminStats', async () => {
37
+ test('0 adminStats StorageKnex', async () => {
27
38
  const r = await storage.adminStats(env.identityKey)
28
39
  expect(r.requestedBy).toBe(env.identityKey)
29
40
  expect(r.usersTotal).toBeGreaterThan(0)
30
41
  })
42
+
43
+ test('1 adminStats StorageServer via RPC', async () => {
44
+ const authFetch = new AuthFetch(setup.wallet)
45
+ const endpointUrl =
46
+ setup.chain === 'main' ? 'https://storage.babbage.systems' : 'https://staging-storage.babbage.systems'
47
+
48
+ const id = nextId++
49
+ const body = {
50
+ jsonrpc: '2.0',
51
+ method: 'adminStats',
52
+ params: [env.identityKey],
53
+ id
54
+ }
55
+
56
+ let response: Response
57
+ try {
58
+ response = await authFetch.fetch(endpointUrl, {
59
+ method: 'POST',
60
+ headers: { 'Content-Type': 'application/json' },
61
+ body: JSON.stringify(body)
62
+ })
63
+ } catch (eu: unknown) {
64
+ throw eu
65
+ }
66
+
67
+ if (!response.ok) {
68
+ throw new Error(`WalletStorageClient rpcCall: network error ${response.status} ${response.statusText}`)
69
+ }
70
+
71
+ const json = await response.json()
72
+ if (json.error) {
73
+ const { code, message, data } = json.error
74
+ const err = new Error(`RPC Error: ${message}`)
75
+ // You could attach more info here if you like:
76
+ ;(err as any).code = code
77
+ ;(err as any).data = data
78
+ throw err
79
+ }
80
+
81
+ const r = json.result as StorageAdminStats
82
+ expect(r.requestedBy).toBe(env.identityKey)
83
+ expect(r.usersTotal).toBeGreaterThan(0)
84
+ })
31
85
  })
@@ -5,6 +5,7 @@ export * from './remoting/StorageClient'
5
5
  export * from './remoting/StorageServer'
6
6
  export * from './schema/KnexMigrations'
7
7
  export * from './StorageKnex'
8
+ export * from './StorageIdb'
8
9
  export * from './schema/tables/index'
9
10
  export * from './schema/entities/index'
10
11
  export * as sync from './sync'
@@ -1,4 +1,5 @@
1
1
  export * from './WalletStorageManager'
2
+ export * from './StorageIdb'
2
3
  export * from './StorageProvider'
3
4
  export * from './StorageSyncReader'
4
5
  export * from './schema/tables/index'
@@ -1,9 +1,10 @@
1
- import { Beef, WalletOutput } from '@bsv/sdk'
1
+ import { Beef, PrivateKey, SignActionArgs, WalletOutput } from '@bsv/sdk'
2
2
  import { sdk, Services, Setup, StorageKnex, TableUser } from '../../../src'
3
3
  import { _tu, TuEnv } from '../../utils/TestUtilsWalletStorage'
4
4
  import { specOpInvalidChange, ValidListOutputsArgs, WERR_REVIEW_ACTIONS } from '../../../src/sdk'
5
5
  import {
6
6
  burnOneSatTestOutput,
7
+ createMainReviewSetup,
7
8
  createOneSatTestOutput,
8
9
  createSetup,
9
10
  doubleSpendOldChange,
@@ -203,49 +204,74 @@ describe('localWallet2 tests', () => {
203
204
  await storage.destroy()
204
205
  })
205
206
 
206
- test('8 jackie Beef', async () => {
207
+ test('8 Beef verifier', async () => {
207
208
  const setup = await createSetup(chain, options)
208
- const beef = Beef.fromBinary(beefJackie)
209
+ // replace bb with beef to test
210
+ const bb = new Beef().toBinary()
211
+ const beef = Beef.fromBinary(bb)
209
212
  console.log(beef.toLogString())
210
213
  const ok = await beef.verify(await setup.services.getChainTracker())
211
214
  await setup.wallet.destroy()
212
215
  })
213
- })
214
216
 
215
- async function createMainReviewSetup(): Promise<{
216
- env: TuEnv
217
- storage: StorageKnex
218
- services: Services
219
- }> {
220
- const env = _tu.getEnv('main')
221
- const knex = Setup.createMySQLKnex(process.env.MAIN_CLOUD_MYSQL_CONNECTION!)
222
- const storage = new StorageKnex({
223
- chain: env.chain,
224
- knex: knex,
225
- commissionSatoshis: 0,
226
- commissionPubKeyHex: undefined,
227
- feeModel: { model: 'sat/kb', value: 1 }
228
- })
229
- const servicesOptions = Services.createDefaultOptions(env.chain)
230
- if (env.whatsonchainApiKey) servicesOptions.whatsOnChainApiKey = env.whatsonchainApiKey
231
- const services = new Services(servicesOptions)
232
- storage.setServices(services)
233
- await storage.makeAvailable()
234
- return { env, storage, services }
235
- }
217
+ test.skip('9 received payment from wif and outpoint', async () => {
218
+ const setup = await createSetup(chain, options)
219
+ console.log(`active store ${setup.wallet.storage.getActiveStore()}`)
220
+ if (!setup.wallet.storage.isActiveEnabled) throw new Error('Active storage is not enabled.')
221
+
222
+ const pk = PrivateKey.fromWif('L4ZRWA...Nw4Brt8rvJLRZegPF2oiBKJaxUgr4e')
223
+ const outpoint = { txid: '5e2965a50618425af21bebddb9aa60c3e12f64c8e1eb44b6589273455a9760e9', vout: 0 }
224
+ const address = pk.toAddress()
225
+ console.log(`address: ${address.toString()}`)
226
+
227
+ const inputBEEF = await setup.activeStorage.getBeefForTransaction(outpoint.txid, { ignoreStorage: true })
228
+ const btx = inputBEEF.findTxid(outpoint.txid)
229
+ const satoshis = btx!.tx!.outputs[0]!.satoshis!
230
+
231
+ const unlock = Setup.getUnlockP2PKH(pk, satoshis)
232
+
233
+ const label = 'inputBrayden257'
234
+
235
+ const car = await setup.wallet.createAction({
236
+ inputBEEF: inputBEEF.toBinary(),
237
+ inputs: [
238
+ {
239
+ outpoint: `${outpoint.txid}.${outpoint.vout}`,
240
+ unlockingScriptLength: 108,
241
+ inputDescription: label
242
+ }
243
+ ],
244
+ labels: [label],
245
+ description: label
246
+ })
236
247
 
237
- const beefJackie = [
238
- 1, 1, 1, 1, 196, 222, 98, 76, 119, 112, 138, 49, 125, 79, 3, 8, 17, 96, 88, 134, 18, 94, 233, 6, 43, 58, 55, 200, 53,
239
- 21, 225, 58, 243, 130, 114, 64, 2, 0, 190, 239, 0, 1, 0, 1, 0, 0, 0, 1, 157, 193, 59, 124, 10, 214, 21, 108, 182, 51,
240
- 203, 122, 124, 52, 230, 65, 248, 166, 3, 136, 224, 45, 213, 116, 91, 81, 101, 168, 142, 252, 196, 20, 110, 0, 0, 0,
241
- 107, 72, 48, 69, 2, 33, 0, 144, 86, 132, 240, 56, 253, 101, 20, 254, 1, 184, 144, 98, 236, 225, 242, 239, 88, 99, 196,
242
- 58, 33, 141, 79, 234, 140, 7, 22, 254, 140, 65, 83, 2, 32, 113, 198, 86, 176, 19, 16, 165, 168, 5, 227, 70, 44, 5, 22,
243
- 144, 179, 172, 170, 13, 148, 3, 236, 35, 2, 74, 238, 235, 84, 148, 192, 102, 138, 65, 33, 3, 15, 101, 106, 207, 42,
244
- 192, 187, 51, 59, 128, 27, 240, 244, 240, 4, 224, 230, 41, 166, 89, 216, 46, 7, 24, 242, 180, 20, 90, 12, 57, 59, 144,
245
- 255, 255, 255, 255, 2, 136, 19, 0, 0, 0, 0, 0, 0, 25, 118, 169, 20, 240, 178, 178, 204, 51, 126, 211, 251, 43, 177,
246
- 154, 94, 189, 29, 53, 41, 220, 136, 142, 80, 136, 172, 208, 140, 0, 0, 0, 0, 0, 0, 25, 118, 169, 20, 217, 48, 110,
247
- 108, 236, 100, 116, 90, 181, 114, 45, 176, 198, 216, 150, 134, 16, 251, 10, 177, 136, 172, 0, 0, 0, 0
248
- ]
249
-
250
- const brayden1 =
251
- 'AQEBAXE5WqftwrSgBSQmDmQVTKGM+NJ/x9wm6you2hSiojHNAgC+7wH+AJgNABIC/jwPAQAAqJjdZODxqnt6LO/FaUZqvyqAoJWI5S7Dpcw7V62EcKj+PQ8BAALlFFz1z73NaIf5N0pUEVCDpERURgmwuZCKMRUV0lJLfwH9n4cAbjyL/rvExhckv/R7TbD9uhjeQOWC3bHjAbj1cAxTStUB/c5DABmU92c9jqsYvsAmxP+rpran9MBf0qKO7fArhV48NI39Af3mIQDqJhIcTpZ2uJZ1Tbq2g9chlguZuD+6bX+sR6QgaZAKegH98hAA+O7zs4OHtLxJkYDLP0hCauX1JovADjkZvdiwXFWR8XMB/XgIALCp1eqeo8VfZ5GKgxOBqXM4IxX4N7EVCtRDBwJ85RibAf09BABUAv5wVhmr20zi61zqkRpkY+jdInddrd1Rp72x88wxwgH9HwIAPRY0Luh4XlDAbzZ5pSsif9Vgs/qrWxrgB+Gc7w2Vpx4B/Q4BAE/ok7b+XhFf7sO4I8MDRWnoI/aEfWbfQh8TvbV4grDrAYYA5fpGI0OG+F/+oQM1xxqsut4iiUchU6evgjLH0ltP/90BQgCgOCMj08mysXsq4gU2OUZP2Z7r+joqXisrErQQ1pd89wEgAOEGf4rYEa0ONBCOh4mwNQxIw9yb43fFhedNhTtJv89bAREAM6Rzx526Ei7vUA8vuFh/f/7u/JR55M8vnJYrVD+8PhkBCQA2XTqUr+YUs4PcsIjgsNsuDDVv8RCe0b/mpZ4/df5+FwEFAPT9i5a9S5VI638TSeF8yqO8Czlevj5yZQ7/+23HLHsaAQMAFJUDwTu3hLphiPcLQMBrQ7G9mvHZ1vfJH2RSvsn1UmsBAABxpx+fnu8Bv3EtoWbXGPZfKpgJTz+8VoWhnDVD2ItlHgEBAJAM9/0kIm7qOMRImt5E7pEfNe9AnFypFjJF4RPciYR8AgEAAQAAAAG3C2Ge+k8SvYVKjUUVtD5b4yiO4HJ/cAlkkUTxceF2kQMAAABrSDBFAiEAi9Eerkoa1ZsmKPGAygtqEp8XOfbBYxca+7eOQGwxAZkCIEzKYkR0EZt5EjFoSZ2ifPgtK/GcCdMVNVbM4zaXE8wIQSEDlJVLZIIKAm1ADSQ12yJ4Kn8hlXoHQ16TfuvGX3xA+Dn/////b2QAAAAAAAAA/SMDIJff12hRv0Zej3FVk7IXcUhYu+lXD/O9XjOECjTiD/AmIQK6ed9fiudgSpgw8Dx5MwKBhq7eBnWhbwJdxPi+juwDgiAQCM50gNpBcCkY0eyOaEm6MrTWWx5A3GacMaHmMGsmbAAAAAAAFO6PVsy6KpyyUV4yCfnmq4sU0InUAwKYDR1Mb2Nrc21pdGgganVzdCBtaWdodCBiZSBjb29sIXgEAGXNHZ9pUnlYenVXeld6V3pXeld6V3pXenhXenVWelZ6VnpWelZ6Vnp2Vnp1cXFVem11WHkBwnhaeVp5IQrEB/DkvUS/wgc1WneLBGIlpwaPxZ7n7aQ62QWq2//IACBsJmsw5qExnGbcQB5b1rQyuklojuzRGClwQdqAdM4IEFx5VnlWeap2dlF/UX9Rf1F/UX9Rf1F/UX9Rf1F/UX9Rf1F/UX9Rf1F/UX9Rf1F/UX9Rf1F/UX9Rf1F/UX9Rf1F/UX9Rf1F/fH58fnx+fH58fnx+fH58fnx+fH58fnx+fH58fnx+fH58fnx+fH58fnx+fH58fnx+fH58fnx+fH58fnx+fH4BAH6Bd1d5VnlWeVZ5VnlTeVZ5VHlXeZWTlSFBQTbQjF7SvzugSK/m3K66/v///////////////////wBubpd2AJ9jbpNndmh3d3d7dXxuUpagY258lHt1fGhTeYJ3UnmCd1N5ASCAUX9Rf1F/UX9Rf1F/UX9Rf1F/UX9Rf1F/UX9Rf1F/UX9Rf1F/UX9Rf1F/UX9Rf1F/UX9Rf1F/UX9Rf1F/UX98fnx+fH58fnx+fH58fnx+fH58fnx+fH58fnx+fH58fnx+fH58fnx+fH58fnx+fH58fnx+fH58fnx+fH58fgEgUnmUf3dUU3mTUnmTATB4flJ+VHl+WHl+Un5TeX5SeX5XeX5rbW1tbW1tbHZXeaxrbW1tbW1sd2lYeXZ2gnduVJR/dXhYlH93d3d2AQB+gXd3e3V8WHl2doJ3bgEolH91eAEslH93d3d2AQB+gXd3d3gEAGXNHZ9pdgX+////AJ14VHmiaVl5qVV5iFp5Wnmsa21tbW1tbHcgAAAAAAAAABl2qRT+seU8HoTezriTu29X86nzVZ8mPYisIAAAAAAAAAAZdqkUIvTSnouUB4YdQp5vDx5W07Bf87WIrCAAAAAAAAAAGXapFJOWwgI9kQo1MDaB9BVVPkZZL1usiKwgAAAAAAAAABl2qRSuDS2WF8xmmuLa3DAw73CMiqRsaoisnwAAAAAAAAAZdqkUx0LxXP32OyV5aEXwNBuO8gFHaMOIrH4CAAAAAAAAGXapFGtDh2pDvdGeE0aEx9mqR4MkgvAriKwmAAAAAAAAABl2qRQB1fdcFILUuP97Yu7so3Rtt0IwKIisIAAAAAAAAAAZdqkUKRhCE8j3m5IU/7X54HREGbhu0PaIrCAAAAAAAAAAGXapFD3FD1rt3K085pPc9jpwFirv4Hh3iKwgAAAAAAAAABl2qRTWyPKlXY1rGWgp9AQWmP8Ef3iK/YisIAAAAAAAAAAZdqkUvgv1lRuYktV+igL9Y+Tp53mKqpCIrCAAAAAAAAAAGXapFE0wqhW+vGNnM975vfrS42m+/BZYiKwgAAAAAAAAABl2qRREOo1SNxh4S5eoy9mwrbzIlKnDo4isIAAAAAAAAAAZdqkU/eq1t6Zd22qnxaH8kfzMcQGzlRaIrCAAAAAAAAAAGXapFCP0+URNUPYWyRl+AnWfvzpMEV+0iKwgAAAAAAAAABl2qRS+Yfs9AXXeOsGITfd+Bht7wItQyoisIAAAAAAAAAAZdqkUJdPKtEBvXNboMYMSh42kCW/QZg6IrCAAAAAAAAAAGXapFL362JA6X52nbCpqPu9sSq+YWovUiKwgAAAAAAAAABl2qRQiVSYysFvpctAUwaYcf1oi3k7I74isIAAAAAAAAAAZdqkUAHsuULRQs0twfQnwCbJeFXtDZXCIrCAAAAAAAAAAGXapFPAlzI7JrR5VmwU2/iE33fBOwjx8iKwgAAAAAAAAABl2qRTFRnb4WSyd8Zm1OWfdLQl3YsvPaoisIAAAAAAAAAAZdqkUm4t4zIQlxJpYPgFwMvbS3mFVfweIrCAAAAAAAAAAGXapFLu73CjMJbl5xhvZIisAIaGrLqOYiKwgAAAAAAAAABl2qRSzSIkv88jHAV396uiel5T8o8sOlYisIAAAAAAAAAAZdqkU7KFNzJZuhtglk9Yg6bJLT9+ux0yIrD8AAAAAAAAAGXapFH5GNFL7FjSu/XeyC0nxkrwz+B0JiKwgAAAAAAAAABl2qRTBIFyv0NdbLNVHATCCOiG7hREUZIisIAAAAAAAAAAZdqkUfspK7DEpfhEf/Xxzsu0hFmJMZNiIrCAAAAAAAAAAGXapFFQvjv2egXVROx/PO0e8aDesU8eOiKwgAAAAAAAAABl2qRSbHbjzIqCvGfyLxvpiuUwshBqm54isIgAAAAAAAAAZdqkUdcLNfjCbktdq909R1yJdm5/OwCqIrCAAAAAAAAAAGXapFOPKEasLf4MzdkQXH3VngSE6MPIuiKwxAAAAAAAAABl2qRTVvs+ffE/LuqnIjX4Insavz8Q8BYisIAAAAAAAAAAZdqkUIVdf9HpVE8x5uO63cEUN8ujoNtSIrCAAAAAAAAAAGXapFOOq/PUwecvDwfrf1gYkAqP3ys4giKwgAAAAAAAAABl2qRRr5DzMu0nhYmp9G7mI/19c7inUpYisZQAAAAAAAAAZdqkU9uBuJNLRUu5P6ep9XEX1qirRKt6IrCAAAAAAAAAAGXapFMLqbFeUVBIvOeQ5WNtyv9yDILj4iKwhAAAAAAAAABl2qRTr3OBEd8YZ63Qr2vkzkJoKPynlD4isIAAAAAAAAAAZdqkUOR0+AoCj5inXdLv3ltKsrjGrfFqIrCAAAAAAAAAAGXapFLH5x3uDlVq+XK/tTpHdA34x2NsciKwgAAAAAAAAABl2qRR9gnN+f1kHQ3LqlKLZ9ohlXKOSlIisIQAAAAAAAAAZdqkUhnu4m7zkp8Hu/I5hE7C1Q6uabd6IrCAAAAAAAAAAGXapFGIpTcIxDcdVhgIpu6hvBJNGto2JiKwgAAAAAAAAABl2qRQ6AwS6I+lu5HFa83g343tmyPqEhoisIAAAAAAAAAAZdqkUK/nFprPk/0Gx5x/xEpAnZLOmLvqIrCAAAAAAAAAAGXapFLJH6kq8GA+weyRLlvcI66ZMTex4iKwgAAAAAAAAABl2qRTUqonKcqw2g+y6JeC2fEOIDE7hWIisIAAAAAAAAAAZdqkUqtzg/gyzPyq3TuKFY8ttY09W00yIrCEAAAAAAAAAGXapFERRMCxBiJ0ReuiBseytqBw0jTpViKwgAAAAAAAAABl2qRTx/O0DMRfhuYRMvDLuCmTlc8oCkoisQgAAAAAAAAAZdqkUZ50W09pJIMYvWbOAcwrWvvPOIP+IrCAAAAAAAAAAGXapFGEPhSzihr/sh4JQMj4DEWHGuTl8iKwgAAAAAAAAABl2qRQCIIs44d0nXOV/V+el4ZcERbV3a4isIAAAAAAAAAAZdqkUffwHk/+HADp3VQXFq/icz0KMXYaIrCAAAAAAAAAAGXapFBJpt9VOISUxJGwIOId0OUt+t+kniKwgAAAAAAAAABl2qRQDiKz3dvk6sqqWfI57KVJKSlLyCoisIAAAAAAAAAAZdqkUlJm3/DfEeuIsyF1u1XvbmS+OP1OIrCAAAAAAAAAAGXapFI6j/LhH4G4NUEUrC0Q/9OUYeM/ciKwgAAAAAAAAABl2qRSqbmX4HmLumB8j3FTfLk5KTVBD0YisIAAAAAAAAAAZdqkUYCOOmpUyYyT/XEvayiazI7yIwXGIrCAAAAAAAAAAGXapFHIAjUOA39xlw4letebtIMIbQyMTiKwgAAAAAAAAABl2qRQ+e23+mRlnPRRGKAgq7OIzsgYzC4isIQAAAAAAAAAZdqkU0lx6y4ltClRalrzAH2vd/9JE7DKIrCAAAAAAAAAAGXapFItcFN4PQ5KQRQL4JI5F+Pq84HtMiKwgAAAAAAAAABl2qRTNmGcwowKdQhvLMe1uYuRk0ErPsIisIAAAAAAAAAAZdqkUkNguMZvhzo7Qb+WL7N6rrTIAr/iIrEoBAAAAAAAAGXapFAKr1S+EvvuWn1FSnSewDx0MtgNjiKwgAAAAAAAAABl2qRR/PSwMFpsLHwOHR0uaN3BZMSonhYisIAAAAAAAAAAZdqkUJjVnJGTs20AaOd7NZV39A1S04CuIrCAAAAAAAAAAGXapFPRhNqLrBui85lJu8pHxFJnql1g3iKwgAAAAAAAAABl2qRTiKqnetZmp8+OnnIiSn+pTL/+mRIisIAAAAAAAAAAZdqkUVRkMIRRWSQpYfyiDMJEATv5U0lmIrCAAAAAAAAAAGXapFElxn2iq5QKeKZ0MNH3CNKt+mqodiKwgAAAAAAAAABl2qRSZo44CECev2t5O5sCWrj9+ItQsl4isIAAAAAAAAAAZdqkUu5kJYMJQ7L17L8rO/Uag7pd6FRaIrCAAAAAAAAAAGXapFDWeZcJj0NKpUdejnA1pblu9+QLFiKwgAAAAAAAAABl2qRQph8G6Jkm3IsSlHeiMZrH5PNahe4isIAAAAAAAAAAZdqkUzZvwHyHV631OiZRBDSmlDkHFZlCIrJYAAAAAAAAAGXapFO9e9nCH/tujvl3MrmqQYBfkAKWuiKwgAAAAAAAAABl2qRQjlT+SIN5essK0IDCn8qWzGAJUj4isIAAAAAAAAAAZdqkUDEV0nNOgJKvIhc6e2WeXDmh5yauIrCAAAAAAAAAAGXapFBidQ+ZIqFp6bAG8yJNXjpgdLHthiKwgAAAAAAAAABl2qRR6keFJrHwdMNKvhqpb6zAtabywaoisIAAAAAAAAAAZdqkUNP2d5/K169H67WgXATnzWsCnL0+IrCAAAAAAAAAAGXapFF5yvcAx9I3n0iBhLV6d1taG4f6jiKwgAAAAAAAAABl2qRTfZv2R2Ohu5MG2DgjiQVJPulpVQYisIAAAAAAAAAAZdqkUQ+5VX9vd8iUl5qHYcHYO/taeirSIrCAAAAAAAAAAGXapFGUQL+WkC+YuxF/640NEWTrPgPU7iKwgAAAAAAAAABl2qRRQZqw+7s0MDvIDq8SRGFA6rpluzoisIAAAAAAAAAAZdqkUvEWZ4fbVb1iTBbYHiVAuofbmlYyIrCAAAAAAAAAAGXapFPdpuwIErTJqZ/R7/uu9Vopt0CL1iKwgAAAAAAAAABl2qRQZjzazl6LQJ6xdI9jPPPuHeaAvd4isIAAAAAAAAAAZdqkUd7j5xJi6lfj+aEcqjdXOiTK9D2uIrCAAAAAAAAAAGXapFHjP2DyQ19kq1gEzS3TuBKxLtcnViKwgAAAAAAAAABl2qRTxOUVfsbwr+/SOGzRE2E0t08C5S4isIgAAAAAAAAAZdqkUxHnowY6ZRONApyCK8O0yLZpRlgeIrCAAAAAAAAAAGXapFJK4zpSXG58bc1U+pZtQD5+chinEiKwgAAAAAAAAABl2qRRFg1rCHUydOxiDO0hChj+K8NZ/eoisIAAAAAAAAAAZdqkUcD0PzMNoBSL5CiA6vRtZpk4mW6SIrCAAAAAAAAAAGXapFCO2IihLEUaUYa26D6C3XGSm9kepiKwgAAAAAAAAABl2qRS22u/qmRgyi7g8u/QodMVDkXiuUoisIAAAAAAAAAAZdqkU2Hf9qoewt4M234goCJgUNQUi0aKIrCAAAAAAAAAAGXapFBh1GtNTmGyDL8MLeWnT8g1uLDhIiKwgAAAAAAAAABl2qRSNfXPtusDs2IEZ0zY1y/7GYRIHV4isIAAAAAAAAAAZdqkUXUFCRUz72mMqQw33jFLS2qrGJiyIrCsAAAAAAAAAGXapFGeqpFmzB8pRfphKd47V90AqVYM6iKxQAAAAAAAAABl2qRRk4KA/Fb6rtw89o7ueeXWYQZriA4isIAAAAAAAAAAZdqkUlluO16nDmWfBfkTnhLrwLy562JuIrAAAAAAAAQAAAAHlFFz1z73NaIf5N0pUEVCDpERURgmwuZCKMRUV0lJLfw0AAABqRzBEAiBCp67/9fF3k1RzHsGwV72MNq0VjvUKCl9u6kSL8rdoOgIgYfIpiO3Y9wPJIh6EUa6WuqEv4UVJlCrVFGET1pSPpuNBIQK7BDaAW1Mwq/L5hIdpaeulIaOlzH7gtynIQ664DOYBrv////8CCgAAAAAAAAAZdqkUA+EIgfWjrx5V0h7kecPWhZZw+OiIrBUAAAAAAAAAGXapFLAAIeAtzjuuRG6Nj9UC4SOWRZZ2iKwAAAAA'
248
+ const st = car.signableTransaction!
249
+ const beef = Beef.fromBinary(st.tx)
250
+ const tx = beef.findAtomicTransaction(beef.txs.slice(-1)[0].txid)!
251
+ tx.inputs[0].unlockingScriptTemplate = unlock
252
+ await tx.sign()
253
+ const unlockingScript = tx.inputs[0].unlockingScript!.toHex()
254
+
255
+ const signArgs: SignActionArgs = {
256
+ reference: st.reference,
257
+ spends: { 0: { unlockingScript } },
258
+ options: {
259
+ acceptDelayedBroadcast: false
260
+ }
261
+ }
262
+
263
+ const sar = await setup.wallet.signAction(signArgs)
264
+
265
+ {
266
+ const beef = Beef.fromBinary(sar.tx!)
267
+ const txid = sar.txid!
268
+
269
+ console.log(`
270
+ BEEF
271
+ ${beef.toHex()}
272
+ ${beef.toLogString()}
273
+ `)
274
+ }
275
+ await setup.wallet.destroy()
276
+ })
277
+ })
@@ -44,10 +44,12 @@ describe('operations.man tests', () => {
44
44
  let r = await storage.listOutputs(auth, vargs)
45
45
  if (r.totalOutputs > 0) {
46
46
  const total: number = r.outputs.reduce((s, o) => (s += o.satoshis), 0)
47
- log += `userId ${userId}: ${r.totalOutputs} utxos updated, total ${total}, ${user.identityKey}\n`
47
+ let l = `userId ${userId}: ${r.totalOutputs} utxos updated, total ${total}, ${user.identityKey}\n`
48
48
  for (const o of r.outputs) {
49
- log += ` ${o.outpoint} ${o.satoshis} now ${o.spendable ? 'spendable' : 'spent'}\n`
49
+ l += ` ${o.outpoint} ${o.satoshis} now ${o.spendable ? 'spendable' : 'spent'}\n`
50
50
  }
51
+ console.log(l)
52
+ log += l
51
53
  withInvalid[userId] = { user, outputs: r.outputs, total }
52
54
  }
53
55
  }
@@ -120,7 +122,7 @@ describe('operations.man tests', () => {
120
122
 
121
123
  test('2 review and unfail false invalids', async () => {
122
124
  const { env, storage, services } = await createMainReviewSetup()
123
- let offset = 600
125
+ let offset = 700
124
126
  const limit = 100
125
127
  let allUnfails: number[] = []
126
128
  for (;;) {
@@ -11,8 +11,18 @@ import {
11
11
  SignActionOptions,
12
12
  SignActionResult
13
13
  } from '@bsv/sdk'
14
- import { EntityProvenTxReq, ScriptTemplateBRC29, sdk, StorageKnex, verifyOne, verifyTruthy, wait } from '../../src'
15
- import { _tu, logger, TestWalletNoSetup } from './TestUtilsWalletStorage'
14
+ import {
15
+ EntityProvenTxReq,
16
+ ScriptTemplateBRC29,
17
+ sdk,
18
+ Services,
19
+ Setup,
20
+ StorageKnex,
21
+ verifyOne,
22
+ verifyTruthy,
23
+ wait
24
+ } from '../../src'
25
+ import { _tu, logger, TestWalletNoSetup, TuEnv } from './TestUtilsWalletStorage'
16
26
  import { validateCreateActionArgs, ValidCreateActionArgs } from '../../src/sdk'
17
27
  import { setDisableDoubleSpendCheckForTest } from '../../src/storage/methods/createAction'
18
28
 
@@ -329,3 +339,25 @@ export async function doubleSpendOldChange(
329
339
  const sar = await setup.wallet.signAction(signArgs)
330
340
  return sar
331
341
  }
342
+
343
+ export async function createMainReviewSetup(): Promise<{
344
+ env: TuEnv
345
+ storage: StorageKnex
346
+ services: Services
347
+ }> {
348
+ const env = _tu.getEnv('main')
349
+ const knex = Setup.createMySQLKnex(process.env.MAIN_CLOUD_MYSQL_CONNECTION!)
350
+ const storage = new StorageKnex({
351
+ chain: env.chain,
352
+ knex: knex,
353
+ commissionSatoshis: 0,
354
+ commissionPubKeyHex: undefined,
355
+ feeModel: { model: 'sat/kb', value: 1 }
356
+ })
357
+ const servicesOptions = Services.createDefaultOptions(env.chain)
358
+ if (env.whatsonchainApiKey) servicesOptions.whatsOnChainApiKey = env.whatsonchainApiKey
359
+ const services = new Services(servicesOptions)
360
+ storage.setServices(services)
361
+ await storage.makeAvailable()
362
+ return { env, storage, services }
363
+ }