@bopen-io/wallet-toolbox 1.7.18

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 (390) hide show
  1. package/.claude/settings.local.json +10 -0
  2. package/.env.template +22 -0
  3. package/.github/ISSUE_TEMPLATE/bug_report.md +40 -0
  4. package/.github/ISSUE_TEMPLATE/discussion.md +24 -0
  5. package/.github/pull_request_template.md +22 -0
  6. package/.github/workflows/push.yaml +145 -0
  7. package/.prettierrc +10 -0
  8. package/CHANGELOG.md +280 -0
  9. package/CONTRIBUTING.md +89 -0
  10. package/README.md +43 -0
  11. package/docs/README.md +85 -0
  12. package/docs/client.md +19627 -0
  13. package/docs/monitor.md +953 -0
  14. package/docs/open-rpc/index.html +46 -0
  15. package/docs/services.md +6377 -0
  16. package/docs/setup.md +1268 -0
  17. package/docs/storage.md +5367 -0
  18. package/docs/wallet.md +19626 -0
  19. package/jest.config.ts +25 -0
  20. package/license.md +28 -0
  21. package/out/tsconfig.all.tsbuildinfo +1 -0
  22. package/package.json +63 -0
  23. package/src/CWIStyleWalletManager.ts +1999 -0
  24. package/src/Setup.ts +579 -0
  25. package/src/SetupClient.ts +322 -0
  26. package/src/SetupWallet.ts +108 -0
  27. package/src/SimpleWalletManager.ts +526 -0
  28. package/src/Wallet.ts +1169 -0
  29. package/src/WalletAuthenticationManager.ts +153 -0
  30. package/src/WalletLogger.ts +213 -0
  31. package/src/WalletPermissionsManager.ts +3660 -0
  32. package/src/WalletSettingsManager.ts +114 -0
  33. package/src/__tests/CWIStyleWalletManager.test.d.ts.map +1 -0
  34. package/src/__tests/CWIStyleWalletManager.test.js.map +1 -0
  35. package/src/__tests/CWIStyleWalletManager.test.ts +675 -0
  36. package/src/__tests/WalletPermissionsManager.callbacks.test.ts +323 -0
  37. package/src/__tests/WalletPermissionsManager.checks.test.ts +844 -0
  38. package/src/__tests/WalletPermissionsManager.encryption.test.ts +412 -0
  39. package/src/__tests/WalletPermissionsManager.fixtures.ts +307 -0
  40. package/src/__tests/WalletPermissionsManager.flows.test.ts +462 -0
  41. package/src/__tests/WalletPermissionsManager.initialization.test.ts +300 -0
  42. package/src/__tests/WalletPermissionsManager.pmodules.test.ts +798 -0
  43. package/src/__tests/WalletPermissionsManager.proxying.test.ts +724 -0
  44. package/src/__tests/WalletPermissionsManager.tokens.test.ts +503 -0
  45. package/src/index.all.ts +27 -0
  46. package/src/index.client.ts +25 -0
  47. package/src/index.mobile.ts +21 -0
  48. package/src/index.ts +1 -0
  49. package/src/monitor/Monitor.ts +412 -0
  50. package/src/monitor/MonitorDaemon.ts +188 -0
  51. package/src/monitor/README.md +3 -0
  52. package/src/monitor/__test/MonitorDaemon.man.test.ts +45 -0
  53. package/src/monitor/tasks/TaskCheckForProofs.ts +243 -0
  54. package/src/monitor/tasks/TaskCheckNoSends.ts +73 -0
  55. package/src/monitor/tasks/TaskClock.ts +33 -0
  56. package/src/monitor/tasks/TaskFailAbandoned.ts +54 -0
  57. package/src/monitor/tasks/TaskMonitorCallHistory.ts +26 -0
  58. package/src/monitor/tasks/TaskNewHeader.ts +93 -0
  59. package/src/monitor/tasks/TaskPurge.ts +68 -0
  60. package/src/monitor/tasks/TaskReorg.ts +89 -0
  61. package/src/monitor/tasks/TaskReviewStatus.ts +48 -0
  62. package/src/monitor/tasks/TaskSendWaiting.ts +122 -0
  63. package/src/monitor/tasks/TaskSyncWhenIdle.ts +26 -0
  64. package/src/monitor/tasks/TaskUnFail.ts +151 -0
  65. package/src/monitor/tasks/WalletMonitorTask.ts +47 -0
  66. package/src/sdk/CertOpsWallet.ts +18 -0
  67. package/src/sdk/PrivilegedKeyManager.ts +372 -0
  68. package/src/sdk/README.md +13 -0
  69. package/src/sdk/WERR_errors.ts +234 -0
  70. package/src/sdk/WalletError.ts +170 -0
  71. package/src/sdk/WalletErrorFromJson.ts +80 -0
  72. package/src/sdk/WalletServices.interfaces.ts +700 -0
  73. package/src/sdk/WalletSigner.interfaces.ts +11 -0
  74. package/src/sdk/WalletStorage.interfaces.ts +606 -0
  75. package/src/sdk/__test/CertificateLifeCycle.test.ts +131 -0
  76. package/src/sdk/__test/PrivilegedKeyManager.test.ts +738 -0
  77. package/src/sdk/__test/WalletError.test.ts +318 -0
  78. package/src/sdk/__test/validationHelpers.test.ts +21 -0
  79. package/src/sdk/index.ts +10 -0
  80. package/src/sdk/types.ts +226 -0
  81. package/src/services/README.md +11 -0
  82. package/src/services/ServiceCollection.ts +248 -0
  83. package/src/services/Services.ts +603 -0
  84. package/src/services/__tests/ARC.man.test.ts +123 -0
  85. package/src/services/__tests/ARC.timeout.man.test.ts +79 -0
  86. package/src/services/__tests/ArcGorillaPool.man.test.ts +108 -0
  87. package/src/services/__tests/arcServices.test.ts +8 -0
  88. package/src/services/__tests/bitrails.test.ts +56 -0
  89. package/src/services/__tests/getMerklePath.test.ts +15 -0
  90. package/src/services/__tests/getRawTx.test.ts +13 -0
  91. package/src/services/__tests/postBeef.test.ts +104 -0
  92. package/src/services/__tests/verifyBeef.test.ts +50 -0
  93. package/src/services/chaintracker/BHServiceClient.ts +212 -0
  94. package/src/services/chaintracker/ChaintracksChainTracker.ts +71 -0
  95. package/src/services/chaintracker/__tests/ChaintracksChainTracker.test.ts +33 -0
  96. package/src/services/chaintracker/__tests/ChaintracksServiceClient.test.ts +29 -0
  97. package/src/services/chaintracker/chaintracks/Api/BlockHeaderApi.ts +72 -0
  98. package/src/services/chaintracker/chaintracks/Api/BulkIngestorApi.ts +83 -0
  99. package/src/services/chaintracker/chaintracks/Api/BulkStorageApi.ts +92 -0
  100. package/src/services/chaintracker/chaintracks/Api/ChaintracksApi.ts +64 -0
  101. package/src/services/chaintracker/chaintracks/Api/ChaintracksClientApi.ts +189 -0
  102. package/src/services/chaintracker/chaintracks/Api/ChaintracksFetchApi.ts +18 -0
  103. package/src/services/chaintracker/chaintracks/Api/ChaintracksFsApi.ts +58 -0
  104. package/src/services/chaintracker/chaintracks/Api/ChaintracksStorageApi.ts +386 -0
  105. package/src/services/chaintracker/chaintracks/Api/LiveIngestorApi.ts +25 -0
  106. package/src/services/chaintracker/chaintracks/Chaintracks.ts +609 -0
  107. package/src/services/chaintracker/chaintracks/ChaintracksService.ts +199 -0
  108. package/src/services/chaintracker/chaintracks/ChaintracksServiceClient.ts +154 -0
  109. package/src/services/chaintracker/chaintracks/Ingest/BulkIngestorBase.ts +176 -0
  110. package/src/services/chaintracker/chaintracks/Ingest/BulkIngestorCDN.ts +174 -0
  111. package/src/services/chaintracker/chaintracks/Ingest/BulkIngestorCDNBabbage.ts +18 -0
  112. package/src/services/chaintracker/chaintracks/Ingest/BulkIngestorWhatsOnChainCdn.ts +113 -0
  113. package/src/services/chaintracker/chaintracks/Ingest/BulkIngestorWhatsOnChainWs.ts +81 -0
  114. package/src/services/chaintracker/chaintracks/Ingest/LiveIngestorBase.ts +86 -0
  115. package/src/services/chaintracker/chaintracks/Ingest/LiveIngestorTeranodeP2P.ts +59 -0
  116. package/src/services/chaintracker/chaintracks/Ingest/LiveIngestorWhatsOnChainPoll.ts +104 -0
  117. package/src/services/chaintracker/chaintracks/Ingest/LiveIngestorWhatsOnChainWs.ts +66 -0
  118. package/src/services/chaintracker/chaintracks/Ingest/WhatsOnChainIngestorWs.ts +566 -0
  119. package/src/services/chaintracker/chaintracks/Ingest/WhatsOnChainServices.ts +219 -0
  120. package/src/services/chaintracker/chaintracks/Ingest/__tests/BulkIngestorCDNBabbage.test.ts +54 -0
  121. package/src/services/chaintracker/chaintracks/Ingest/__tests/LiveIngestorWhatsOnChainPoll.test.ts +33 -0
  122. package/src/services/chaintracker/chaintracks/Ingest/__tests/WhatsOnChainServices.test.ts +124 -0
  123. package/src/services/chaintracker/chaintracks/Storage/BulkStorageBase.ts +92 -0
  124. package/src/services/chaintracker/chaintracks/Storage/ChaintracksKnexMigrations.ts +104 -0
  125. package/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageBase.ts +382 -0
  126. package/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageIdb.ts +574 -0
  127. package/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageKnex.ts +438 -0
  128. package/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageMemory.ts +29 -0
  129. package/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageNoDb.ts +304 -0
  130. package/src/services/chaintracker/chaintracks/Storage/__tests/ChaintracksStorageIdb.test.ts +102 -0
  131. package/src/services/chaintracker/chaintracks/Storage/__tests/ChaintracksStorageKnex.test.ts +45 -0
  132. package/src/services/chaintracker/chaintracks/__tests/Chaintracks.test.ts +77 -0
  133. package/src/services/chaintracker/chaintracks/__tests/ChaintracksClientApi.test.ts +192 -0
  134. package/src/services/chaintracker/chaintracks/__tests/LocalCdnServer.ts +75 -0
  135. package/src/services/chaintracker/chaintracks/__tests/createIdbChaintracks.test.ts +62 -0
  136. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest349/mainNetBlockHeaders.json +1 -0
  137. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest349/mainNet_0.headers +0 -0
  138. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest349/mainNet_1.headers +0 -0
  139. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest349/mainNet_2.headers +0 -0
  140. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest349/mainNet_3.headers +0 -0
  141. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest379/mainNetBlockHeaders.json +1 -0
  142. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest379/mainNet_0.headers +0 -0
  143. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest379/mainNet_1.headers +0 -0
  144. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest379/mainNet_2.headers +0 -0
  145. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest379/mainNet_3.headers +0 -0
  146. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest399/mainNetBlockHeaders.json +1 -0
  147. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest399/mainNet_0.headers +0 -0
  148. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest399/mainNet_1.headers +0 -0
  149. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest399/mainNet_2.headers +0 -0
  150. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest399/mainNet_3.headers +0 -0
  151. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest402/mainNetBlockHeaders.json +1 -0
  152. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest402/mainNet_0.headers +0 -0
  153. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest402/mainNet_1.headers +0 -0
  154. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest402/mainNet_2.headers +0 -0
  155. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest402/mainNet_3.headers +0 -0
  156. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest402/mainNet_4.headers +0 -0
  157. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest499/mainNetBlockHeaders.json +1 -0
  158. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest499/mainNet_0.headers +0 -0
  159. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest499/mainNet_1.headers +0 -0
  160. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest499/mainNet_2.headers +0 -0
  161. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest499/mainNet_3.headers +0 -0
  162. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest499/mainNet_4.headers +0 -0
  163. package/src/services/chaintracker/chaintracks/createDefaultIdbChaintracksOptions.ts +92 -0
  164. package/src/services/chaintracker/chaintracks/createDefaultKnexChaintracksOptions.ts +111 -0
  165. package/src/services/chaintracker/chaintracks/createDefaultNoDbChaintracksOptions.ts +91 -0
  166. package/src/services/chaintracker/chaintracks/createIdbChaintracks.ts +60 -0
  167. package/src/services/chaintracker/chaintracks/createKnexChaintracks.ts +65 -0
  168. package/src/services/chaintracker/chaintracks/createNoDbChaintracks.ts +60 -0
  169. package/src/services/chaintracker/chaintracks/index.all.ts +12 -0
  170. package/src/services/chaintracker/chaintracks/index.client.ts +4 -0
  171. package/src/services/chaintracker/chaintracks/index.mobile.ts +37 -0
  172. package/src/services/chaintracker/chaintracks/util/BulkFileDataManager.ts +975 -0
  173. package/src/services/chaintracker/chaintracks/util/BulkFileDataReader.ts +60 -0
  174. package/src/services/chaintracker/chaintracks/util/BulkFilesReader.ts +336 -0
  175. package/src/services/chaintracker/chaintracks/util/BulkHeaderFile.ts +247 -0
  176. package/src/services/chaintracker/chaintracks/util/ChaintracksFetch.ts +69 -0
  177. package/src/services/chaintracker/chaintracks/util/ChaintracksFs.ts +141 -0
  178. package/src/services/chaintracker/chaintracks/util/HeightRange.ts +153 -0
  179. package/src/services/chaintracker/chaintracks/util/SingleWriterMultiReaderLock.ts +76 -0
  180. package/src/services/chaintracker/chaintracks/util/__tests/BulkFileDataManager.test.ts +304 -0
  181. package/src/services/chaintracker/chaintracks/util/__tests/ChaintracksFetch.test.ts +60 -0
  182. package/src/services/chaintracker/chaintracks/util/__tests/HeightRange.test.ts +67 -0
  183. package/src/services/chaintracker/chaintracks/util/__tests/SingleWriterMultiReaderLock.test.ts +49 -0
  184. package/src/services/chaintracker/chaintracks/util/blockHeaderUtilities.ts +573 -0
  185. package/src/services/chaintracker/chaintracks/util/dirtyHashes.ts +29 -0
  186. package/src/services/chaintracker/chaintracks/util/validBulkHeaderFilesByFileHash.ts +432 -0
  187. package/src/services/chaintracker/index.all.ts +4 -0
  188. package/src/services/chaintracker/index.client.ts +4 -0
  189. package/src/services/chaintracker/index.mobile.ts +4 -0
  190. package/src/services/createDefaultWalletServicesOptions.ts +77 -0
  191. package/src/services/index.ts +1 -0
  192. package/src/services/processingErrors/arcSuccessError.json +76 -0
  193. package/src/services/providers/ARC.ts +350 -0
  194. package/src/services/providers/Bitails.ts +256 -0
  195. package/src/services/providers/SdkWhatsOnChain.ts +83 -0
  196. package/src/services/providers/WhatsOnChain.ts +883 -0
  197. package/src/services/providers/__tests/WhatsOnChain.test.ts +242 -0
  198. package/src/services/providers/__tests/exchangeRates.test.ts +18 -0
  199. package/src/services/providers/exchangeRates.ts +265 -0
  200. package/src/services/providers/getBeefForTxid.ts +369 -0
  201. package/src/signer/README.md +5 -0
  202. package/src/signer/WalletSigner.ts +17 -0
  203. package/src/signer/methods/acquireDirectCertificate.ts +52 -0
  204. package/src/signer/methods/buildSignableTransaction.ts +183 -0
  205. package/src/signer/methods/completeSignedTransaction.ts +117 -0
  206. package/src/signer/methods/createAction.ts +172 -0
  207. package/src/signer/methods/internalizeAction.ts +106 -0
  208. package/src/signer/methods/proveCertificate.ts +43 -0
  209. package/src/signer/methods/signAction.ts +54 -0
  210. package/src/storage/README.md +14 -0
  211. package/src/storage/StorageIdb.ts +2304 -0
  212. package/src/storage/StorageKnex.ts +1425 -0
  213. package/src/storage/StorageProvider.ts +810 -0
  214. package/src/storage/StorageReader.ts +194 -0
  215. package/src/storage/StorageReaderWriter.ts +432 -0
  216. package/src/storage/StorageSyncReader.ts +34 -0
  217. package/src/storage/WalletStorageManager.ts +943 -0
  218. package/src/storage/__test/StorageIdb.test.ts +43 -0
  219. package/src/storage/__test/WalletStorageManager.test.ts +275 -0
  220. package/src/storage/__test/adminStats.man.test.ts +89 -0
  221. package/src/storage/__test/getBeefForTransaction.test.ts +385 -0
  222. package/src/storage/index.all.ts +11 -0
  223. package/src/storage/index.client.ts +7 -0
  224. package/src/storage/index.mobile.ts +6 -0
  225. package/src/storage/methods/ListActionsSpecOp.ts +70 -0
  226. package/src/storage/methods/ListOutputsSpecOp.ts +129 -0
  227. package/src/storage/methods/__test/GenerateChange/generateChangeSdk.test.ts +1057 -0
  228. package/src/storage/methods/__test/GenerateChange/randomValsUsed1.ts +20 -0
  229. package/src/storage/methods/__test/offsetKey.test.ts +274 -0
  230. package/src/storage/methods/attemptToPostReqsToNetwork.ts +389 -0
  231. package/src/storage/methods/createAction.ts +947 -0
  232. package/src/storage/methods/generateChange.ts +556 -0
  233. package/src/storage/methods/getBeefForTransaction.ts +139 -0
  234. package/src/storage/methods/getSyncChunk.ts +293 -0
  235. package/src/storage/methods/internalizeAction.ts +562 -0
  236. package/src/storage/methods/listActionsIdb.ts +183 -0
  237. package/src/storage/methods/listActionsKnex.ts +226 -0
  238. package/src/storage/methods/listCertificates.ts +73 -0
  239. package/src/storage/methods/listOutputsIdb.ts +203 -0
  240. package/src/storage/methods/listOutputsKnex.ts +263 -0
  241. package/src/storage/methods/offsetKey.ts +89 -0
  242. package/src/storage/methods/processAction.ts +420 -0
  243. package/src/storage/methods/purgeData.ts +251 -0
  244. package/src/storage/methods/purgeDataIdb.ts +10 -0
  245. package/src/storage/methods/reviewStatus.ts +101 -0
  246. package/src/storage/methods/reviewStatusIdb.ts +43 -0
  247. package/src/storage/methods/utils.Buffer.ts +33 -0
  248. package/src/storage/methods/utils.ts +56 -0
  249. package/src/storage/remoting/StorageClient.ts +567 -0
  250. package/src/storage/remoting/StorageMobile.ts +544 -0
  251. package/src/storage/remoting/StorageServer.ts +291 -0
  252. package/src/storage/remoting/__test/StorageClient.test.ts +113 -0
  253. package/src/storage/schema/KnexMigrations.ts +489 -0
  254. package/src/storage/schema/StorageIdbSchema.ts +150 -0
  255. package/src/storage/schema/entities/EntityBase.ts +210 -0
  256. package/src/storage/schema/entities/EntityCertificate.ts +188 -0
  257. package/src/storage/schema/entities/EntityCertificateField.ts +136 -0
  258. package/src/storage/schema/entities/EntityCommission.ts +148 -0
  259. package/src/storage/schema/entities/EntityOutput.ts +290 -0
  260. package/src/storage/schema/entities/EntityOutputBasket.ts +153 -0
  261. package/src/storage/schema/entities/EntityOutputTag.ts +121 -0
  262. package/src/storage/schema/entities/EntityOutputTagMap.ts +123 -0
  263. package/src/storage/schema/entities/EntityProvenTx.ts +319 -0
  264. package/src/storage/schema/entities/EntityProvenTxReq.ts +580 -0
  265. package/src/storage/schema/entities/EntitySyncState.ts +389 -0
  266. package/src/storage/schema/entities/EntityTransaction.ts +306 -0
  267. package/src/storage/schema/entities/EntityTxLabel.ts +121 -0
  268. package/src/storage/schema/entities/EntityTxLabelMap.ts +123 -0
  269. package/src/storage/schema/entities/EntityUser.ts +112 -0
  270. package/src/storage/schema/entities/MergeEntity.ts +73 -0
  271. package/src/storage/schema/entities/__tests/CertificateFieldTests.test.ts +353 -0
  272. package/src/storage/schema/entities/__tests/CertificateTests.test.ts +354 -0
  273. package/src/storage/schema/entities/__tests/CommissionTests.test.ts +371 -0
  274. package/src/storage/schema/entities/__tests/OutputBasketTests.test.ts +278 -0
  275. package/src/storage/schema/entities/__tests/OutputTagMapTests.test.ts +242 -0
  276. package/src/storage/schema/entities/__tests/OutputTagTests.test.ts +288 -0
  277. package/src/storage/schema/entities/__tests/OutputTests.test.ts +464 -0
  278. package/src/storage/schema/entities/__tests/ProvenTxReqTests.test.ts +340 -0
  279. package/src/storage/schema/entities/__tests/ProvenTxTests.test.ts +504 -0
  280. package/src/storage/schema/entities/__tests/SyncStateTests.test.ts +288 -0
  281. package/src/storage/schema/entities/__tests/TransactionTests.test.ts +604 -0
  282. package/src/storage/schema/entities/__tests/TxLabelMapTests.test.ts +361 -0
  283. package/src/storage/schema/entities/__tests/TxLabelTests.test.ts +198 -0
  284. package/src/storage/schema/entities/__tests/stampLogTests.test.ts +90 -0
  285. package/src/storage/schema/entities/__tests/usersTests.test.ts +340 -0
  286. package/src/storage/schema/entities/index.ts +16 -0
  287. package/src/storage/schema/tables/TableCertificate.ts +21 -0
  288. package/src/storage/schema/tables/TableCertificateField.ts +12 -0
  289. package/src/storage/schema/tables/TableCommission.ts +13 -0
  290. package/src/storage/schema/tables/TableMonitorEvent.ts +9 -0
  291. package/src/storage/schema/tables/TableOutput.ts +64 -0
  292. package/src/storage/schema/tables/TableOutputBasket.ts +12 -0
  293. package/src/storage/schema/tables/TableOutputTag.ts +10 -0
  294. package/src/storage/schema/tables/TableOutputTagMap.ts +9 -0
  295. package/src/storage/schema/tables/TableProvenTx.ts +14 -0
  296. package/src/storage/schema/tables/TableProvenTxReq.ts +65 -0
  297. package/src/storage/schema/tables/TableSettings.ts +17 -0
  298. package/src/storage/schema/tables/TableSyncState.ts +18 -0
  299. package/src/storage/schema/tables/TableTransaction.ts +54 -0
  300. package/src/storage/schema/tables/TableTxLabel.ts +10 -0
  301. package/src/storage/schema/tables/TableTxLabelMap.ts +9 -0
  302. package/src/storage/schema/tables/TableUser.ts +16 -0
  303. package/src/storage/schema/tables/index.ts +16 -0
  304. package/src/storage/sync/StorageMySQLDojoReader.ts +696 -0
  305. package/src/storage/sync/index.ts +1 -0
  306. package/src/utility/Format.ts +133 -0
  307. package/src/utility/README.md +3 -0
  308. package/src/utility/ReaderUint8Array.ts +187 -0
  309. package/src/utility/ScriptTemplateBRC29.ts +73 -0
  310. package/src/utility/__tests/utilityHelpers.noBuffer.test.ts +109 -0
  311. package/src/utility/aggregateResults.ts +68 -0
  312. package/src/utility/identityUtils.ts +159 -0
  313. package/src/utility/index.all.ts +7 -0
  314. package/src/utility/index.client.ts +7 -0
  315. package/src/utility/parseTxScriptOffsets.ts +29 -0
  316. package/src/utility/stampLog.ts +69 -0
  317. package/src/utility/tscProofToMerklePath.ts +48 -0
  318. package/src/utility/utilityHelpers.buffer.ts +34 -0
  319. package/src/utility/utilityHelpers.noBuffer.ts +60 -0
  320. package/src/utility/utilityHelpers.ts +275 -0
  321. package/src/wab-client/WABClient.ts +94 -0
  322. package/src/wab-client/__tests/WABClient.man.test.ts +59 -0
  323. package/src/wab-client/auth-method-interactors/AuthMethodInteractor.ts +47 -0
  324. package/src/wab-client/auth-method-interactors/DevConsoleInteractor.ts +73 -0
  325. package/src/wab-client/auth-method-interactors/PersonaIDInteractor.ts +35 -0
  326. package/src/wab-client/auth-method-interactors/TwilioPhoneInteractor.ts +72 -0
  327. package/syncVersions.js +71 -0
  328. package/test/Wallet/StorageClient/storageClient.man.test.ts +75 -0
  329. package/test/Wallet/action/abortAction.test.ts +47 -0
  330. package/test/Wallet/action/createAction.test.ts +299 -0
  331. package/test/Wallet/action/createAction2.test.ts +1273 -0
  332. package/test/Wallet/action/createActionToGenerateBeefs.man.test.ts +293 -0
  333. package/test/Wallet/action/internalizeAction.a.test.ts +286 -0
  334. package/test/Wallet/action/internalizeAction.test.ts +682 -0
  335. package/test/Wallet/action/relinquishOutput.test.ts +37 -0
  336. package/test/Wallet/certificate/acquireCertificate.test.ts +298 -0
  337. package/test/Wallet/certificate/listCertificates.test.ts +346 -0
  338. package/test/Wallet/construct/Wallet.constructor.test.ts +57 -0
  339. package/test/Wallet/get/getHeaderForHeight.test.ts +82 -0
  340. package/test/Wallet/get/getHeight.test.ts +52 -0
  341. package/test/Wallet/get/getKnownTxids.test.ts +86 -0
  342. package/test/Wallet/get/getNetwork.test.ts +27 -0
  343. package/test/Wallet/get/getVersion.test.ts +27 -0
  344. package/test/Wallet/list/listActions.test.ts +279 -0
  345. package/test/Wallet/list/listActions2.test.ts +1381 -0
  346. package/test/Wallet/list/listCertificates.test.ts +118 -0
  347. package/test/Wallet/list/listOutputs.test.ts +447 -0
  348. package/test/Wallet/live/walletLive.man.test.ts +521 -0
  349. package/test/Wallet/local/localWallet.man.test.ts +93 -0
  350. package/test/Wallet/local/localWallet2.man.test.ts +277 -0
  351. package/test/Wallet/signAction/mountaintop.man.test.ts +130 -0
  352. package/test/Wallet/specOps/specOps.man.test.ts +220 -0
  353. package/test/Wallet/support/janitor.man.test.ts +40 -0
  354. package/test/Wallet/support/operations.man.test.ts +407 -0
  355. package/test/Wallet/support/reqErrorReview.2025.05.06.man.test.ts +347 -0
  356. package/test/Wallet/sync/Wallet.sync.test.ts +215 -0
  357. package/test/Wallet/sync/Wallet.updateWalletLegacyTestData.man.test.ts +203 -0
  358. package/test/Wallet/sync/setActive.test.ts +170 -0
  359. package/test/WalletClient/LocalKVStore.man.test.ts +114 -0
  360. package/test/WalletClient/WERR.man.test.ts +35 -0
  361. package/test/bsv-ts-sdk/LocalKVStore.test.ts +102 -0
  362. package/test/checkDB.ts +57 -0
  363. package/test/checkdb +0 -0
  364. package/test/examples/backup.man.test.ts +59 -0
  365. package/test/examples/pushdrop.test.ts +282 -0
  366. package/test/monitor/Monitor.test.ts +620 -0
  367. package/test/services/Services.test.ts +263 -0
  368. package/test/storage/KnexMigrations.test.ts +86 -0
  369. package/test/storage/StorageMySQLDojoReader.man.test.ts +60 -0
  370. package/test/storage/count.test.ts +177 -0
  371. package/test/storage/find.test.ts +195 -0
  372. package/test/storage/findLegacy.test.ts +67 -0
  373. package/test/storage/idb/allocateChange.test.ts +251 -0
  374. package/test/storage/idb/count.test.ts +158 -0
  375. package/test/storage/idb/find.test.ts +177 -0
  376. package/test/storage/idb/idbSpeed.test.ts +36 -0
  377. package/test/storage/idb/insert.test.ts +268 -0
  378. package/test/storage/idb/transactionAbort.test.ts +108 -0
  379. package/test/storage/idb/update.test.ts +999 -0
  380. package/test/storage/insert.test.ts +278 -0
  381. package/test/storage/update.test.ts +1021 -0
  382. package/test/storage/update2.test.ts +897 -0
  383. package/test/utils/TestUtilsWalletStorage.ts +2526 -0
  384. package/test/utils/localWalletMethods.ts +363 -0
  385. package/test/utils/removeFailedFromDatabase.sql +17 -0
  386. package/ts2md.json +44 -0
  387. package/tsconfig.all.json +31 -0
  388. package/tsconfig.client.json +29 -0
  389. package/tsconfig.json +17 -0
  390. package/tsconfig.mobile.json +28 -0
package/src/Wallet.ts ADDED
@@ -0,0 +1,1169 @@
1
+ import {
2
+ AbortActionArgs,
3
+ AbortActionResult,
4
+ AcquireCertificateArgs,
5
+ AcquireCertificateResult,
6
+ AuthenticatedResult,
7
+ Beef,
8
+ BeefParty,
9
+ CreateActionArgs,
10
+ CreateActionResult,
11
+ CreateHmacArgs,
12
+ CreateHmacResult,
13
+ CreateSignatureArgs,
14
+ CreateSignatureResult,
15
+ DiscoverByAttributesArgs,
16
+ DiscoverByIdentityKeyArgs,
17
+ DiscoverCertificatesResult,
18
+ GetHeaderArgs,
19
+ GetHeaderResult,
20
+ GetHeightResult,
21
+ GetNetworkResult,
22
+ GetPublicKeyArgs,
23
+ GetPublicKeyResult,
24
+ GetVersionResult,
25
+ InternalizeActionArgs,
26
+ InternalizeActionResult,
27
+ ListActionsArgs,
28
+ ListActionsResult,
29
+ ListCertificatesArgs,
30
+ ListCertificatesResult,
31
+ ListOutputsArgs,
32
+ ListOutputsResult,
33
+ OriginatorDomainNameStringUnder250Bytes,
34
+ ProtoWallet,
35
+ ProveCertificateArgs,
36
+ ProveCertificateResult,
37
+ PubKeyHex,
38
+ RelinquishCertificateArgs,
39
+ RelinquishCertificateResult,
40
+ RelinquishOutputArgs,
41
+ RelinquishOutputResult,
42
+ RevealCounterpartyKeyLinkageArgs,
43
+ RevealCounterpartyKeyLinkageResult,
44
+ RevealSpecificKeyLinkageArgs,
45
+ RevealSpecificKeyLinkageResult,
46
+ SignActionArgs,
47
+ SignActionResult,
48
+ Transaction as BsvTransaction,
49
+ TrustSelf,
50
+ Utils,
51
+ VerifyHmacArgs,
52
+ VerifyHmacResult,
53
+ VerifySignatureArgs,
54
+ VerifySignatureResult,
55
+ WalletDecryptArgs,
56
+ WalletDecryptResult,
57
+ WalletEncryptArgs,
58
+ WalletEncryptResult,
59
+ WalletInterface,
60
+ createNonce,
61
+ AuthFetch,
62
+ verifyNonce,
63
+ MasterCertificate,
64
+ Certificate,
65
+ LookupResolver,
66
+ AtomicBEEF,
67
+ BEEF,
68
+ KeyDeriverApi,
69
+ Validation,
70
+ WalletLoggerInterface,
71
+ MakeWalletLogger
72
+ } from '@bsv/sdk'
73
+ import { acquireDirectCertificate } from './signer/methods/acquireDirectCertificate'
74
+ import { proveCertificate } from './signer/methods/proveCertificate'
75
+ import { createAction, CreateActionResultX } from './signer/methods/createAction'
76
+ import { signAction, SignActionResultX } from './signer/methods/signAction'
77
+ import { internalizeAction } from './signer/methods/internalizeAction'
78
+ import { WalletSettingsManager } from './WalletSettingsManager'
79
+ import { queryOverlay, transformVerifiableCertificatesWithTrust } from './utility/identityUtils'
80
+ import { maxPossibleSatoshis } from './storage/methods/generateChange'
81
+ import { WalletStorageManager } from './storage/WalletStorageManager'
82
+ import { Monitor } from './monitor/Monitor'
83
+ import { WalletSigner } from './signer/WalletSigner'
84
+ import { randomBytesBase64, toWalletNetwork } from './utility/utilityHelpers'
85
+ import { ScriptTemplateBRC29 } from './utility/ScriptTemplateBRC29'
86
+ import {
87
+ Chain,
88
+ KeyPair,
89
+ specOpFailedActions,
90
+ specOpInvalidChange,
91
+ specOpNoSendActions,
92
+ specOpSetWalletChangeParams,
93
+ specOpThrowReviewActions,
94
+ specOpWalletBalance,
95
+ StorageIdentity,
96
+ WalletBalance
97
+ } from './sdk/types'
98
+ import { WalletServices } from './sdk/WalletServices.interfaces'
99
+ import { PrivilegedKeyManager } from './sdk/PrivilegedKeyManager'
100
+ import { WERR_INTERNAL, WERR_INVALID_PARAMETER, WERR_REVIEW_ACTIONS } from './sdk/WERR_errors'
101
+ import { AuthId, StorageCreateActionResult, StorageInternalizeActionResult } from './sdk/WalletStorage.interfaces'
102
+ import { WalletError } from './sdk/WalletError'
103
+
104
+ /**
105
+ * The preferred means of constructing a `Wallet` is with a `WalletArgs` instance.
106
+ */
107
+ export interface WalletArgs {
108
+ chain: Chain
109
+ keyDeriver: KeyDeriverApi
110
+ storage: WalletStorageManager
111
+ services?: WalletServices
112
+ monitor?: Monitor
113
+ privilegedKeyManager?: PrivilegedKeyManager
114
+ settingsManager?: WalletSettingsManager
115
+ lookupResolver?: LookupResolver
116
+ /**
117
+ * Optional. Provide a function conforming to the `MakeWalletLogger` type to enable wallet request logging.
118
+ *
119
+ * For simple requests using `Console` may be adequate, initialize with
120
+ * `() => Console`
121
+ *
122
+ * Aggregate tracing and control over capturing all logged output in one place:
123
+ * `(log?: string | WalletLoggerInterface) => new WalletLogger(log)`
124
+ */
125
+ makeLogger?: MakeWalletLogger
126
+ }
127
+
128
+ function isWalletSigner(args: WalletArgs | WalletSigner): args is WalletSigner {
129
+ return args['isWalletSigner']
130
+ }
131
+
132
+ export class Wallet implements WalletInterface, ProtoWallet {
133
+ chain: Chain
134
+ keyDeriver: KeyDeriverApi
135
+ storage: WalletStorageManager
136
+ settingsManager: WalletSettingsManager
137
+ lookupResolver: LookupResolver
138
+
139
+ services?: WalletServices
140
+ monitor?: Monitor
141
+
142
+ identityKey: string
143
+
144
+ /**
145
+ * The wallet creates a `BeefParty` when it is created.
146
+ * All the Beefs that pass through the wallet are merged into this beef.
147
+ * Thus what it contains at any time is the union of all transactions and proof data processed.
148
+ * The class `BeefParty` derives from `Beef`, adding the ability to track the source of merged data.
149
+ *
150
+ * This allows it to generate beefs to send to a particular “party” (storage or the user)
151
+ * that includes “txid only proofs” for transactions they already know about.
152
+ * Over time, this allows an active wallet to drastically reduce the amount of data transmitted.
153
+ */
154
+ beef: BeefParty
155
+ /**
156
+ * If true, signableTransactions will include sourceTransaction for each input,
157
+ * including those that do not require signature and those that were also contained
158
+ * in the inputBEEF.
159
+ */
160
+ includeAllSourceTransactions: boolean = true
161
+ /**
162
+ * If true, txids that are known to the wallet's party beef do not need to be returned from storage.
163
+ */
164
+ autoKnownTxids: boolean = false
165
+ /**
166
+ * If true, beefs returned to the user may contain txidOnly transactions.
167
+ */
168
+ returnTxidOnly: boolean = false
169
+ trustSelf?: TrustSelf
170
+ userParty: string
171
+ proto: ProtoWallet
172
+ privilegedKeyManager?: PrivilegedKeyManager
173
+ makeLogger?: MakeWalletLogger
174
+
175
+ pendingSignActions: Record<string, PendingSignAction>
176
+
177
+ /**
178
+ * For repeatability testing, set to an array of random numbers from [0..1).
179
+ */
180
+ randomVals?: number[] = undefined
181
+
182
+ constructor(
183
+ argsOrSigner: WalletArgs | WalletSigner,
184
+ services?: WalletServices,
185
+ monitor?: Monitor,
186
+ privilegedKeyManager?: PrivilegedKeyManager,
187
+ makeLogger?: MakeWalletLogger
188
+ ) {
189
+ const args: WalletArgs = !isWalletSigner(argsOrSigner)
190
+ ? argsOrSigner
191
+ : {
192
+ chain: argsOrSigner.chain,
193
+ keyDeriver: argsOrSigner.keyDeriver,
194
+ storage: argsOrSigner.storage,
195
+ services,
196
+ monitor,
197
+ privilegedKeyManager,
198
+ makeLogger
199
+ }
200
+
201
+ if (args.storage._authId.identityKey != args.keyDeriver.identityKey)
202
+ throw new WERR_INVALID_PARAMETER(
203
+ 'storage',
204
+ `authenticated as the same identityKey (${args.storage._authId.identityKey}) as the keyDeriver (${args.keyDeriver.identityKey}).`
205
+ )
206
+
207
+ this.settingsManager = args.settingsManager || new WalletSettingsManager(this)
208
+ this.chain = args.chain
209
+ this.lookupResolver =
210
+ args.lookupResolver ||
211
+ new LookupResolver({
212
+ networkPreset: toWalletNetwork(this.chain)
213
+ })
214
+ this.keyDeriver = args.keyDeriver
215
+ this.storage = args.storage
216
+ this.proto = new ProtoWallet(args.keyDeriver)
217
+ this.services = args.services
218
+ this.monitor = args.monitor
219
+ this.privilegedKeyManager = args.privilegedKeyManager
220
+ this.makeLogger = args.makeLogger
221
+
222
+ this.identityKey = this.keyDeriver.identityKey
223
+
224
+ this.pendingSignActions = {}
225
+
226
+ this.userParty = `user ${this.getClientChangeKeyPair().publicKey}`
227
+ this.beef = new BeefParty([this.userParty])
228
+ this.trustSelf = 'known'
229
+
230
+ if (this.services) {
231
+ this.storage.setServices(this.services)
232
+ }
233
+ }
234
+
235
+ async destroy(): Promise<void> {
236
+ await this.storage.destroy()
237
+ if (this.privilegedKeyManager) await this.privilegedKeyManager.destroyKey()
238
+ }
239
+
240
+ getClientChangeKeyPair(): KeyPair {
241
+ const kp: KeyPair = {
242
+ privateKey: this.keyDeriver.rootKey.toString(),
243
+ publicKey: this.keyDeriver.rootKey.toPublicKey().toString()
244
+ }
245
+ return kp
246
+ }
247
+
248
+ async getIdentityKey(): Promise<PubKeyHex> {
249
+ return (await this.getPublicKey({ identityKey: true })).publicKey
250
+ }
251
+
252
+ getPublicKey(
253
+ args: GetPublicKeyArgs,
254
+ originator?: OriginatorDomainNameStringUnder250Bytes
255
+ ): Promise<GetPublicKeyResult> {
256
+ if (args.privileged) {
257
+ if (!this.privilegedKeyManager) {
258
+ throw new Error('Privileged operations require the Wallet to be configured with a privileged key manager.')
259
+ }
260
+ return this.privilegedKeyManager.getPublicKey(args)
261
+ }
262
+ return this.proto.getPublicKey(args)
263
+ }
264
+ revealCounterpartyKeyLinkage(
265
+ args: RevealCounterpartyKeyLinkageArgs,
266
+ originator?: OriginatorDomainNameStringUnder250Bytes
267
+ ): Promise<RevealCounterpartyKeyLinkageResult> {
268
+ if (args.privileged) {
269
+ if (!this.privilegedKeyManager) {
270
+ throw new Error('Privileged operations require the Wallet to be configured with a privileged key manager.')
271
+ }
272
+ return this.privilegedKeyManager.revealCounterpartyKeyLinkage(args)
273
+ }
274
+ return this.proto.revealCounterpartyKeyLinkage(args)
275
+ }
276
+ revealSpecificKeyLinkage(
277
+ args: RevealSpecificKeyLinkageArgs,
278
+ originator?: OriginatorDomainNameStringUnder250Bytes
279
+ ): Promise<RevealSpecificKeyLinkageResult> {
280
+ if (args.privileged) {
281
+ if (!this.privilegedKeyManager) {
282
+ throw new Error('Privileged operations require the Wallet to be configured with a privileged key manager.')
283
+ }
284
+ return this.privilegedKeyManager.revealSpecificKeyLinkage(args)
285
+ }
286
+ return this.proto.revealSpecificKeyLinkage(args)
287
+ }
288
+ encrypt(args: WalletEncryptArgs, originator?: OriginatorDomainNameStringUnder250Bytes): Promise<WalletEncryptResult> {
289
+ if (args.privileged) {
290
+ if (!this.privilegedKeyManager) {
291
+ throw new Error('Privileged operations require the Wallet to be configured with a privileged key manager.')
292
+ }
293
+ return this.privilegedKeyManager.encrypt(args)
294
+ }
295
+ return this.proto.encrypt(args)
296
+ }
297
+ decrypt(args: WalletDecryptArgs, originator?: OriginatorDomainNameStringUnder250Bytes): Promise<WalletDecryptResult> {
298
+ if (args.privileged) {
299
+ if (!this.privilegedKeyManager) {
300
+ throw new Error('Privileged operations require the Wallet to be configured with a privileged key manager.')
301
+ }
302
+ return this.privilegedKeyManager.decrypt(args)
303
+ }
304
+ return this.proto.decrypt(args)
305
+ }
306
+ createHmac(args: CreateHmacArgs, originator?: OriginatorDomainNameStringUnder250Bytes): Promise<CreateHmacResult> {
307
+ if (args.privileged) {
308
+ if (!this.privilegedKeyManager) {
309
+ throw new Error('Privileged operations require the Wallet to be configured with a privileged key manager.')
310
+ }
311
+ return this.privilegedKeyManager.createHmac(args)
312
+ }
313
+ return this.proto.createHmac(args)
314
+ }
315
+ verifyHmac(args: VerifyHmacArgs, originator?: OriginatorDomainNameStringUnder250Bytes): Promise<VerifyHmacResult> {
316
+ if (args.privileged) {
317
+ if (!this.privilegedKeyManager) {
318
+ throw new Error('Privileged operations require the Wallet to be configured with a privileged key manager.')
319
+ }
320
+ return this.privilegedKeyManager.verifyHmac(args)
321
+ }
322
+ return this.proto.verifyHmac(args)
323
+ }
324
+ createSignature(
325
+ args: CreateSignatureArgs,
326
+ originator?: OriginatorDomainNameStringUnder250Bytes
327
+ ): Promise<CreateSignatureResult> {
328
+ if (args.privileged) {
329
+ if (!this.privilegedKeyManager) {
330
+ throw new Error('Privileged operations require the Wallet to be configured with a privileged key manager.')
331
+ }
332
+ return this.privilegedKeyManager.createSignature(args)
333
+ }
334
+ return this.proto.createSignature(args)
335
+ }
336
+ verifySignature(
337
+ args: VerifySignatureArgs,
338
+ originator?: OriginatorDomainNameStringUnder250Bytes
339
+ ): Promise<VerifySignatureResult> {
340
+ if (args.privileged) {
341
+ if (!this.privilegedKeyManager) {
342
+ throw new Error('Privileged operations require the Wallet to be configured with a privileged key manager.')
343
+ }
344
+ return this.privilegedKeyManager.verifySignature(args)
345
+ }
346
+ return this.proto.verifySignature(args)
347
+ }
348
+
349
+ getServices(): WalletServices {
350
+ if (!this.services)
351
+ throw new WERR_INVALID_PARAMETER('services', 'valid in constructor arguments to be retreived here.')
352
+ return this.services
353
+ }
354
+
355
+ /**
356
+ * @returns the full list of txids whose validity this wallet claims to know.
357
+ *
358
+ * @param newKnownTxids Optional. Additional new txids known to be valid by the caller to be merged.
359
+ */
360
+ getKnownTxids(newKnownTxids?: string[]): string[] {
361
+ if (newKnownTxids) {
362
+ for (const txid of newKnownTxids) this.beef.mergeTxidOnly(txid)
363
+ }
364
+ const r = this.beef.sortTxs()
365
+ const knownTxids = r.valid
366
+ return knownTxids
367
+ }
368
+
369
+ getStorageIdentity(): StorageIdentity {
370
+ const s = this.storage.getSettings()
371
+ return {
372
+ storageIdentityKey: s.storageIdentityKey,
373
+ storageName: s.storageName
374
+ }
375
+ }
376
+
377
+ private validateAuthAndArgs<A, T extends Validation.ValidWalletSignerArgs>(
378
+ args: A,
379
+ validate: (args: A, logger?: WalletLoggerInterface) => T,
380
+ logger?: WalletLoggerInterface
381
+ ): { vargs: T; auth: AuthId } {
382
+ const vargs = validate(args, logger)
383
+ const auth: AuthId = { identityKey: this.identityKey }
384
+ return { vargs, auth }
385
+ }
386
+
387
+ //////////////////
388
+ // List Methods
389
+ //////////////////
390
+
391
+ async listActions(
392
+ args: ListActionsArgs,
393
+ originator?: OriginatorDomainNameStringUnder250Bytes
394
+ ): Promise<ListActionsResult> {
395
+ Validation.validateOriginator(originator)
396
+ const { vargs } = this.validateAuthAndArgs(args, Validation.validateListActionsArgs)
397
+ const r = await this.storage.listActions(vargs)
398
+ return r
399
+ }
400
+
401
+ get storageParty(): string {
402
+ return `storage ${this.getStorageIdentity().storageIdentityKey}`
403
+ }
404
+
405
+ async listOutputs(
406
+ args: ListOutputsArgs,
407
+ originator?: OriginatorDomainNameStringUnder250Bytes
408
+ ): Promise<ListOutputsResult> {
409
+ Validation.validateOriginator(originator)
410
+ const { vargs } = this.validateAuthAndArgs(args, Validation.validateListOutputsArgs)
411
+ if (this.autoKnownTxids && !vargs.knownTxids) {
412
+ vargs.knownTxids = this.getKnownTxids()
413
+ }
414
+ const r = await this.storage.listOutputs(vargs)
415
+ if (r.BEEF) {
416
+ this.beef.mergeBeefFromParty(this.storageParty, r.BEEF)
417
+ r.BEEF = this.verifyReturnedTxidOnlyBEEF(r.BEEF)
418
+ }
419
+ return r
420
+ }
421
+
422
+ async listCertificates(
423
+ args: ListCertificatesArgs,
424
+ originator?: OriginatorDomainNameStringUnder250Bytes
425
+ ): Promise<ListCertificatesResult> {
426
+ Validation.validateOriginator(originator)
427
+ const { vargs } = this.validateAuthAndArgs(args, Validation.validateListCertificatesArgs)
428
+ const r = await this.storage.listCertificates(vargs)
429
+ return r
430
+ }
431
+
432
+ //////////////////
433
+ // Certificates
434
+ //////////////////
435
+
436
+ async acquireCertificate(
437
+ args: AcquireCertificateArgs,
438
+ originator?: OriginatorDomainNameStringUnder250Bytes
439
+ ): Promise<AcquireCertificateResult> {
440
+ Validation.validateOriginator(originator)
441
+ if (args.acquisitionProtocol === 'direct') {
442
+ const { auth, vargs } = this.validateAuthAndArgs(args, Validation.validateAcquireDirectCertificateArgs)
443
+ vargs.subject = (
444
+ await this.getPublicKey({
445
+ identityKey: true,
446
+ privileged: args.privileged,
447
+ privilegedReason: args.privilegedReason
448
+ })
449
+ ).publicKey
450
+ try {
451
+ // Confirm that the information received adds up to a usable certificate...
452
+ // TODO: Clean up MasterCertificate to support decrypt on instance
453
+ const cert = new MasterCertificate(
454
+ vargs.type,
455
+ vargs.serialNumber,
456
+ vargs.subject,
457
+ vargs.certifier,
458
+ vargs.revocationOutpoint,
459
+ vargs.fields,
460
+ vargs.keyringForSubject,
461
+ vargs.signature
462
+ )
463
+ await cert.verify()
464
+
465
+ // Verify certificate details
466
+ await MasterCertificate.decryptFields(
467
+ this,
468
+ vargs.keyringForSubject,
469
+ vargs.fields,
470
+ vargs.certifier,
471
+ vargs.privileged,
472
+ vargs.privilegedReason
473
+ )
474
+ } catch (eu: unknown) {
475
+ const e = WalletError.fromUnknown(eu)
476
+ throw new WERR_INVALID_PARAMETER(
477
+ 'args',
478
+ `valid encrypted and signed certificate and keyring from revealer. ${e.name}: ${e.message}`
479
+ )
480
+ }
481
+
482
+ const r = await acquireDirectCertificate(this, auth, vargs)
483
+ return r
484
+ }
485
+
486
+ if (args.acquisitionProtocol === 'issuance') {
487
+ const { auth, vargs } = this.validateAuthAndArgs(args, Validation.validateAcquireIssuanceCertificateArgs)
488
+ // Create a random nonce that the server can verify
489
+ const clientNonce = await createNonce(this, vargs.certifier)
490
+ // TODO: Consider adding support to request certificates from a certifier before acquiring a certificate.
491
+ const authClient = new AuthFetch(this)
492
+
493
+ // Create a certificate master keyring
494
+ // The certifier is able to decrypt these fields as they are the counterparty
495
+ const { certificateFields, masterKeyring } = await MasterCertificate.createCertificateFields(
496
+ this,
497
+ vargs.certifier,
498
+ vargs.fields
499
+ )
500
+
501
+ // Make a Certificate Signing Request (CSR) to the certifier
502
+ const response = await authClient.fetch(`${vargs.certifierUrl}/signCertificate`, {
503
+ method: 'POST',
504
+ headers: {
505
+ 'Content-Type': 'application/json'
506
+ },
507
+ body: JSON.stringify({
508
+ clientNonce,
509
+ type: vargs.type,
510
+ fields: certificateFields,
511
+ masterKeyring
512
+ })
513
+ })
514
+
515
+ if (response.headers.get('x-bsv-auth-identity-key') !== vargs.certifier) {
516
+ throw new Error(
517
+ `Invalid certifier! Expected: ${vargs.certifier}, Received: ${response.headers.get('x-bsv-auth-identity-key')}`
518
+ )
519
+ }
520
+
521
+ const { certificate, serverNonce } = await response.json()
522
+
523
+ // Validate the server response
524
+ if (!certificate) {
525
+ throw new Error('No certificate received from certifier!')
526
+ }
527
+ if (!serverNonce) {
528
+ throw new Error('No serverNonce received from certifier!')
529
+ }
530
+
531
+ const signedCertificate = new Certificate(
532
+ certificate.type,
533
+ certificate.serialNumber,
534
+ certificate.subject,
535
+ certificate.certifier,
536
+ certificate.revocationOutpoint,
537
+ certificate.fields,
538
+ certificate.signature
539
+ )
540
+
541
+ // Validate server nonce
542
+ await verifyNonce(serverNonce, this, vargs.certifier)
543
+ // Verify the server included our nonce
544
+ const { valid } = await this.verifyHmac({
545
+ hmac: Utils.toArray(signedCertificate.serialNumber, 'base64'),
546
+ data: Utils.toArray(clientNonce + serverNonce, 'base64'),
547
+ protocolID: [2, 'certificate issuance'],
548
+ keyID: serverNonce + clientNonce,
549
+ counterparty: vargs.certifier
550
+ })
551
+ if (!valid) throw new Error('Invalid serialNumber')
552
+
553
+ // Validate the certificate received
554
+ if (signedCertificate.type !== vargs.type) {
555
+ throw new Error(`Invalid certificate type! Expected: ${vargs.type}, Received: ${signedCertificate.type}`)
556
+ }
557
+ if (signedCertificate.subject !== this.identityKey) {
558
+ throw new Error(
559
+ `Invalid certificate subject! Expected: ${this.identityKey}, Received: ${signedCertificate.subject}`
560
+ )
561
+ }
562
+ if (signedCertificate.certifier !== vargs.certifier) {
563
+ throw new Error(`Invalid certifier! Expected: ${vargs.certifier}, Received: ${signedCertificate.certifier}`)
564
+ }
565
+ if (!signedCertificate.revocationOutpoint) {
566
+ throw new Error(`Invalid revocationOutpoint!`)
567
+ }
568
+ if (Object.keys(signedCertificate.fields).length !== Object.keys(certificateFields).length) {
569
+ throw new Error(`Fields mismatch! Objects have different numbers of keys.`)
570
+ }
571
+ for (const field of Object.keys(certificateFields)) {
572
+ if (!(field in signedCertificate.fields)) {
573
+ throw new Error(`Missing field: ${field} in certificate.fields`)
574
+ }
575
+ if (signedCertificate.fields[field] !== certificateFields[field]) {
576
+ throw new Error(
577
+ `Invalid field! Expected: ${certificateFields[field]}, Received: ${signedCertificate.fields[field]}`
578
+ )
579
+ }
580
+ }
581
+
582
+ await signedCertificate.verify()
583
+
584
+ // Test decryption works
585
+ await MasterCertificate.decryptFields(this, masterKeyring, certificate.fields, vargs.certifier)
586
+
587
+ // Store the newly issued certificate
588
+ return await acquireDirectCertificate(this, auth, {
589
+ ...certificate,
590
+ keyringRevealer: 'certifier',
591
+ keyringForSubject: masterKeyring,
592
+ privileged: vargs.privileged
593
+ })
594
+ }
595
+
596
+ throw new WERR_INVALID_PARAMETER('acquisitionProtocol', `valid.${args.acquisitionProtocol} is unrecognized.`)
597
+ }
598
+
599
+ async relinquishCertificate(
600
+ args: RelinquishCertificateArgs,
601
+ originator?: OriginatorDomainNameStringUnder250Bytes
602
+ ): Promise<RelinquishCertificateResult> {
603
+ Validation.validateOriginator(originator)
604
+ this.validateAuthAndArgs(args, Validation.validateRelinquishCertificateArgs)
605
+ const r = await this.storage.relinquishCertificate(args)
606
+ return { relinquished: true }
607
+ }
608
+
609
+ async proveCertificate(
610
+ args: ProveCertificateArgs,
611
+ originator?: OriginatorDomainNameStringUnder250Bytes
612
+ ): Promise<ProveCertificateResult> {
613
+ originator = Validation.validateOriginator(originator)
614
+ const { auth, vargs } = this.validateAuthAndArgs(args, Validation.validateProveCertificateArgs)
615
+ const r = await proveCertificate(this, auth, vargs)
616
+ return r
617
+ }
618
+
619
+ /** 2-minute cache of trust settings for identity resolution paths */
620
+ private _trustSettingsCache?: {
621
+ expiresAt: number
622
+ trustSettings: Awaited<ReturnType<WalletSettingsManager['get']>>['trustSettings']
623
+ }
624
+
625
+ /** 2-minute cache of queryOverlay() results keyed by normalized query */
626
+ private _overlayCache: Map<string, { expiresAt: number; value: unknown }> = new Map()
627
+
628
+ async discoverByIdentityKey(
629
+ args: DiscoverByIdentityKeyArgs,
630
+ originator?: OriginatorDomainNameStringUnder250Bytes
631
+ ): Promise<DiscoverCertificatesResult> {
632
+ Validation.validateOriginator(originator)
633
+ this.validateAuthAndArgs(args, Validation.validateDiscoverByIdentityKeyArgs)
634
+
635
+ const TTL_MS = 2 * 60 * 1000
636
+ const now = Date.now()
637
+
638
+ // --- trustSettings cache (2 minutes) ---
639
+ let trustSettings =
640
+ this._trustSettingsCache && this._trustSettingsCache.expiresAt > now
641
+ ? this._trustSettingsCache.trustSettings
642
+ : undefined
643
+
644
+ if (!trustSettings) {
645
+ const settings = await this.settingsManager.get()
646
+ trustSettings = settings.trustSettings
647
+ this._trustSettingsCache = { trustSettings, expiresAt: now + TTL_MS }
648
+ }
649
+
650
+ const certifiers = trustSettings.trustedCertifiers.map(c => c.identityKey).sort()
651
+
652
+ // --- queryOverlay cache (2 minutes) ---
653
+ const cacheKey = JSON.stringify({
654
+ fn: 'discoverByIdentityKey',
655
+ identityKey: args.identityKey,
656
+ certifiers
657
+ })
658
+
659
+ let cached = this._overlayCache.get(cacheKey)
660
+ if (!cached || cached.expiresAt <= now) {
661
+ const value = await queryOverlay({ identityKey: args.identityKey, certifiers }, this.lookupResolver)
662
+ cached = { value, expiresAt: now + TTL_MS }
663
+ this._overlayCache.set(cacheKey, cached)
664
+ }
665
+
666
+ if (!cached.value) {
667
+ return { totalCertificates: 0, certificates: [] }
668
+ }
669
+
670
+ return transformVerifiableCertificatesWithTrust(trustSettings, cached.value as any)
671
+ }
672
+
673
+ async discoverByAttributes(
674
+ args: DiscoverByAttributesArgs,
675
+ originator?: OriginatorDomainNameStringUnder250Bytes
676
+ ): Promise<DiscoverCertificatesResult> {
677
+ Validation.validateOriginator(originator)
678
+ this.validateAuthAndArgs(args, Validation.validateDiscoverByAttributesArgs)
679
+
680
+ const TTL_MS = 2 * 60 * 1000
681
+ const now = Date.now()
682
+
683
+ // --- trustSettings cache (2 minutes) ---
684
+ let trustSettings =
685
+ this._trustSettingsCache && this._trustSettingsCache.expiresAt > now
686
+ ? this._trustSettingsCache.trustSettings
687
+ : undefined
688
+
689
+ if (!trustSettings) {
690
+ const settings = await this.settingsManager.get()
691
+ trustSettings = settings.trustSettings
692
+ this._trustSettingsCache = { trustSettings, expiresAt: now + TTL_MS }
693
+ }
694
+
695
+ const certifiers = trustSettings.trustedCertifiers.map(c => c.identityKey).sort()
696
+
697
+ // Normalize attributes for a stable cache key.
698
+ // If attributes is an object, sort its top-level keys; if it's an array, sort a shallow copy.
699
+ let attributesKey: unknown = args.attributes
700
+ if (args.attributes && typeof args.attributes === 'object') {
701
+ const keys = Object.keys(args.attributes as Record<string, unknown>).sort()
702
+ attributesKey = JSON.stringify(args.attributes, keys)
703
+ }
704
+
705
+ // --- queryOverlay cache (2 minutes) ---
706
+ const cacheKey = JSON.stringify({
707
+ fn: 'discoverByAttributes',
708
+ attributes: attributesKey,
709
+ certifiers
710
+ })
711
+
712
+ let cached = this._overlayCache.get(cacheKey)
713
+ if (!cached || cached.expiresAt <= now) {
714
+ const value = await queryOverlay({ attributes: args.attributes, certifiers }, this.lookupResolver)
715
+ cached = { value, expiresAt: now + TTL_MS }
716
+ this._overlayCache.set(cacheKey, cached)
717
+ }
718
+
719
+ if (!cached.value) {
720
+ return { totalCertificates: 0, certificates: [] }
721
+ }
722
+
723
+ return transformVerifiableCertificatesWithTrust(trustSettings, cached.value as any)
724
+ }
725
+
726
+ verifyReturnedTxidOnly(beef: Beef, knownTxids?: string[]): Beef {
727
+ if (this.returnTxidOnly) return beef
728
+ const onlyTxids = beef.txs.filter(btx => btx.isTxidOnly).map(btx => btx.txid)
729
+ for (const txid of onlyTxids) {
730
+ if (knownTxids && knownTxids.indexOf(txid) >= 0) continue
731
+ const btx = beef.findTxid(txid)
732
+ const tx = this.beef.findAtomicTransaction(txid)
733
+ if (!tx) throw new WERR_INTERNAL(`unable to merge txid ${txid} into beef`)
734
+ beef.mergeTransaction(tx)
735
+ }
736
+ for (const btx of beef.txs) {
737
+ if (knownTxids && knownTxids.indexOf(btx.txid) >= 0) continue
738
+ if (btx.isTxidOnly) throw new WERR_INTERNAL(`remaining txidOnly ${btx.txid} is not known`)
739
+ }
740
+ return beef
741
+ }
742
+
743
+ verifyReturnedTxidOnlyAtomicBEEF(beef: AtomicBEEF, knownTxids?: string[]): AtomicBEEF {
744
+ if (this.returnTxidOnly) return beef
745
+ const b = Beef.fromBinary(beef)
746
+ if (!b.atomicTxid) throw new WERR_INTERNAL()
747
+ return this.verifyReturnedTxidOnly(b, knownTxids).toBinaryAtomic(b.atomicTxid!)
748
+ }
749
+
750
+ verifyReturnedTxidOnlyBEEF(beef: BEEF): BEEF {
751
+ if (this.returnTxidOnly) return beef
752
+ const b = Beef.fromBinary(beef)
753
+ return this.verifyReturnedTxidOnly(b).toBinary()
754
+ }
755
+
756
+ logMakeLogger(method: string, args: any): WalletLoggerInterface | undefined {
757
+ const logger = this.makeLogger?.(args['log'])
758
+ this.logMethodStart(method, logger)
759
+ return logger
760
+ }
761
+
762
+ logMethodStart(method: string, logger?: WalletLoggerInterface): void {
763
+ logger?.group(`Wallet ${method}`)
764
+ }
765
+
766
+ logResult(r: any, logger?: WalletLoggerInterface): void {
767
+ if (!logger) return
768
+ logger.groupEnd()
769
+ r['log'] = logger.flush?.()
770
+ }
771
+
772
+ logWalletError(eu: unknown, logger?: WalletLoggerInterface): void {
773
+ if (!logger) return
774
+ logger.error('WalletError:', WalletError.unknownToJson(eu))
775
+ logger.flush?.()
776
+ }
777
+
778
+ //////////////////
779
+ // Actions
780
+ //////////////////
781
+
782
+ async createAction(
783
+ args: CreateActionArgs,
784
+ originator?: OriginatorDomainNameStringUnder250Bytes
785
+ ): Promise<CreateActionResult> {
786
+ const logger = this.logMakeLogger(`createAction`, args)
787
+ try {
788
+ Validation.validateOriginator(originator)
789
+
790
+ if (!args.options) args.options = {}
791
+ args.options.trustSelf ||= this.trustSelf
792
+ if (this.autoKnownTxids && !args.options.knownTxids) {
793
+ args.options.knownTxids = this.getKnownTxids(args.options.knownTxids)
794
+ }
795
+
796
+ const { auth, vargs } = this.validateAuthAndArgs(args, Validation.validateCreateActionArgs, logger)
797
+ logger?.log('validated args')
798
+
799
+ vargs.includeAllSourceTransactions = this.includeAllSourceTransactions
800
+ if (this.randomVals && this.randomVals.length > 1) {
801
+ vargs.randomVals = [...this.randomVals]
802
+ }
803
+
804
+ const r = await createAction(this, auth, vargs)
805
+ logger?.log('action created')
806
+
807
+ if (r.tx) {
808
+ this.beef.mergeBeefFromParty(this.storageParty, r.tx)
809
+ }
810
+
811
+ if (r.tx) {
812
+ r.tx = this.verifyReturnedTxidOnlyAtomicBEEF(r.tx, args.options?.knownTxids)
813
+ logger?.log('verify returned AtomicBEEF')
814
+ }
815
+
816
+ if (!vargs.isDelayed) throwIfAnyUnsuccessfulCreateActions(r)
817
+
818
+ this.logResult(r, logger)
819
+ return r
820
+ } catch (eu: unknown) {
821
+ this.logWalletError(eu, logger)
822
+ throw eu
823
+ }
824
+ }
825
+
826
+ async signAction(
827
+ args: SignActionArgs,
828
+ originator?: OriginatorDomainNameStringUnder250Bytes
829
+ ): Promise<SignActionResult> {
830
+ Validation.validateOriginator(originator)
831
+
832
+ const { auth, vargs } = this.validateAuthAndArgs(args, Validation.validateSignActionArgs)
833
+ // createAction options are merged with undefined signAction options before validation...
834
+ const r = await signAction(this, auth, args)
835
+
836
+ if (!vargs.isDelayed) throwIfAnyUnsuccessfulSignActions(r)
837
+
838
+ const prior = this.pendingSignActions[args.reference]
839
+ if (r.tx) r.tx = this.verifyReturnedTxidOnlyAtomicBEEF(r.tx, prior.args.options?.knownTxids)
840
+
841
+ return r
842
+ }
843
+
844
+ async internalizeAction(
845
+ args: InternalizeActionArgs,
846
+ originator?: OriginatorDomainNameStringUnder250Bytes
847
+ ): Promise<InternalizeActionResult> {
848
+ Validation.validateOriginator(originator)
849
+ const { auth, vargs } = this.validateAuthAndArgs(args, Validation.validateInternalizeActionArgs)
850
+
851
+ if (vargs.labels.indexOf(specOpThrowReviewActions) >= 0) throwDummyReviewActions()
852
+
853
+ const r = await internalizeAction(this, auth, args)
854
+
855
+ throwIfUnsuccessfulInternalizeAction(r)
856
+
857
+ return r
858
+ }
859
+
860
+ async abortAction(
861
+ args: AbortActionArgs,
862
+ originator?: OriginatorDomainNameStringUnder250Bytes
863
+ ): Promise<AbortActionResult> {
864
+ Validation.validateOriginator(originator)
865
+
866
+ const { auth } = this.validateAuthAndArgs(args, Validation.validateAbortActionArgs)
867
+ const r = await this.storage.abortAction(args)
868
+ return r
869
+ }
870
+
871
+ async relinquishOutput(
872
+ args: RelinquishOutputArgs,
873
+ originator?: OriginatorDomainNameStringUnder250Bytes
874
+ ): Promise<RelinquishOutputResult> {
875
+ Validation.validateOriginator(originator)
876
+ const { vargs } = this.validateAuthAndArgs(args, Validation.validateRelinquishOutputArgs)
877
+ const r = await this.storage.relinquishOutput(args)
878
+ return { relinquished: true }
879
+ }
880
+
881
+ async isAuthenticated(args: {}, originator?: OriginatorDomainNameStringUnder250Bytes): Promise<AuthenticatedResult> {
882
+ Validation.validateOriginator(originator)
883
+ const r: { authenticated: true } = {
884
+ authenticated: true
885
+ }
886
+ return r
887
+ }
888
+
889
+ async waitForAuthentication(
890
+ args: {},
891
+ originator?: OriginatorDomainNameStringUnder250Bytes
892
+ ): Promise<AuthenticatedResult> {
893
+ Validation.validateOriginator(originator)
894
+ return { authenticated: true }
895
+ }
896
+
897
+ async getHeight(args: {}, originator?: OriginatorDomainNameStringUnder250Bytes): Promise<GetHeightResult> {
898
+ Validation.validateOriginator(originator)
899
+ const height = await this.getServices().getHeight()
900
+ return { height }
901
+ }
902
+
903
+ async getHeaderForHeight(
904
+ args: GetHeaderArgs,
905
+ originator?: OriginatorDomainNameStringUnder250Bytes
906
+ ): Promise<GetHeaderResult> {
907
+ Validation.validateOriginator(originator)
908
+ const serializedHeader = await this.getServices().getHeaderForHeight(args.height)
909
+ return { header: Utils.toHex(serializedHeader) }
910
+ }
911
+
912
+ async getNetwork(args: {}, originator?: OriginatorDomainNameStringUnder250Bytes): Promise<GetNetworkResult> {
913
+ Validation.validateOriginator(originator)
914
+ return { network: toWalletNetwork(this.chain) }
915
+ }
916
+
917
+ async getVersion(args: {}, originator?: OriginatorDomainNameStringUnder250Bytes): Promise<GetVersionResult> {
918
+ Validation.validateOriginator(originator)
919
+ return { version: 'wallet-brc100-1.0.0' }
920
+ }
921
+
922
+ /**
923
+ * Transfer all possible satoshis held by this wallet to `toWallet`.
924
+ *
925
+ * @param toWallet wallet which will receive this wallet's satoshis.
926
+ */
927
+ async sweepTo(toWallet: Wallet): Promise<void> {
928
+ const derivationPrefix = randomBytesBase64(8)
929
+ const derivationSuffix = randomBytesBase64(8)
930
+ const keyDeriver = this.keyDeriver
931
+
932
+ const t = new ScriptTemplateBRC29({
933
+ derivationPrefix,
934
+ derivationSuffix,
935
+ keyDeriver
936
+ })
937
+
938
+ const label = 'sweep'
939
+
940
+ const satoshis = maxPossibleSatoshis
941
+
942
+ const car = await this.createAction({
943
+ outputs: [
944
+ {
945
+ lockingScript: t.lock(keyDeriver.rootKey.toString(), toWallet.identityKey).toHex(),
946
+ satoshis,
947
+ outputDescription: label,
948
+ tags: ['relinquish'],
949
+ customInstructions: JSON.stringify({
950
+ derivationPrefix,
951
+ derivationSuffix,
952
+ type: 'BRC29'
953
+ })
954
+ }
955
+ ],
956
+ options: {
957
+ randomizeOutputs: false,
958
+ acceptDelayedBroadcast: false
959
+ },
960
+ labels: [label],
961
+ description: label
962
+ })
963
+
964
+ const iar = await toWallet.internalizeAction({
965
+ tx: car.tx!,
966
+ outputs: [
967
+ {
968
+ outputIndex: 0,
969
+ protocol: 'wallet payment',
970
+ paymentRemittance: {
971
+ derivationPrefix,
972
+ derivationSuffix,
973
+ senderIdentityKey: this.identityKey
974
+ }
975
+ }
976
+ ],
977
+ description: label,
978
+ labels: [label]
979
+ })
980
+ }
981
+
982
+ /**
983
+ * Uses `listOutputs` to iterate over chunks of up to 1000 outputs to
984
+ * compute the sum of output satoshis.
985
+ *
986
+ * @param {string} basket - Optional. Defaults to 'default', the wallet change basket.
987
+ * @returns {WalletBalance} total sum of output satoshis and utxo details (satoshis and outpoints)
988
+ */
989
+ async balanceAndUtxos(basket: string = 'default'): Promise<WalletBalance> {
990
+ const r: WalletBalance = { total: 0, utxos: [] }
991
+ let offset = 0
992
+ for (;;) {
993
+ const change = await this.listOutputs({
994
+ basket,
995
+ limit: 1000,
996
+ offset
997
+ })
998
+ if (change.totalOutputs === 0) break
999
+ for (const o of change.outputs) {
1000
+ r.total += o.satoshis
1001
+ r.utxos.push({ satoshis: o.satoshis, outpoint: o.outpoint })
1002
+ }
1003
+ offset += change.outputs.length
1004
+ }
1005
+ return r
1006
+ }
1007
+
1008
+ /**
1009
+ * Uses `listOutputs` special operation to compute the total value (of satoshis) for
1010
+ * all spendable outputs in the 'default' basket.
1011
+ *
1012
+ * @returns {number} sum of output satoshis
1013
+ */
1014
+ async balance(): Promise<number> {
1015
+ const args: ListOutputsArgs = {
1016
+ basket: specOpWalletBalance
1017
+ }
1018
+ const r = await this.listOutputs(args)
1019
+ return r.totalOutputs
1020
+ }
1021
+
1022
+ /**
1023
+ * Uses `listOutputs` special operation to review the spendability via `Services` of
1024
+ * outputs currently considered spendable. Returns the outputs that fail to verify.
1025
+ *
1026
+ * Ignores the `limit` and `offset` properties.
1027
+ *
1028
+ * @param all Defaults to false. If false, only change outputs ('default' basket) are reviewed. If true, all spendable outputs are reviewed.
1029
+ * @param release Defaults to false. If true, sets outputs that fail to verify to un-spendable (spendable: false)
1030
+ * @param optionalArgs Optional. Additional tags will constrain the outputs processed.
1031
+ * @returns outputs which are/where considered spendable but currently fail to verify as spendable.
1032
+ */
1033
+ async reviewSpendableOutputs(
1034
+ all = false,
1035
+ release = false,
1036
+ optionalArgs?: Partial<ListOutputsArgs>
1037
+ ): Promise<ListOutputsResult> {
1038
+ const args: ListOutputsArgs = {
1039
+ ...(optionalArgs || {}),
1040
+ basket: specOpInvalidChange
1041
+ }
1042
+ args.tags ||= []
1043
+ if (all) args.tags.push('all')
1044
+ if (release) args.tags.push('release')
1045
+ const r = await this.listOutputs(args)
1046
+ return r
1047
+ }
1048
+
1049
+ /**
1050
+ * Uses `listOutputs` special operation to update the 'default' basket's automatic
1051
+ * change generation parameters.
1052
+ *
1053
+ * @param count target number of change UTXOs to maintain.
1054
+ * @param satoshis target value for new change outputs.
1055
+ */
1056
+ async setWalletChangeParams(count: number, satoshis: number): Promise<void> {
1057
+ const args: ListOutputsArgs = {
1058
+ basket: specOpSetWalletChangeParams,
1059
+ tags: [count.toString(), satoshis.toString()]
1060
+ }
1061
+ await this.listOutputs(args)
1062
+ }
1063
+
1064
+ /**
1065
+ * Uses `listActions` special operation to return only actions with status 'nosend'.
1066
+ *
1067
+ * @param abort Defaults to false. If true, runs `abortAction` on each 'nosend' action.
1068
+ * @returns {ListActionsResult} start `listActions` result restricted to 'nosend' (or 'failed' if aborted) actions.
1069
+ */
1070
+ async listNoSendActions(args: ListActionsArgs, abort = false): Promise<ListActionsResult> {
1071
+ const { vargs } = this.validateAuthAndArgs(args, Validation.validateListActionsArgs)
1072
+ vargs.labels.push(specOpNoSendActions)
1073
+ if (abort) vargs.labels.push('abort')
1074
+ const r = await this.storage.listActions(vargs)
1075
+ return r
1076
+ }
1077
+
1078
+ /**
1079
+ * Uses `listActions` special operation to return only actions with status 'failed'.
1080
+ *
1081
+ * @param unfail Defaults to false. If true, queues the action for attempted recovery.
1082
+ * @returns {ListActionsResult} start `listActions` result restricted to 'failed' status actions.
1083
+ */
1084
+ async listFailedActions(args: ListActionsArgs, unfail = false): Promise<ListActionsResult> {
1085
+ const { vargs } = this.validateAuthAndArgs(args, Validation.validateListActionsArgs)
1086
+ vargs.labels.push(specOpFailedActions)
1087
+ if (unfail) vargs.labels.push('unfail')
1088
+ const r = await this.storage.listActions(vargs)
1089
+ return r
1090
+ }
1091
+ }
1092
+
1093
+ export interface PendingStorageInput {
1094
+ vin: number
1095
+ derivationPrefix: string
1096
+ derivationSuffix: string
1097
+ unlockerPubKey?: string
1098
+ sourceSatoshis: number
1099
+ lockingScript: string
1100
+ }
1101
+
1102
+ export interface PendingSignAction {
1103
+ reference: string
1104
+ dcr: StorageCreateActionResult
1105
+ args: Validation.ValidCreateActionArgs
1106
+ tx: BsvTransaction
1107
+ amount: number
1108
+ pdi: PendingStorageInput[]
1109
+ }
1110
+
1111
+ function throwIfAnyUnsuccessfulCreateActions(r: CreateActionResultX) {
1112
+ const ndrs = r.notDelayedResults
1113
+ const swrs = r.sendWithResults
1114
+
1115
+ if (!ndrs || !swrs || swrs.every(r => r.status === 'unproven')) return
1116
+
1117
+ throw new WERR_REVIEW_ACTIONS(ndrs, swrs, r.txid, r.tx, r.noSendChange)
1118
+ }
1119
+
1120
+ function throwIfAnyUnsuccessfulSignActions(r: SignActionResultX) {
1121
+ const ndrs = r.notDelayedResults
1122
+ const swrs = r.sendWithResults
1123
+
1124
+ if (!ndrs || !swrs || swrs.every(r => r.status === 'unproven')) return
1125
+
1126
+ throw new WERR_REVIEW_ACTIONS(ndrs, swrs, r.txid, r.tx)
1127
+ }
1128
+
1129
+ function throwIfUnsuccessfulInternalizeAction(r: StorageInternalizeActionResult) {
1130
+ const ndrs = r.notDelayedResults
1131
+ const swrs = r.sendWithResults
1132
+
1133
+ if (!ndrs || !swrs || swrs.every(r => r.status === 'unproven')) return
1134
+
1135
+ throw new WERR_REVIEW_ACTIONS(ndrs, swrs, r.txid)
1136
+ }
1137
+
1138
+ /**
1139
+ * Throws a WERR_REVIEW_ACTIONS with a full set of properties to test data formats and propagation.
1140
+ */
1141
+ export function throwDummyReviewActions() {
1142
+ const b58Beef =
1143
+ 'gno9MC7VXii1KoCkc2nsVyYJpqzN3dhBzYATETJcys62emMKfpBof4R7GozwYEaSapUtnNvqQ57aaYYjm3U2dv9eUJ1sV46boHkQgppYmAz9YH8FdZduV8aJayPViaKcyPmbDhEw6UW8TM5iFZLXNs7HBnJHUKCeTdNK4FUEL7vAugxAV9WUUZ43BZjJk2SmSeps9TCXjt1Ci9fKWp3d9QSoYvTpxwzyUFHjRKtbUgwq55ZfkBp5bV2Bpz9qSuKywKewW7Hh4S1nCUScwwzpKDozb3zic1V9p2k8rQxoPsRxjUJ8bjhNDdsN8d7KukFuc3n47fXzdWttvnxwsujLJRGnQbgJuknQqx3KLf5kJXHzwjG6TzigZk2t24qeB6d3hbYiaDr2fFkUJBL3tukTHhfNkQYRXuz3kucVDzvejHyqJaF51mXG8BjMN5aQj91ZJXCaPVqkMWCzmvyaqmXMdRiJdSAynhXbQK91xf6RwdNhz1tg5f9B6oJJMhsi9UYSVymmax8VLKD9AKzBCBDcfyD83m3jyS1VgKGZn3SkQmr6bsoWq88L3GsMnnmYUGogvdAYarTqg3pzkjCMxHzmJBMN6ofnUk8c1sRTXQue7BbyUaN5uZu3KW6CmFsEfpuqVvnqFW93TU1jrPP2S8yz8AexAnARPCKE8Yz7RfVaT6RCavwQKL3u5iookwRWEZXW1QWmM37yJWHD87SjVynyg327a1CLwcBxmE2CB48QeNVGyQki4CTQMqw2o8TMhDPJej1g68oniAjBcxBLSCs7KGvK3k7AfrHbCMULX9CTibYhCjdFjbsbBoocqJpxxcvkMo1fEEiAzZuiBVZQDYktDdTVbhKHvYkW25HcYX75NJrpNAhm7AjFeKLzEVxqAQkMfvTufpESNRZF4kQqg2Rg8h2ajcKTd5cpEPwXCrZLHm4EaZEmZVbg3QNfGhn7BJu1bHMtLqPD4y8eJxm2uGrW6saf6qKYmmu64F8A667NbD4yskPRQ1S863VzwGpxxmgLc1Ta3R46jEqsAoRDoZVUaCgBBZG3Yg1CTgi1EVBMXU7qvY4n3h8o2FLCEMWY4KadnV3iD4FbcdCmg4yxBosNAZgbPjhgGjCimjh4YsLd9zymGLmivmz2ZBg5m3xaiXT9NN81X9C1JUujd'
1144
+ const beef = Beef.fromBinary(Utils.fromBase58(b58Beef))
1145
+ const btx = beef.txs.slice(-1)[0]
1146
+ const txid = btx.txid
1147
+
1148
+ console.log('Throwing dummy WERR_REVIEW_ACTIONS')
1149
+
1150
+ throw new WERR_REVIEW_ACTIONS(
1151
+ [
1152
+ {
1153
+ txid, // only care that it is syntactically a txid
1154
+ status: 'doubleSpend',
1155
+ competingTxs: [txid], // a txid in the beef
1156
+ competingBeef: beef.toBinary()
1157
+ }
1158
+ ],
1159
+ [
1160
+ {
1161
+ txid,
1162
+ status: 'failed'
1163
+ }
1164
+ ],
1165
+ txid,
1166
+ beef.toBinaryAtomic(txid),
1167
+ [`${txid}.0`]
1168
+ )
1169
+ }