@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
@@ -0,0 +1,420 @@
1
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
2
+ import {
3
+ Beef,
4
+ Transaction as BsvTransaction,
5
+ SendWithResult,
6
+ SendWithResultStatus,
7
+ WalletLoggerInterface
8
+ } from '@bsv/sdk'
9
+ import { aggregateActionResults } from '../../utility/aggregateResults'
10
+ import { StorageProvider } from '../StorageProvider'
11
+ import {
12
+ AuthId,
13
+ ReviewActionResult,
14
+ StorageProcessActionArgs,
15
+ StorageProcessActionResults
16
+ } from '../../sdk/WalletStorage.interfaces'
17
+ import { stampLog } from '../../utility/stampLog'
18
+ import {
19
+ randomBytesBase64,
20
+ verifyId,
21
+ verifyInteger,
22
+ verifyOne,
23
+ verifyOneOrNone,
24
+ verifyTruthy
25
+ } from '../../utility/utilityHelpers'
26
+ import { EntityProvenTxReq } from '../schema/entities/EntityProvenTxReq'
27
+ import { WERR_INTERNAL, WERR_INVALID_OPERATION } from '../../sdk/WERR_errors'
28
+ import { TableProvenTxReq } from '../schema/tables/TableProvenTxReq'
29
+ import { TableProvenTx } from '../schema/tables/TableProvenTx'
30
+ import { ProvenTxReqStatus, TransactionStatus } from '../../sdk/types'
31
+ import { parseTxScriptOffsets, TxScriptOffsets } from '../../utility/parseTxScriptOffsets'
32
+ import { TableTransaction } from '../schema/tables/TableTransaction'
33
+ import { TableOutput } from '../schema/tables/TableOutput'
34
+ import { TableCommission } from '../schema/tables/TableCommission'
35
+ import { asArray, asString } from '../../utility/utilityHelpers.noBuffer'
36
+
37
+ export async function processAction(
38
+ storage: StorageProvider,
39
+ auth: AuthId,
40
+ args: StorageProcessActionArgs
41
+ ): Promise<StorageProcessActionResults> {
42
+ const logger = args.logger
43
+ logger?.group('storage processAction')
44
+
45
+ const userId = verifyId(auth.userId)
46
+ const r: StorageProcessActionResults = {
47
+ sendWithResults: undefined
48
+ }
49
+
50
+ let req: EntityProvenTxReq | undefined
51
+ const txidsOfReqsToShareWithWorld: string[] = [...args.sendWith]
52
+
53
+ if (args.isNewTx) {
54
+ const vargs = await validateCommitNewTxToStorageArgs(storage, userId, args)
55
+ logger?.log(`validated new tx updates to storage`)
56
+ ;({ req } = await commitNewTxToStorage(storage, userId, vargs))
57
+ logger?.log(`committed new tx updates to storage `)
58
+ if (!req) throw new WERR_INTERNAL()
59
+ // Add the new txid to sendWith unless there are no others to send and the noSend option is set.
60
+ if (args.isNoSend && !args.isSendWith) {
61
+ logger?.log(`noSend txid ${req.txid}`)
62
+ } else {
63
+ txidsOfReqsToShareWithWorld.push(req.txid)
64
+ logger?.log(`sending txid ${req.txid}`)
65
+ }
66
+ }
67
+
68
+ const { swr, ndr } = await shareReqsWithWorld(
69
+ storage,
70
+ userId,
71
+ txidsOfReqsToShareWithWorld,
72
+ args.isDelayed,
73
+ undefined,
74
+ logger
75
+ )
76
+
77
+ r.sendWithResults = swr
78
+ r.notDelayedResults = ndr
79
+
80
+ logger?.groupEnd()
81
+
82
+ return r
83
+ }
84
+
85
+ export interface GetReqsAndBeefDetail {
86
+ txid: string
87
+ req?: TableProvenTxReq
88
+ proven?: TableProvenTx
89
+ status: 'readyToSend' | 'alreadySent' | 'error' | 'unknown'
90
+ error?: string
91
+ }
92
+
93
+ export interface GetReqsAndBeefResult {
94
+ beef: Beef
95
+ details: GetReqsAndBeefDetail[]
96
+ }
97
+
98
+ export interface PostBeefResultForTxidApi {
99
+ txid: string
100
+
101
+ /**
102
+ * 'success' - The transaction was accepted for processing
103
+ */
104
+ status: 'success' | 'error'
105
+
106
+ /**
107
+ * if true, the transaction was already known to this service. Usually treat as a success.
108
+ *
109
+ * Potentially stop posting to additional transaction processors.
110
+ */
111
+ alreadyKnown?: boolean
112
+
113
+ blockHash?: string
114
+ blockHeight?: number
115
+ merklePath?: string
116
+ }
117
+
118
+ /**
119
+ * Verifies that all the txids are known reqs with ready-to-share status.
120
+ * Assigns a batch identifier and updates all the provenTxReqs.
121
+ * If not isDelayed, triggers an initial attempt to broadcast the batch and returns the results.
122
+ *
123
+ * @param storage
124
+ * @param userId
125
+ * @param txids
126
+ * @param isDelayed
127
+ * @param r Optional. Ignores txids and allows ProvenTxReqs and merged beef to be passed in.
128
+ */
129
+ export async function shareReqsWithWorld(
130
+ storage: StorageProvider,
131
+ userId: number,
132
+ txids: string[],
133
+ isDelayed: boolean,
134
+ r?: GetReqsAndBeefResult,
135
+ logger?: WalletLoggerInterface
136
+ ): Promise<{ swr: SendWithResult[]; ndr: ReviewActionResult[] | undefined }> {
137
+ let swr: SendWithResult[] = []
138
+ let ndr: ReviewActionResult[] | undefined = undefined
139
+
140
+ if (!r && txids.length < 1) return { swr, ndr }
141
+
142
+ // Collect what we know about these sendWith transaction txids from storage.
143
+ r ||= await storage.getReqsAndBeefToShareWithWorld(txids, [])
144
+
145
+ const readyToSendReqs: EntityProvenTxReq[] = []
146
+ for (const getReq of r.details) {
147
+ let status: SendWithResultStatus = 'failed'
148
+ if (getReq.status === 'alreadySent') status = 'unproven'
149
+ else if (getReq.status === 'readyToSend') {
150
+ status = 'sending'
151
+ readyToSendReqs.push(new EntityProvenTxReq(getReq.req!))
152
+ }
153
+ swr.push({
154
+ txid: getReq.txid,
155
+ status
156
+ })
157
+ }
158
+
159
+ // Filter original txids down to reqIds that are available and need sending
160
+ const readyToSendReqIds = readyToSendReqs.map(r => r.id)
161
+ const transactionIds = readyToSendReqs.map(r => r.notify.transactionIds || []).flat()
162
+
163
+ // If there are reqs to send, verify that we have a valid aggregate beef for them.
164
+ // If isDelayed, this (or a different beef) will have to be rebuilt at the time of sending.
165
+ if (readyToSendReqs.length > 0) {
166
+ const beefIsValid = await r.beef.verify(await storage.getServices().getChainTracker())
167
+ if (!beefIsValid) {
168
+ logger?.error(`VERIFY FALSE BEEF: ${r.beef.toLogString()}`)
169
+ throw new WERR_INTERNAL(`merged Beef failed validation.`)
170
+ }
171
+ logger?.log(`beef is valid`)
172
+ }
173
+
174
+ // Set req batch property for the reqs being sent
175
+ // If delayed, also bump status to 'unsent' and we're done here
176
+ const batch = txids.length > 1 ? randomBytesBase64(16) : undefined
177
+ if (isDelayed) {
178
+ // Just bump the req status to 'unsent' to enable background sending...
179
+ if (readyToSendReqIds.length > 0) {
180
+ await storage.transaction(async trx => {
181
+ await storage.updateProvenTxReq(readyToSendReqIds, { status: 'unsent', batch }, trx)
182
+ await storage.updateTransaction(transactionIds, { status: 'sending' }, trx)
183
+ })
184
+ }
185
+ return { swr, ndr }
186
+ }
187
+
188
+ if (readyToSendReqIds.length < 1) {
189
+ return { swr, ndr }
190
+ }
191
+
192
+ if (batch) {
193
+ // Keep batch values in sync...
194
+ for (const req of readyToSendReqs) req.batch = batch
195
+ await storage.updateProvenTxReq(readyToSendReqIds, { batch })
196
+ }
197
+
198
+ //
199
+ // Handle the NON-DELAYED-SEND-NOW case
200
+ //
201
+ const prtn = await storage.attemptToPostReqsToNetwork(readyToSendReqs, undefined, logger)
202
+
203
+ const { swr: swrRes, rar } = await aggregateActionResults(storage, swr, prtn)
204
+ return { swr: swrRes, ndr: rar }
205
+ }
206
+
207
+ interface ReqTxStatus {
208
+ req: ProvenTxReqStatus
209
+ tx: TransactionStatus
210
+ }
211
+
212
+ interface ValidCommitNewTxToStorageArgs {
213
+ // validated input args
214
+
215
+ reference: string
216
+ txid: string
217
+ rawTx: number[]
218
+ isNoSend: boolean
219
+ isDelayed: boolean
220
+ isSendWith: boolean
221
+ log?: string
222
+
223
+ // validated dependent args
224
+
225
+ tx: BsvTransaction
226
+ txScriptOffsets: TxScriptOffsets
227
+ transactionId: number
228
+ transaction: TableTransaction
229
+ inputOutputs: TableOutput[]
230
+ outputOutputs: TableOutput[]
231
+ commission: TableCommission | undefined
232
+ beef: Beef
233
+
234
+ req: EntityProvenTxReq
235
+ outputUpdates: { id: number; update: Partial<TableOutput> }[]
236
+ transactionUpdate: Partial<TableTransaction>
237
+ postStatus?: ReqTxStatus
238
+ }
239
+
240
+ async function validateCommitNewTxToStorageArgs(
241
+ storage: StorageProvider,
242
+ userId: number,
243
+ params: StorageProcessActionArgs
244
+ ): Promise<ValidCommitNewTxToStorageArgs> {
245
+ if (!params.reference || !params.txid || !params.rawTx)
246
+ throw new WERR_INVALID_OPERATION('One or more expected params are undefined.')
247
+ let tx: BsvTransaction
248
+ try {
249
+ tx = BsvTransaction.fromBinary(params.rawTx)
250
+ } catch (e: unknown) {
251
+ throw new WERR_INVALID_OPERATION('Parsing serialized transaction failed.')
252
+ }
253
+ if (params.txid !== tx.id('hex'))
254
+ throw new WERR_INVALID_OPERATION(`Hash of serialized transaction doesn't match expected txid`)
255
+ if (!(await storage.getServices()).nLockTimeIsFinal(tx)) {
256
+ throw new WERR_INVALID_OPERATION(`This transaction is not final.
257
+ Ensure that the transaction meets the rules for being a finalized
258
+ which can be found at https://wiki.bitcoinsv.io/index.php/NLocktime_and_nSequence`)
259
+ }
260
+ const txScriptOffsets = parseTxScriptOffsets(params.rawTx)
261
+ const transaction = verifyOne(
262
+ await storage.findTransactions({
263
+ partial: { userId, reference: params.reference }
264
+ })
265
+ )
266
+ if (!transaction.isOutgoing) throw new WERR_INVALID_OPERATION('isOutgoing is not true')
267
+ if (!transaction.inputBEEF) throw new WERR_INVALID_OPERATION()
268
+ const beef = Beef.fromBinary(asArray(transaction.inputBEEF))
269
+ // TODO: Could check beef validates transaction inputs...
270
+ // Transaction must have unsigned or unprocessed status
271
+ if (transaction.status !== 'unsigned' && transaction.status !== 'unprocessed')
272
+ throw new WERR_INVALID_OPERATION(`invalid transaction status ${transaction.status}`)
273
+ const transactionId = verifyId(transaction.transactionId)
274
+ const outputOutputs = await storage.findOutputs({
275
+ partial: { userId, transactionId }
276
+ })
277
+ const inputOutputs = await storage.findOutputs({
278
+ partial: { userId, spentBy: transactionId }
279
+ })
280
+
281
+ const commission = verifyOneOrNone(await storage.findCommissions({ partial: { transactionId, userId } }))
282
+ if (storage.commissionSatoshis > 0) {
283
+ // A commission is required...
284
+ if (!commission) throw new WERR_INTERNAL()
285
+ const commissionValid = tx.outputs.some(
286
+ x => x.satoshis === commission.satoshis && x.lockingScript.toHex() === asString(commission.lockingScript!)
287
+ )
288
+ if (!commissionValid)
289
+ throw new WERR_INVALID_OPERATION('Transaction did not include an output to cover service fee.')
290
+ }
291
+
292
+ const req = EntityProvenTxReq.fromTxid(params.txid, params.rawTx, transaction.inputBEEF)
293
+ req.addNotifyTransactionId(transactionId)
294
+
295
+ // "Processing" a transaction is the final step of creating a new one.
296
+ // If it is to be sent to the network directly (prior to return from processAction),
297
+ // then there is status pre-send and post-send.
298
+ // Otherwise there is no post-send status.
299
+ // Note that isSendWith trumps isNoSend, e.g. isNoSend && !isSendWith
300
+ //
301
+ // Determine what status the req and transaction should have pre- at the end of processing.
302
+ // Pre-Status (to newReq/newTx) Post-Status (to all sent reqs/txs)
303
+ // req tx req tx
304
+ // isNoSend noSend noSend
305
+ // !isNoSend && isDelayed unsent unprocessed
306
+ // !isNoSend && !isDelayed unprocessed unprocessed sending/unmined sending/unproven This is the only case that sends immediately.
307
+ let postStatus: ReqTxStatus | undefined = undefined
308
+ let status: ReqTxStatus
309
+ if (params.isNoSend && !params.isSendWith) status = { req: 'nosend', tx: 'nosend' }
310
+ else if (!params.isNoSend && params.isDelayed) status = { req: 'unsent', tx: 'unprocessed' }
311
+ else if (!params.isNoSend && !params.isDelayed) {
312
+ status = { req: 'unprocessed', tx: 'unprocessed' }
313
+ postStatus = { req: 'unmined', tx: 'unproven' }
314
+ } else throw new WERR_INTERNAL('logic error')
315
+
316
+ req.status = status.req
317
+ const vargs: ValidCommitNewTxToStorageArgs = {
318
+ reference: params.reference,
319
+ txid: params.txid,
320
+ rawTx: params.rawTx,
321
+ isSendWith: !!params.sendWith && params.sendWith.length > 0,
322
+ isDelayed: params.isDelayed,
323
+ isNoSend: params.isNoSend,
324
+ // Properties with values added during validation.
325
+ tx,
326
+ txScriptOffsets,
327
+ transactionId,
328
+ transaction,
329
+ inputOutputs,
330
+ outputOutputs,
331
+ commission,
332
+ beef,
333
+ req,
334
+ outputUpdates: [],
335
+ // update txid, status in transactions table and drop rawTransaction value
336
+ transactionUpdate: {
337
+ txid: params.txid,
338
+ rawTx: undefined,
339
+ inputBEEF: undefined,
340
+ status: status.tx
341
+ },
342
+ postStatus
343
+ }
344
+
345
+ // update outputs with txid, script offsets and lengths, drop long output scripts from outputs table
346
+ // outputs spendable will be updated for change to true and all others to !!o.tracked when tx has been broadcast
347
+ // MAX_OUTPUTSCRIPT_LENGTH is limit for scripts left in outputs table
348
+ for (const o of vargs.outputOutputs) {
349
+ const vout = verifyInteger(o.vout)
350
+ const offset = vargs.txScriptOffsets.outputs[vout]
351
+ const rawTxScript = asString(vargs.rawTx.slice(offset.offset, offset.offset + offset.length))
352
+ if (o.lockingScript && rawTxScript !== asString(o.lockingScript))
353
+ throw new WERR_INVALID_OPERATION(
354
+ `rawTx output locking script for vout ${vout} not equal to expected output script.`
355
+ )
356
+ if (tx.outputs[vout].lockingScript.toHex() !== rawTxScript)
357
+ throw new WERR_INVALID_OPERATION(
358
+ `parsed transaction output locking script for vout ${vout} not equal to expected output script.`
359
+ )
360
+ const update: Partial<TableOutput> = {
361
+ txid: vargs.txid,
362
+ spendable: true, // spendability is gated by transaction status. Remains true until the output is spent.
363
+ scriptLength: offset.length,
364
+ scriptOffset: offset.offset
365
+ }
366
+ if (offset.length > (await storage.getSettings()).maxOutputScript)
367
+ // Remove long lockingScript data from outputs table, will be read from rawTx in proven_tx or proven_tx_reqs tables.
368
+ update.lockingScript = undefined
369
+ vargs.outputUpdates.push({ id: o.outputId!, update })
370
+ }
371
+
372
+ return vargs
373
+ }
374
+
375
+ export interface CommitNewTxResults {
376
+ req: EntityProvenTxReq
377
+ log?: string
378
+ }
379
+
380
+ async function commitNewTxToStorage(
381
+ storage: StorageProvider,
382
+ userId: number,
383
+ vargs: ValidCommitNewTxToStorageArgs
384
+ ): Promise<CommitNewTxResults> {
385
+ let log = vargs.log
386
+
387
+ log = stampLog(log, `start storage commitNewTxToStorage`)
388
+
389
+ let req: EntityProvenTxReq | undefined
390
+
391
+ await storage.transaction(async trx => {
392
+ log = stampLog(log, `... storage commitNewTxToStorage storage transaction start`)
393
+
394
+ // Create initial 'nosend' proven_tx_req record to store signed, valid rawTx and input beef
395
+ req = await vargs.req.insertOrMerge(storage, trx)
396
+
397
+ log = stampLog(log, `... storage commitNewTxToStorage req inserted`)
398
+
399
+ for (const ou of vargs.outputUpdates) {
400
+ await storage.updateOutput(ou.id, ou.update, trx)
401
+ }
402
+
403
+ log = stampLog(log, `... storage commitNewTxToStorage outputs updated`)
404
+
405
+ await storage.updateTransaction(vargs.transactionId, vargs.transactionUpdate, trx)
406
+
407
+ log = stampLog(log, `... storage commitNewTxToStorage storage transaction end`)
408
+ })
409
+
410
+ log = stampLog(log, `... storage commitNewTxToStorage storage transaction await done`)
411
+
412
+ const r: CommitNewTxResults = {
413
+ req: verifyTruthy(req),
414
+ log
415
+ }
416
+
417
+ log = stampLog(log, `end storage commitNewTxToStorage`)
418
+
419
+ return r
420
+ }
@@ -0,0 +1,251 @@
1
+ import { Beef } from '@bsv/sdk'
2
+ import { Knex } from 'knex'
3
+ import { StorageKnex } from '../StorageKnex'
4
+ import { PurgeParams, PurgeResults, StorageGetBeefOptions, TrxToken } from '../../sdk/WalletStorage.interfaces'
5
+ import { WalletError } from '../../sdk/WalletError'
6
+ import { TableTransaction } from '../schema/tables/TableTransaction'
7
+ import { TableOutput } from '../schema/tables/TableOutput'
8
+ import { TableOutputTagMap } from '../schema/tables/TableOutputTagMap'
9
+ import { TableTxLabelMap } from '../schema/tables/TableTxLabelMap'
10
+ import { TableCommission } from '../schema/tables/TableCommission'
11
+
12
+ export async function purgeData(storage: StorageKnex, params: PurgeParams, trx?: TrxToken): Promise<PurgeResults> {
13
+ const r: PurgeResults = { count: 0, log: '' }
14
+ const defaultAge = 1000 * 60 * 60 * 24 * 14
15
+
16
+ const runPurgeQuery = async <T extends object>(pq: PurgeQuery): Promise<void> => {
17
+ try {
18
+ pq.sql = pq.q.toString()
19
+ const count = await pq.q
20
+ if (count > 0) {
21
+ r.count += count
22
+ r.log += `${count} ${pq.log}\n`
23
+ }
24
+ } catch (eu: unknown) {
25
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
26
+ const e = WalletError.fromUnknown(eu)
27
+ throw eu
28
+ }
29
+ }
30
+
31
+ if (params.purgeCompleted) {
32
+ const age = params.purgeCompletedAge || defaultAge
33
+ const before = toSqlWhereDate(new Date(Date.now() - age))
34
+
35
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
36
+ const qs: PurgeQuery[] = []
37
+
38
+ // select * from transactions where updated_at < '2024-08-20' and status = 'completed' and not provenTxId is null and (not truncatedExternalInputs is null or not beef is null or not rawTx is null)
39
+ qs.push({
40
+ log: 'conpleted transactions purged of transient data',
41
+ q: storage
42
+ .toDb(trx)('transactions')
43
+ .update({
44
+ inputBEEF: null,
45
+ rawTx: null
46
+ })
47
+ .where('updated_at', '<', before)
48
+ .where('status', 'completed')
49
+ .whereNotNull('provenTxId')
50
+ .where(function () {
51
+ this.orWhereNotNull('inputBEEF')
52
+ this.orWhereNotNull('rawTx')
53
+ })
54
+ })
55
+
56
+ const completedReqs = await storage
57
+ .toDb(trx)<{ provenTxReqId: number }>('proven_tx_reqs')
58
+ .select('provenTxReqId')
59
+ .where('updated_at', '<', before)
60
+ .where('status', 'completed')
61
+ .whereNotNull('provenTxId')
62
+ .where('notified', 1)
63
+ const completedReqIds = completedReqs.map(o => o.provenTxReqId)
64
+
65
+ if (completedReqIds.length > 0) {
66
+ qs.push({
67
+ log: 'completed proven_tx_reqs deleted',
68
+ q: storage.toDb(trx)('proven_tx_reqs').whereIn('provenTxReqId', completedReqIds).delete()
69
+ })
70
+ }
71
+
72
+ for (const q of qs) await runPurgeQuery(q)
73
+ }
74
+
75
+ if (params.purgeFailed) {
76
+ const age = params.purgeFailedAge || defaultAge
77
+ const before = toSqlWhereDate(new Date(Date.now() - age))
78
+
79
+ const qs: PurgeQuery[] = []
80
+
81
+ const failedTxsQ = storage
82
+ .toDb(trx)<{ transactionId: number }>('transactions')
83
+ .select('transactionId')
84
+ .where('updated_at', '<', before)
85
+ .where('status', 'failed')
86
+ const txs = await failedTxsQ
87
+ const failedTxIds = txs.map(tx => tx.transactionId)
88
+
89
+ await deleteTransactions(failedTxIds, qs, 'failed', true)
90
+
91
+ const invalidReqs = await storage
92
+ .toDb(trx)<{ provenTxReqId: number }>('proven_tx_reqs')
93
+ .select('provenTxReqId')
94
+ .where('updated_at', '<', before)
95
+ .where('status', 'invalid')
96
+ const invalidReqIds = invalidReqs.map(o => o.provenTxReqId)
97
+ if (invalidReqIds.length > 0)
98
+ qs.push({
99
+ log: 'invalid proven_tx_reqs deleted',
100
+ q: storage.toDb(trx)('proven_tx_reqs').whereIn('provenTxReqId', invalidReqIds).delete()
101
+ })
102
+
103
+ const doubleSpendReqs = await storage
104
+ .toDb(trx)<{ provenTxReqId: number }>('proven_tx_reqs')
105
+ .select('provenTxReqId')
106
+ .where('updated_at', '<', before)
107
+ .where('status', 'doubleSpend')
108
+ const doubleSpendReqIds = doubleSpendReqs.map(o => o.provenTxReqId)
109
+ if (doubleSpendReqIds.length > 0)
110
+ qs.push({
111
+ log: 'doubleSpend proven_tx_reqs deleted',
112
+ q: storage.toDb(trx)('proven_tx_reqs').whereIn('provenTxReqId', doubleSpendReqIds).delete()
113
+ })
114
+
115
+ for (const q of qs) await runPurgeQuery(q)
116
+ }
117
+
118
+ if (params.purgeSpent) {
119
+ const age = params.purgeSpentAge || defaultAge
120
+ const before = toSqlWhereDate(new Date(Date.now() - age))
121
+
122
+ const beef = new Beef()
123
+ const utxos = await storage.findOutputs({
124
+ partial: { spendable: true },
125
+ txStatus: ['sending', 'unproven', 'completed', 'nosend']
126
+ })
127
+ for (const utxo of utxos) {
128
+ // Figure out all the txids required to prove the validity of this utxo and merge proofs into beef.
129
+ const options: StorageGetBeefOptions = {
130
+ mergeToBeef: beef,
131
+ ignoreServices: true
132
+ }
133
+ if (utxo.txid) await storage.getBeefForTransaction(utxo.txid, options)
134
+ }
135
+ const proofTxids: Record<string, boolean> = {}
136
+ for (const btx of beef.txs) proofTxids[btx.txid] = true
137
+
138
+ let qs: PurgeQuery[] = []
139
+
140
+ const spentTxsQ = storage
141
+ .toDb(trx)<TableTransaction>('transactions')
142
+ .where('updated_at', '<', before)
143
+ .where('status', 'completed')
144
+ .whereRaw(
145
+ `not exists(select outputId from outputs as o where o.transactionId = transactions.transactionId and o.spendable = 1)`
146
+ )
147
+ const txs: TableTransaction[] = await spentTxsQ
148
+ // Save any spent txid still needed to prove a utxo:
149
+ const nptxs = txs.filter(t => !proofTxids[t.txid || ''])
150
+ let spentTxIds = nptxs.map(tx => tx.transactionId)
151
+
152
+ if (spentTxIds.length > 0) {
153
+ const update: Partial<TableOutput> = {
154
+ spentBy: null as unknown as undefined
155
+ }
156
+ qs.push({
157
+ log: 'spent outputs no longer tracked by spentBy',
158
+ q: storage
159
+ .toDb(trx)<TableOutput>('outputs')
160
+ .update(storage.validatePartialForUpdate(update, undefined, ['spendable']))
161
+ .where('spendable', false)
162
+ .whereIn('spentBy', spentTxIds)
163
+ })
164
+
165
+ await deleteTransactions(spentTxIds, qs, 'spent', false)
166
+
167
+ for (const q of qs) await runPurgeQuery(q)
168
+ }
169
+ }
170
+
171
+ // Delete proven_txs no longer referenced by remaining transactions.
172
+ const qs: PurgeQuery[] = []
173
+ qs.push({
174
+ log: 'orphan proven_txs deleted',
175
+ q: storage
176
+ .toDb(trx)('proven_txs')
177
+ .whereRaw(
178
+ `not exists(select * from transactions as t where t.txid = proven_txs.txid or t.provenTxId = proven_txs.provenTxId)`
179
+ )
180
+ .whereRaw(
181
+ `not exists(select * from proven_tx_reqs as r where r.txid = proven_txs.txid or r.provenTxId = proven_txs.provenTxId)`
182
+ )
183
+ .delete()
184
+ })
185
+ for (const q of qs) await runPurgeQuery(q)
186
+
187
+ return r
188
+
189
+ async function deleteTransactions(
190
+ transactionIds: number[],
191
+ qs: PurgeQuery[],
192
+ reason: string,
193
+ markNotSpentBy: boolean
194
+ ) {
195
+ if (transactionIds.length > 0) {
196
+ const outputs = await storage
197
+ .toDb(trx)<{ outputId: number }>('outputs')
198
+ .select('outputId')
199
+ .whereIn('transactionId', transactionIds)
200
+ const outputIds = outputs.map(o => o.outputId)
201
+ if (outputIds.length > 0) {
202
+ qs.push({
203
+ log: `${reason} output_tags_map deleted`,
204
+ q: storage.toDb(trx)<TableOutputTagMap>('output_tags_map').whereIn('outputId', outputIds).delete()
205
+ })
206
+ qs.push({
207
+ log: `${reason} outputs deleted`,
208
+ q: storage.toDb(trx)<TableOutput>('outputs').whereIn('outputId', outputIds).delete()
209
+ })
210
+ }
211
+
212
+ qs.push({
213
+ log: `${reason} tx_labels_map deleted`,
214
+ q: storage.toDb(trx)<TableTxLabelMap>('tx_labels_map').whereIn('transactionId', transactionIds).delete()
215
+ })
216
+
217
+ qs.push({
218
+ log: `${reason} commissions deleted`,
219
+ q: storage.toDb(trx)<TableCommission>('commissions').whereIn('transactionId', transactionIds).delete()
220
+ })
221
+
222
+ if (markNotSpentBy) {
223
+ qs.push({
224
+ log: 'unspent outputs updated to spendable',
225
+ q: storage
226
+ .toDb(trx)<TableOutput>('outputs')
227
+ .update({ spendable: true, spentBy: null as unknown as undefined })
228
+ .whereIn('spentBy', transactionIds)
229
+ })
230
+ }
231
+
232
+ qs.push({
233
+ log: `${reason} transactions deleted`,
234
+ q: storage.toDb(trx)<TableTransaction>('transactions').whereIn('transactionId', transactionIds).delete()
235
+ })
236
+ }
237
+ }
238
+ }
239
+
240
+ interface PurgeQuery {
241
+ q: Knex.QueryBuilder<any, number>
242
+ sql?: string
243
+ log: string
244
+ }
245
+
246
+ function toSqlWhereDate(d: Date): string {
247
+ let s = d.toISOString()
248
+ s = s.replace('T', ' ')
249
+ s = s.replace('Z', '')
250
+ return s
251
+ }
@@ -0,0 +1,10 @@
1
+ import { Beef } from '@bsv/sdk'
2
+ import { Knex } from 'knex'
3
+ import { StorageIdb } from '../StorageIdb'
4
+ import { PurgeParams, PurgeResults, TrxToken } from '../../sdk/WalletStorage.interfaces'
5
+
6
+ export async function purgeDataIdb(storage: StorageIdb, params: PurgeParams, trx?: TrxToken): Promise<PurgeResults> {
7
+ const r: PurgeResults = { count: 0, log: '' }
8
+ // TODO: implement purgeDataIdb
9
+ return r
10
+ }