@bsv/wallet-toolbox 1.6.1 → 1.6.2

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 (71) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/docs/client.md +13 -0
  3. package/docs/wallet.md +13 -0
  4. package/mobile/out/src/services/Services.d.ts.map +1 -1
  5. package/mobile/out/src/services/Services.js +7 -3
  6. package/mobile/out/src/services/Services.js.map +1 -1
  7. package/mobile/out/src/services/chaintracker/chaintracks/Ingest/LiveIngestorWhatsOnChainPoll.d.ts.map +1 -1
  8. package/mobile/out/src/services/chaintracker/chaintracks/Ingest/LiveIngestorWhatsOnChainPoll.js +1 -14
  9. package/mobile/out/src/services/chaintracker/chaintracks/Ingest/LiveIngestorWhatsOnChainPoll.js.map +1 -1
  10. package/mobile/out/src/services/chaintracker/chaintracks/Ingest/WhatsOnChainServices.d.ts +1 -0
  11. package/mobile/out/src/services/chaintracker/chaintracks/Ingest/WhatsOnChainServices.d.ts.map +1 -1
  12. package/mobile/out/src/services/chaintracker/chaintracks/Ingest/WhatsOnChainServices.js +18 -0
  13. package/mobile/out/src/services/chaintracker/chaintracks/Ingest/WhatsOnChainServices.js.map +1 -1
  14. package/mobile/out/src/services/createDefaultWalletServicesOptions.js +4 -2
  15. package/mobile/out/src/services/createDefaultWalletServicesOptions.js.map +1 -1
  16. package/mobile/out/src/signer/methods/internalizeAction.js +2 -2
  17. package/mobile/out/src/signer/methods/internalizeAction.js.map +1 -1
  18. package/mobile/out/src/storage/StorageProvider.d.ts.map +1 -1
  19. package/mobile/out/src/storage/StorageProvider.js +1 -0
  20. package/mobile/out/src/storage/StorageProvider.js.map +1 -1
  21. package/mobile/out/src/utility/utilityHelpers.d.ts +2 -0
  22. package/mobile/out/src/utility/utilityHelpers.d.ts.map +1 -1
  23. package/mobile/out/src/utility/utilityHelpers.js +7 -0
  24. package/mobile/out/src/utility/utilityHelpers.js.map +1 -1
  25. package/mobile/package-lock.json +2 -2
  26. package/mobile/package.json +1 -1
  27. package/out/src/services/Services.d.ts.map +1 -1
  28. package/out/src/services/Services.js +7 -3
  29. package/out/src/services/Services.js.map +1 -1
  30. package/out/src/services/chaintracker/__tests/ChaintracksServiceClient.test.js +3 -1
  31. package/out/src/services/chaintracker/__tests/ChaintracksServiceClient.test.js.map +1 -1
  32. package/out/src/services/chaintracker/chaintracks/Ingest/LiveIngestorWhatsOnChainPoll.d.ts.map +1 -1
  33. package/out/src/services/chaintracker/chaintracks/Ingest/LiveIngestorWhatsOnChainPoll.js +1 -14
  34. package/out/src/services/chaintracker/chaintracks/Ingest/LiveIngestorWhatsOnChainPoll.js.map +1 -1
  35. package/out/src/services/chaintracker/chaintracks/Ingest/WhatsOnChainServices.d.ts +1 -0
  36. package/out/src/services/chaintracker/chaintracks/Ingest/WhatsOnChainServices.d.ts.map +1 -1
  37. package/out/src/services/chaintracker/chaintracks/Ingest/WhatsOnChainServices.js +18 -0
  38. package/out/src/services/chaintracker/chaintracks/Ingest/WhatsOnChainServices.js.map +1 -1
  39. package/out/src/services/chaintracker/chaintracks/__tests/ChaintracksClientApi.test.js +24 -15
  40. package/out/src/services/chaintracker/chaintracks/__tests/ChaintracksClientApi.test.js.map +1 -1
  41. package/out/src/services/chaintracker/chaintracks/__tests/LocalCdnServer.d.ts.map +1 -1
  42. package/out/src/services/chaintracker/chaintracks/__tests/LocalCdnServer.js +9 -2
  43. package/out/src/services/chaintracker/chaintracks/__tests/LocalCdnServer.js.map +1 -1
  44. package/out/src/services/createDefaultWalletServicesOptions.js +4 -2
  45. package/out/src/services/createDefaultWalletServicesOptions.js.map +1 -1
  46. package/out/src/signer/methods/internalizeAction.js +2 -2
  47. package/out/src/signer/methods/internalizeAction.js.map +1 -1
  48. package/out/src/storage/StorageProvider.d.ts.map +1 -1
  49. package/out/src/storage/StorageProvider.js +1 -0
  50. package/out/src/storage/StorageProvider.js.map +1 -1
  51. package/out/src/storage/__test/getBeefForTransaction.test.js +8 -6
  52. package/out/src/storage/__test/getBeefForTransaction.test.js.map +1 -1
  53. package/out/src/utility/Format.js +2 -2
  54. package/out/src/utility/utilityHelpers.d.ts +2 -0
  55. package/out/src/utility/utilityHelpers.d.ts.map +1 -1
  56. package/out/src/utility/utilityHelpers.js +7 -0
  57. package/out/src/utility/utilityHelpers.js.map +1 -1
  58. package/out/tsconfig.all.tsbuildinfo +1 -1
  59. package/package.json +1 -1
  60. package/src/services/Services.ts +6 -2
  61. package/src/services/chaintracker/__tests/ChaintracksServiceClient.test.ts +3 -1
  62. package/src/services/chaintracker/chaintracks/Ingest/LiveIngestorWhatsOnChainPoll.ts +3 -17
  63. package/src/services/chaintracker/chaintracks/Ingest/WhatsOnChainServices.ts +19 -0
  64. package/src/services/chaintracker/chaintracks/__tests/ChaintracksClientApi.test.ts +26 -16
  65. package/src/services/chaintracker/chaintracks/__tests/LocalCdnServer.ts +10 -2
  66. package/src/services/createDefaultWalletServicesOptions.ts +5 -5
  67. package/src/signer/methods/internalizeAction.ts +2 -2
  68. package/src/storage/StorageProvider.ts +1 -0
  69. package/src/storage/__test/getBeefForTransaction.test.ts +37 -35
  70. package/src/utility/Format.ts +2 -2
  71. package/src/utility/utilityHelpers.ts +7 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bsv/wallet-toolbox",
3
- "version": "1.6.1",
3
+ "version": "1.6.2",
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",
@@ -413,10 +413,14 @@ export class Services implements WalletServices {
413
413
  async hashToHeader(hash: string): Promise<BlockHeader> {
414
414
  const method = async () => {
415
415
  const header = await this.options.chaintracks!.findHeaderForBlockHash(hash)
416
- if (!header) throw new WERR_INVALID_PARAMETER('hash', `valid blockhash '${hash}' on mined chain ${this.chain}`)
417
416
  return header
418
417
  }
419
- return this.invokeChaintracksWithRetry(method)
418
+ let header = await this.invokeChaintracksWithRetry(method)
419
+ if (!header) {
420
+ header = await this.whatsonchain.getBlockHeaderByHash(hash)
421
+ }
422
+ if (!header) throw new WERR_INVALID_PARAMETER('hash', `valid blockhash '${hash}' on mined chain ${this.chain}`)
423
+ return header
420
424
  }
421
425
 
422
426
  async getMerklePath(txid: string, useNext?: boolean): Promise<GetMerklePathResult> {
@@ -23,5 +23,7 @@ describe('ChaintracksServiceClient tests', () => {
23
23
  })
24
24
 
25
25
  function makeClient(chain: sdk.Chain) {
26
- return new ChaintracksServiceClient(chain, `https://npm-registry.babbage.systems:${chain === 'main' ? 8084 : 8083}`)
26
+ //const chaintracksUrl = `https://npm-registry.babbage.systems:${chain === 'main' ? 8084 : 8083}`
27
+ const chaintracksUrl = `https://${chain}net-chaintracks.babbage.systems`
28
+ return new ChaintracksServiceClient(chain, chaintracksUrl)
27
29
  }
@@ -2,11 +2,10 @@ import { BlockHeader, Chain } from '../../../../sdk'
2
2
  import { wait } from '../../../../utility/utilityHelpers'
3
3
  import { LiveIngestorBase, LiveIngestorBaseOptions } from './LiveIngestorBase'
4
4
  import {
5
- EnqueueHandler,
6
- ErrorHandler,
7
5
  WhatsOnChainServices,
8
6
  WhatsOnChainServicesOptions,
9
- WocGetHeadersHeader
7
+ WocGetHeadersHeader,
8
+ wocGetHeadersHeaderToBlockHeader
10
9
  } from './WhatsOnChainServices'
11
10
 
12
11
  export interface LiveIngestorWhatsOnChainOptions extends LiveIngestorBaseOptions, WhatsOnChainServicesOptions {
@@ -81,20 +80,7 @@ export class LiveIngestorWhatsOnChainPoll extends LiveIngestorBase {
81
80
  const newHeaders = headers.filter(h => !lastHeaders.some(lh => lh.hash === h.hash))
82
81
 
83
82
  for (const h of newHeaders) {
84
- const bits: number = typeof h.bits === 'string' ? parseInt(h.bits, 16) : h.bits
85
- if (!h.previousblockhash) {
86
- h.previousblockhash = '0000000000000000000000000000000000000000000000000000000000000000' // genesis
87
- }
88
- const bh: BlockHeader = {
89
- height: h.height,
90
- hash: h.hash,
91
- version: h.version,
92
- previousHash: h.previousblockhash,
93
- merkleRoot: h.merkleroot,
94
- time: h.time,
95
- bits,
96
- nonce: h.nonce
97
- }
83
+ const bh = wocGetHeadersHeaderToBlockHeader(h)
98
84
  liveHeaders.unshift(bh)
99
85
  }
100
86
 
@@ -192,6 +192,25 @@ export interface WocGetHeadersHeader {
192
192
  num_tx: number
193
193
  }
194
194
 
195
+ export function wocGetHeadersHeaderToBlockHeader(h: WocGetHeadersHeader): BlockHeader {
196
+ const bits: number = typeof h.bits === 'string' ? parseInt(h.bits, 16) : h.bits
197
+ if (!h.previousblockhash) {
198
+ h.previousblockhash = '0000000000000000000000000000000000000000000000000000000000000000' // genesis
199
+ }
200
+ const bh: BlockHeader = {
201
+ height: h.height,
202
+ hash: h.hash,
203
+ version: h.version,
204
+ previousHash: h.previousblockhash,
205
+ merkleRoot: h.merkleroot,
206
+ time: h.time,
207
+ bits,
208
+ nonce: h.nonce
209
+ }
210
+
211
+ return bh
212
+ }
213
+
195
214
  export interface GetHeaderByteFileLinksResult {
196
215
  sourceUrl: string
197
216
  fileName: string
@@ -22,13 +22,14 @@ clientClass = 'Chaintracks'
22
22
  const includeLocalServiceClient = true
23
23
  const includeLocalServiceChaintracks = true
24
24
  const includeNpmRegistryClient = true
25
+ const includeGcrTestClient = true
25
26
 
26
27
  describe(`ChaintracksClientApi tests`, () => {
27
28
  jest.setTimeout(999999999)
28
29
 
29
30
  const chain: Chain = 'main'
30
31
 
31
- const clients: ChaintracksClientApi[] = []
32
+ const clients: { client: ChaintracksClientApi; chain: Chain }[] = []
32
33
 
33
34
  let localService: ChaintracksService
34
35
  let localServiceStorage: ChaintracksStorageApi
@@ -43,19 +44,28 @@ describe(`ChaintracksClientApi tests`, () => {
43
44
 
44
45
  if (includeLocalServiceClient) {
45
46
  localServiceClient = new ChaintracksServiceClient(chain, `http://localhost:${localService.port}`, {})
46
- clients.push(localServiceClient)
47
+ clients.push({ client: localServiceClient, chain })
47
48
  }
48
49
 
49
50
  if (includeLocalServiceChaintracks) {
50
- clients.push(localService.chaintracks)
51
+ clients.push({ client: localService.chaintracks, chain })
51
52
  }
52
53
  }
53
54
 
55
+ if (includeGcrTestClient) {
56
+ const gcr = new ChaintracksServiceClient('test', `https://testnet-chaintracks.babbage.systems`, {})
57
+ clients.push({ client: gcr, chain: 'test' })
58
+ }
59
+ if (includeGcrTestClient) {
60
+ const gcr = new ChaintracksServiceClient('main', `https://mainnet-chaintracks.babbage.systems`, {})
61
+ clients.push({ client: gcr, chain: 'main' })
62
+ }
63
+
54
64
  if (includeNpmRegistryClient) {
55
- clients.push(makeNpmRegistryClient(chain))
65
+ clients.push({ client: makeNpmRegistryClient(chain), chain })
56
66
  }
57
67
 
58
- const ft = await clients[0].findChainTipHeader()
68
+ const ft = await clients[0].client.findChainTipHeader()
59
69
  if (!ft) throw new Error('No chain tip found')
60
70
  firstTip = ft
61
71
  })
@@ -65,30 +75,30 @@ describe(`ChaintracksClientApi tests`, () => {
65
75
  })
66
76
 
67
77
  test('0 getChain', async () => {
68
- for (const client of clients) {
78
+ for (const { client, chain } of clients) {
69
79
  const gotChain = await client.getChain()
70
80
  expect(gotChain).toBe(chain)
71
81
  }
72
82
  })
73
83
 
74
84
  test('1 getInfo', async () => {
75
- for (const client of clients) {
85
+ for (const { client, chain } of clients) {
76
86
  const gotInfo = await client.getInfo()
77
87
  expect(gotInfo.chain).toBe(chain)
78
88
  expect(gotInfo.heightBulk).toBeGreaterThan(700000)
79
- expect(gotInfo.heightLive).toBeGreaterThanOrEqual(firstTip.height)
89
+ expect(gotInfo.heightLive).toBeGreaterThanOrEqual(firstTip.height - 2)
80
90
  }
81
91
  })
82
92
 
83
93
  test('2 getPresentHeight', async () => {
84
- for (const client of clients) {
94
+ for (const { client, chain } of clients) {
85
95
  const presentHeight = await client.getPresentHeight()
86
- expect(presentHeight).toBeGreaterThanOrEqual(firstTip.height)
96
+ expect(presentHeight).toBeGreaterThanOrEqual(firstTip.height - 2)
87
97
  }
88
98
  })
89
99
 
90
100
  test('3 getHeaders', async () => {
91
- for (const client of clients) {
101
+ for (const { client, chain } of clients) {
92
102
  const info = await client.getInfo()
93
103
  const h0 = info.heightBulk + 1
94
104
  const h1 = info.heightLive || 10
@@ -113,21 +123,21 @@ describe(`ChaintracksClientApi tests`, () => {
113
123
  })
114
124
 
115
125
  test('4 findChainTipHeader', async () => {
116
- for (const client of clients) {
126
+ for (const { client, chain } of clients) {
117
127
  const tipHeader = await client.findChainTipHeader()
118
128
  expect(tipHeader.height >= firstTip.height).toBe(true)
119
129
  }
120
130
  })
121
131
 
122
132
  test('5 findChainTipHash', async () => {
123
- for (const client of clients) {
133
+ for (const { client, chain } of clients) {
124
134
  const hash = await client.findChainTipHash()
125
135
  expect(hash.length === 64).toBe(true)
126
136
  }
127
137
  })
128
138
 
129
139
  test('6 findHeaderForHeight', async () => {
130
- for (const client of clients) {
140
+ for (const { client, chain } of clients) {
131
141
  const header0 = await client.findHeaderForHeight(0)
132
142
  expect(header0 !== undefined).toBe(true)
133
143
  if (header0) {
@@ -137,13 +147,13 @@ describe(`ChaintracksClientApi tests`, () => {
137
147
  const header = await client.findHeaderForHeight(firstTip.height)
138
148
  expect(header && header.height === firstTip.height).toBe(true)
139
149
 
140
- const missing = await client.findHeaderForHeight(1000 + firstTip.height)
150
+ const missing = await client.findHeaderForHeight(99999999)
141
151
  expect(missing === undefined).toBe(true)
142
152
  }
143
153
  })
144
154
 
145
155
  test('7 addHeader', async () => {
146
- for (const client of clients) {
156
+ for (const { client, chain } of clients) {
147
157
  const t = await client.findChainTipHeader()
148
158
  const h: BaseBlockHeader = {
149
159
  version: t.version,
@@ -42,11 +42,19 @@ export class LocalCdnServer {
42
42
  this.app.get('/download/:filename', (req, res) => {
43
43
  const filePath = path.join(this.folder, req.params.filename)
44
44
 
45
- if (!fs.existsSync(filePath)) {
45
+ // Ensure filePath stays within the allowed folder (prevent directory traversal)
46
+ const resolvedFolder = path.resolve(this.folder)
47
+ const resolvedFilePath = path.resolve(filePath)
48
+ if (!resolvedFilePath.startsWith(resolvedFolder + path.sep)) {
49
+ // Prevent access to files outside the allowed directory
50
+ return res.status(403).json({ error: 'Access denied' })
51
+ }
52
+
53
+ if (!fs.existsSync(resolvedFilePath)) {
46
54
  return res.status(404).json({ error: 'File not found' })
47
55
  }
48
56
 
49
- res.download(filePath, err => {
57
+ res.download(resolvedFilePath, err => {
50
58
  if (err) {
51
59
  res.status(500).json({ error: 'Error downloading file' })
52
60
  }
@@ -15,6 +15,9 @@ export function createDefaultWalletServicesOptions(
15
15
  ? 'mainnet_9596de07e92300c6287e4393594ae39c' // no plan
16
16
  : 'testnet_0e6cf72133b43ea2d7861da2a38684e3' // personal "starter" key
17
17
 
18
+ //const chaintracksUrl = `https://npm-registry.babbage.systems:${chain === 'main' ? 8084 : 8083}`
19
+ const chaintracksUrl = `https://${chain}net-chaintracks.babbage.systems`
20
+
18
21
  const o: WalletServicesOptions = {
19
22
  chain,
20
23
  taalApiKey,
@@ -36,11 +39,8 @@ export function createDefaultWalletServicesOptions(
36
39
  fiatUpdateMsecs: 1000 * 60 * 60 * 24, // 24 hours
37
40
  disableMapiCallback: true, // Rely on WalletMonitor by default.
38
41
  exchangeratesapiKey: 'bd539d2ff492bcb5619d5f27726a766f',
39
- chaintracksFiatExchangeRatesUrl: `https://npm-registry.babbage.systems:${chain === 'main' ? 8084 : 8083}/getFiatExchangeRates`,
40
- chaintracks: new ChaintracksServiceClient(
41
- chain,
42
- `https://npm-registry.babbage.systems:${chain === 'main' ? 8084 : 8083}`
43
- ),
42
+ chaintracksFiatExchangeRatesUrl: `${chaintracksUrl}/getFiatExchangeRates`,
43
+ chaintracks: new ChaintracksServiceClient(chain, chaintracksUrl),
44
44
  arcUrl: arcDefaultUrl(chain),
45
45
  arcConfig: {
46
46
  apiKey: arcApiKey ?? undefined,
@@ -63,14 +63,14 @@ export async function internalizeAction(
63
63
  function setupWalletPaymentForOutput(o: InternalizeOutput, dargs: ValidInternalizeActionArgs) {
64
64
  const p = o.paymentRemittance
65
65
  const output = tx.outputs[o.outputIndex]
66
- if (!p) throw new WERR_INVALID_PARAMETER('paymentRemitance', `valid for protocol ${o.protocol}`)
66
+ if (!p) throw new WERR_INVALID_PARAMETER('paymentRemittance', `valid for protocol ${o.protocol}`)
67
67
 
68
68
  const keyID = `${p.derivationPrefix} ${p.derivationSuffix}`
69
69
 
70
70
  const privKey = wallet.keyDeriver!.derivePrivateKey(brc29ProtocolID, keyID, p.senderIdentityKey)
71
71
  const expectedLockScript = new P2PKH().lock(privKey.toAddress())
72
72
  if (output.lockingScript.toHex() !== expectedLockScript.toHex())
73
- throw new WERR_INVALID_PARAMETER('paymentRemitance', `locked by script conforming to BRC-29`)
73
+ throw new WERR_INVALID_PARAMETER('paymentRemittance', `locked by script conforming to BRC-29`)
74
74
  }
75
75
 
76
76
  function setupBasketInsertionForOutput(o: InternalizeOutput, dargs: ValidInternalizeActionArgs) {
@@ -103,6 +103,7 @@ export abstract class StorageProvider extends StorageReaderWriter implements Wal
103
103
  this.feeModel = options.feeModel
104
104
  this.commissionPubKeyHex = options.commissionPubKeyHex
105
105
  this.commissionSatoshis = options.commissionSatoshis
106
+ this.maxRecursionDepth = 12
106
107
  }
107
108
 
108
109
  abstract reviewStatus(args: { agedLimit: Date; trx?: TrxToken }): Promise<{ log: string }>
@@ -1,32 +1,9 @@
1
1
  import { Beef, ListActionsResult, ListOutputsResult } from '@bsv/sdk'
2
+ import { WalletError } from '../../sdk/WalletError'
3
+ import { StorageAdminStats, StorageProvider } from '../StorageProvider'
4
+ import { Chain } from '../../sdk/types'
5
+ import { Services } from '../../services/Services'
2
6
  import {
3
- TrxToken,
4
- PurgeParams,
5
- PurgeResults,
6
- ProvenOrRawTx,
7
- AuthId,
8
- ValidListActionsArgs,
9
- ValidListOutputsArgs,
10
- FindCertificatesArgs,
11
- FindOutputBasketsArgs,
12
- FindOutputsArgs,
13
- FindOutputTagMapsArgs,
14
- FindProvenTxReqsArgs,
15
- FindProvenTxsArgs,
16
- FindTxLabelMapsArgs,
17
- FindCertificateFieldsArgs,
18
- FindCommissionsArgs,
19
- FindMonitorEventsArgs,
20
- FindOutputTagsArgs,
21
- FindSyncStatesArgs,
22
- FindTransactionsArgs,
23
- FindTxLabelsArgs,
24
- FindUsersArgs,
25
- FindForUserSincePagedArgs,
26
- StorageGetBeefOptions
27
- } from '../../sdk'
28
- import {
29
- StorageProvider,
30
7
  TableCertificate,
31
8
  TableCertificateField,
32
9
  TableCertificateX,
@@ -43,17 +20,41 @@ import {
43
20
  TableTransaction,
44
21
  TableTxLabel,
45
22
  TableTxLabelMap,
46
- TableUser,
47
- sdk,
48
- Services,
49
- EntityProvenTx,
50
- StorageAdminStats
51
- } from '../../index.client'
23
+ TableUser
24
+ } from '../schema/tables'
25
+ import {
26
+ AuthId,
27
+ FindCertificateFieldsArgs,
28
+ FindCertificatesArgs,
29
+ FindCommissionsArgs,
30
+ FindForUserSincePagedArgs,
31
+ FindMonitorEventsArgs,
32
+ FindOutputBasketsArgs,
33
+ FindOutputsArgs,
34
+ FindOutputTagMapsArgs,
35
+ FindOutputTagsArgs,
36
+ FindProvenTxReqsArgs,
37
+ FindProvenTxsArgs,
38
+ FindSyncStatesArgs,
39
+ FindTransactionsArgs,
40
+ FindTxLabelMapsArgs,
41
+ FindTxLabelsArgs,
42
+ FindUsersArgs,
43
+ ProvenOrRawTx,
44
+ PurgeParams,
45
+ PurgeResults,
46
+ StorageGetBeefOptions,
47
+ TrxToken,
48
+ } from '../../sdk/WalletStorage.interfaces'
49
+ import {
50
+ ValidListActionsArgs,
51
+ ValidListOutputsArgs
52
+ } from '../../sdk/validationHelpers'
52
53
 
53
54
  describe('getBeefForTransaction tests', () => {
54
55
  jest.setTimeout(99999999)
55
56
 
56
- test('0_', async () => {
57
+ test('0 ProtoStorage.getBeefForTxid', async () => {
57
58
  const ps = new ProtoStorage('main')
58
59
  const beef = await ps.getBeefForTxid('794f836052ad73732a550c38bea3697a722c6a1e54bcbe63735ba79e0d23f623')
59
60
  expect(beef.bumps.length > 0)
@@ -68,7 +69,7 @@ class ProtoStorage extends StorageProvider {
68
69
  gbo: StorageGetBeefOptions
69
70
  whatsOnChainApiKey?: string
70
71
 
71
- constructor(chain: sdk.Chain) {
72
+ constructor(chain: Chain) {
72
73
  const o = StorageProvider.createStorageBaseOptions(chain)
73
74
  super(o)
74
75
  const so = Services.createDefaultOptions(chain)
@@ -80,6 +81,7 @@ class ProtoStorage extends StorageProvider {
80
81
  ignoreServices: false,
81
82
  ignoreStorage: true
82
83
  }
84
+ this.maxRecursionDepth = 2
83
85
  }
84
86
 
85
87
  async getBeefForTxid(txid: string): Promise<Beef> {
@@ -101,7 +101,7 @@ export abstract class Format {
101
101
 
102
102
  static toLogStringAdminStats(s: StorageAdminStats): string {
103
103
  let log = `StorageAdminStats: ${s.when} ${s.requestedBy}\n`
104
- log += ` ${al('', 13)} ${ar('Day', 15)} ${ar('Month', 15)} ${ar('Total', 15)}\n`
104
+ log += ` ${al('', 13)} ${ar('Day', 18)} ${ar('Month', 18)} ${ar('Total', 18)}\n`
105
105
  log += dmt('users', s.usersDay, s.usersMonth, s.usersTotal)
106
106
  log += dmt('change sats', sa(s.satoshisDefaultDay), sa(s.satoshisDefaultMonth), sa(s.satoshisDefaultTotal))
107
107
  log += dmt('other sats', sa(s.satoshisOtherDay), sa(s.satoshisOtherMonth), sa(s.satoshisOtherTotal))
@@ -122,7 +122,7 @@ export abstract class Format {
122
122
  return log
123
123
 
124
124
  function dmt(l: string, d: number | string, m: number | string, t: number | string): string {
125
- return ` ${al(l, 13)} ${ar(d, 15)} ${ar(m, 15)} ${ar(t, 15)}\n`
125
+ return ` ${al(l, 13)} ${ar(d, 18)} ${ar(m, 18)} ${ar(t, 18)}\n`
126
126
  }
127
127
  }
128
128
  }
@@ -151,9 +151,16 @@ export function verifyOne<T>(results: T[], errorDescrition?: string): T {
151
151
 
152
152
  /**
153
153
  * Returns an await'able Promise that resolves in the given number of msecs.
154
+ * @param msecs number of milliseconds to wait before resolving the promise.
155
+ * Must be greater than zero and less than 2 minutes (120,000 msecs)
154
156
  * @publicbody
155
157
  */
156
158
  export function wait(msecs: number): Promise<void> {
159
+ const MIN_WAIT = 0
160
+ const MAX_WAIT = 2 * 60 * 1000 // maximum allowed wait in ms (2 minutes)
161
+ if (typeof msecs !== 'number' || !Number.isFinite(msecs) || isNaN(msecs) || msecs < MIN_WAIT || msecs > MAX_WAIT) {
162
+ throw new WERR_INVALID_PARAMETER('msecs', `a number between ${MIN_WAIT} and ${MAX_WAIT} msecs, not ${msecs}.`)
163
+ }
157
164
  return new Promise(resolve => setTimeout(resolve, msecs))
158
165
  }
159
166