@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.
- package/.claude/settings.local.json +10 -0
- package/.env.template +22 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +40 -0
- package/.github/ISSUE_TEMPLATE/discussion.md +24 -0
- package/.github/pull_request_template.md +22 -0
- package/.github/workflows/push.yaml +145 -0
- package/.prettierrc +10 -0
- package/CHANGELOG.md +280 -0
- package/CONTRIBUTING.md +89 -0
- package/README.md +43 -0
- package/docs/README.md +85 -0
- package/docs/client.md +19627 -0
- package/docs/monitor.md +953 -0
- package/docs/open-rpc/index.html +46 -0
- package/docs/services.md +6377 -0
- package/docs/setup.md +1268 -0
- package/docs/storage.md +5367 -0
- package/docs/wallet.md +19626 -0
- package/jest.config.ts +25 -0
- package/license.md +28 -0
- package/out/tsconfig.all.tsbuildinfo +1 -0
- package/package.json +63 -0
- package/src/CWIStyleWalletManager.ts +1999 -0
- package/src/Setup.ts +579 -0
- package/src/SetupClient.ts +322 -0
- package/src/SetupWallet.ts +108 -0
- package/src/SimpleWalletManager.ts +526 -0
- package/src/Wallet.ts +1169 -0
- package/src/WalletAuthenticationManager.ts +153 -0
- package/src/WalletLogger.ts +213 -0
- package/src/WalletPermissionsManager.ts +3660 -0
- package/src/WalletSettingsManager.ts +114 -0
- package/src/__tests/CWIStyleWalletManager.test.d.ts.map +1 -0
- package/src/__tests/CWIStyleWalletManager.test.js.map +1 -0
- package/src/__tests/CWIStyleWalletManager.test.ts +675 -0
- package/src/__tests/WalletPermissionsManager.callbacks.test.ts +323 -0
- package/src/__tests/WalletPermissionsManager.checks.test.ts +844 -0
- package/src/__tests/WalletPermissionsManager.encryption.test.ts +412 -0
- package/src/__tests/WalletPermissionsManager.fixtures.ts +307 -0
- package/src/__tests/WalletPermissionsManager.flows.test.ts +462 -0
- package/src/__tests/WalletPermissionsManager.initialization.test.ts +300 -0
- package/src/__tests/WalletPermissionsManager.pmodules.test.ts +798 -0
- package/src/__tests/WalletPermissionsManager.proxying.test.ts +724 -0
- package/src/__tests/WalletPermissionsManager.tokens.test.ts +503 -0
- package/src/index.all.ts +27 -0
- package/src/index.client.ts +25 -0
- package/src/index.mobile.ts +21 -0
- package/src/index.ts +1 -0
- package/src/monitor/Monitor.ts +412 -0
- package/src/monitor/MonitorDaemon.ts +188 -0
- package/src/monitor/README.md +3 -0
- package/src/monitor/__test/MonitorDaemon.man.test.ts +45 -0
- package/src/monitor/tasks/TaskCheckForProofs.ts +243 -0
- package/src/monitor/tasks/TaskCheckNoSends.ts +73 -0
- package/src/monitor/tasks/TaskClock.ts +33 -0
- package/src/monitor/tasks/TaskFailAbandoned.ts +54 -0
- package/src/monitor/tasks/TaskMonitorCallHistory.ts +26 -0
- package/src/monitor/tasks/TaskNewHeader.ts +93 -0
- package/src/monitor/tasks/TaskPurge.ts +68 -0
- package/src/monitor/tasks/TaskReorg.ts +89 -0
- package/src/monitor/tasks/TaskReviewStatus.ts +48 -0
- package/src/monitor/tasks/TaskSendWaiting.ts +122 -0
- package/src/monitor/tasks/TaskSyncWhenIdle.ts +26 -0
- package/src/monitor/tasks/TaskUnFail.ts +151 -0
- package/src/monitor/tasks/WalletMonitorTask.ts +47 -0
- package/src/sdk/CertOpsWallet.ts +18 -0
- package/src/sdk/PrivilegedKeyManager.ts +372 -0
- package/src/sdk/README.md +13 -0
- package/src/sdk/WERR_errors.ts +234 -0
- package/src/sdk/WalletError.ts +170 -0
- package/src/sdk/WalletErrorFromJson.ts +80 -0
- package/src/sdk/WalletServices.interfaces.ts +700 -0
- package/src/sdk/WalletSigner.interfaces.ts +11 -0
- package/src/sdk/WalletStorage.interfaces.ts +606 -0
- package/src/sdk/__test/CertificateLifeCycle.test.ts +131 -0
- package/src/sdk/__test/PrivilegedKeyManager.test.ts +738 -0
- package/src/sdk/__test/WalletError.test.ts +318 -0
- package/src/sdk/__test/validationHelpers.test.ts +21 -0
- package/src/sdk/index.ts +10 -0
- package/src/sdk/types.ts +226 -0
- package/src/services/README.md +11 -0
- package/src/services/ServiceCollection.ts +248 -0
- package/src/services/Services.ts +603 -0
- package/src/services/__tests/ARC.man.test.ts +123 -0
- package/src/services/__tests/ARC.timeout.man.test.ts +79 -0
- package/src/services/__tests/ArcGorillaPool.man.test.ts +108 -0
- package/src/services/__tests/arcServices.test.ts +8 -0
- package/src/services/__tests/bitrails.test.ts +56 -0
- package/src/services/__tests/getMerklePath.test.ts +15 -0
- package/src/services/__tests/getRawTx.test.ts +13 -0
- package/src/services/__tests/postBeef.test.ts +104 -0
- package/src/services/__tests/verifyBeef.test.ts +50 -0
- package/src/services/chaintracker/BHServiceClient.ts +212 -0
- package/src/services/chaintracker/ChaintracksChainTracker.ts +71 -0
- package/src/services/chaintracker/__tests/ChaintracksChainTracker.test.ts +33 -0
- package/src/services/chaintracker/__tests/ChaintracksServiceClient.test.ts +29 -0
- package/src/services/chaintracker/chaintracks/Api/BlockHeaderApi.ts +72 -0
- package/src/services/chaintracker/chaintracks/Api/BulkIngestorApi.ts +83 -0
- package/src/services/chaintracker/chaintracks/Api/BulkStorageApi.ts +92 -0
- package/src/services/chaintracker/chaintracks/Api/ChaintracksApi.ts +64 -0
- package/src/services/chaintracker/chaintracks/Api/ChaintracksClientApi.ts +189 -0
- package/src/services/chaintracker/chaintracks/Api/ChaintracksFetchApi.ts +18 -0
- package/src/services/chaintracker/chaintracks/Api/ChaintracksFsApi.ts +58 -0
- package/src/services/chaintracker/chaintracks/Api/ChaintracksStorageApi.ts +386 -0
- package/src/services/chaintracker/chaintracks/Api/LiveIngestorApi.ts +25 -0
- package/src/services/chaintracker/chaintracks/Chaintracks.ts +609 -0
- package/src/services/chaintracker/chaintracks/ChaintracksService.ts +199 -0
- package/src/services/chaintracker/chaintracks/ChaintracksServiceClient.ts +154 -0
- package/src/services/chaintracker/chaintracks/Ingest/BulkIngestorBase.ts +176 -0
- package/src/services/chaintracker/chaintracks/Ingest/BulkIngestorCDN.ts +174 -0
- package/src/services/chaintracker/chaintracks/Ingest/BulkIngestorCDNBabbage.ts +18 -0
- package/src/services/chaintracker/chaintracks/Ingest/BulkIngestorWhatsOnChainCdn.ts +113 -0
- package/src/services/chaintracker/chaintracks/Ingest/BulkIngestorWhatsOnChainWs.ts +81 -0
- package/src/services/chaintracker/chaintracks/Ingest/LiveIngestorBase.ts +86 -0
- package/src/services/chaintracker/chaintracks/Ingest/LiveIngestorTeranodeP2P.ts +59 -0
- package/src/services/chaintracker/chaintracks/Ingest/LiveIngestorWhatsOnChainPoll.ts +104 -0
- package/src/services/chaintracker/chaintracks/Ingest/LiveIngestorWhatsOnChainWs.ts +66 -0
- package/src/services/chaintracker/chaintracks/Ingest/WhatsOnChainIngestorWs.ts +566 -0
- package/src/services/chaintracker/chaintracks/Ingest/WhatsOnChainServices.ts +219 -0
- package/src/services/chaintracker/chaintracks/Ingest/__tests/BulkIngestorCDNBabbage.test.ts +54 -0
- package/src/services/chaintracker/chaintracks/Ingest/__tests/LiveIngestorWhatsOnChainPoll.test.ts +33 -0
- package/src/services/chaintracker/chaintracks/Ingest/__tests/WhatsOnChainServices.test.ts +124 -0
- package/src/services/chaintracker/chaintracks/Storage/BulkStorageBase.ts +92 -0
- package/src/services/chaintracker/chaintracks/Storage/ChaintracksKnexMigrations.ts +104 -0
- package/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageBase.ts +382 -0
- package/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageIdb.ts +574 -0
- package/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageKnex.ts +438 -0
- package/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageMemory.ts +29 -0
- package/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageNoDb.ts +304 -0
- package/src/services/chaintracker/chaintracks/Storage/__tests/ChaintracksStorageIdb.test.ts +102 -0
- package/src/services/chaintracker/chaintracks/Storage/__tests/ChaintracksStorageKnex.test.ts +45 -0
- package/src/services/chaintracker/chaintracks/__tests/Chaintracks.test.ts +77 -0
- package/src/services/chaintracker/chaintracks/__tests/ChaintracksClientApi.test.ts +192 -0
- package/src/services/chaintracker/chaintracks/__tests/LocalCdnServer.ts +75 -0
- package/src/services/chaintracker/chaintracks/__tests/createIdbChaintracks.test.ts +62 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest349/mainNetBlockHeaders.json +1 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest349/mainNet_0.headers +0 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest349/mainNet_1.headers +0 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest349/mainNet_2.headers +0 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest349/mainNet_3.headers +0 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest379/mainNetBlockHeaders.json +1 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest379/mainNet_0.headers +0 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest379/mainNet_1.headers +0 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest379/mainNet_2.headers +0 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest379/mainNet_3.headers +0 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest399/mainNetBlockHeaders.json +1 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest399/mainNet_0.headers +0 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest399/mainNet_1.headers +0 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest399/mainNet_2.headers +0 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest399/mainNet_3.headers +0 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest402/mainNetBlockHeaders.json +1 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest402/mainNet_0.headers +0 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest402/mainNet_1.headers +0 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest402/mainNet_2.headers +0 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest402/mainNet_3.headers +0 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest402/mainNet_4.headers +0 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest499/mainNetBlockHeaders.json +1 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest499/mainNet_0.headers +0 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest499/mainNet_1.headers +0 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest499/mainNet_2.headers +0 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest499/mainNet_3.headers +0 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest499/mainNet_4.headers +0 -0
- package/src/services/chaintracker/chaintracks/createDefaultIdbChaintracksOptions.ts +92 -0
- package/src/services/chaintracker/chaintracks/createDefaultKnexChaintracksOptions.ts +111 -0
- package/src/services/chaintracker/chaintracks/createDefaultNoDbChaintracksOptions.ts +91 -0
- package/src/services/chaintracker/chaintracks/createIdbChaintracks.ts +60 -0
- package/src/services/chaintracker/chaintracks/createKnexChaintracks.ts +65 -0
- package/src/services/chaintracker/chaintracks/createNoDbChaintracks.ts +60 -0
- package/src/services/chaintracker/chaintracks/index.all.ts +12 -0
- package/src/services/chaintracker/chaintracks/index.client.ts +4 -0
- package/src/services/chaintracker/chaintracks/index.mobile.ts +37 -0
- package/src/services/chaintracker/chaintracks/util/BulkFileDataManager.ts +975 -0
- package/src/services/chaintracker/chaintracks/util/BulkFileDataReader.ts +60 -0
- package/src/services/chaintracker/chaintracks/util/BulkFilesReader.ts +336 -0
- package/src/services/chaintracker/chaintracks/util/BulkHeaderFile.ts +247 -0
- package/src/services/chaintracker/chaintracks/util/ChaintracksFetch.ts +69 -0
- package/src/services/chaintracker/chaintracks/util/ChaintracksFs.ts +141 -0
- package/src/services/chaintracker/chaintracks/util/HeightRange.ts +153 -0
- package/src/services/chaintracker/chaintracks/util/SingleWriterMultiReaderLock.ts +76 -0
- package/src/services/chaintracker/chaintracks/util/__tests/BulkFileDataManager.test.ts +304 -0
- package/src/services/chaintracker/chaintracks/util/__tests/ChaintracksFetch.test.ts +60 -0
- package/src/services/chaintracker/chaintracks/util/__tests/HeightRange.test.ts +67 -0
- package/src/services/chaintracker/chaintracks/util/__tests/SingleWriterMultiReaderLock.test.ts +49 -0
- package/src/services/chaintracker/chaintracks/util/blockHeaderUtilities.ts +573 -0
- package/src/services/chaintracker/chaintracks/util/dirtyHashes.ts +29 -0
- package/src/services/chaintracker/chaintracks/util/validBulkHeaderFilesByFileHash.ts +432 -0
- package/src/services/chaintracker/index.all.ts +4 -0
- package/src/services/chaintracker/index.client.ts +4 -0
- package/src/services/chaintracker/index.mobile.ts +4 -0
- package/src/services/createDefaultWalletServicesOptions.ts +77 -0
- package/src/services/index.ts +1 -0
- package/src/services/processingErrors/arcSuccessError.json +76 -0
- package/src/services/providers/ARC.ts +350 -0
- package/src/services/providers/Bitails.ts +256 -0
- package/src/services/providers/SdkWhatsOnChain.ts +83 -0
- package/src/services/providers/WhatsOnChain.ts +883 -0
- package/src/services/providers/__tests/WhatsOnChain.test.ts +242 -0
- package/src/services/providers/__tests/exchangeRates.test.ts +18 -0
- package/src/services/providers/exchangeRates.ts +265 -0
- package/src/services/providers/getBeefForTxid.ts +369 -0
- package/src/signer/README.md +5 -0
- package/src/signer/WalletSigner.ts +17 -0
- package/src/signer/methods/acquireDirectCertificate.ts +52 -0
- package/src/signer/methods/buildSignableTransaction.ts +183 -0
- package/src/signer/methods/completeSignedTransaction.ts +117 -0
- package/src/signer/methods/createAction.ts +172 -0
- package/src/signer/methods/internalizeAction.ts +106 -0
- package/src/signer/methods/proveCertificate.ts +43 -0
- package/src/signer/methods/signAction.ts +54 -0
- package/src/storage/README.md +14 -0
- package/src/storage/StorageIdb.ts +2304 -0
- package/src/storage/StorageKnex.ts +1425 -0
- package/src/storage/StorageProvider.ts +810 -0
- package/src/storage/StorageReader.ts +194 -0
- package/src/storage/StorageReaderWriter.ts +432 -0
- package/src/storage/StorageSyncReader.ts +34 -0
- package/src/storage/WalletStorageManager.ts +943 -0
- package/src/storage/__test/StorageIdb.test.ts +43 -0
- package/src/storage/__test/WalletStorageManager.test.ts +275 -0
- package/src/storage/__test/adminStats.man.test.ts +89 -0
- package/src/storage/__test/getBeefForTransaction.test.ts +385 -0
- package/src/storage/index.all.ts +11 -0
- package/src/storage/index.client.ts +7 -0
- package/src/storage/index.mobile.ts +6 -0
- package/src/storage/methods/ListActionsSpecOp.ts +70 -0
- package/src/storage/methods/ListOutputsSpecOp.ts +129 -0
- package/src/storage/methods/__test/GenerateChange/generateChangeSdk.test.ts +1057 -0
- package/src/storage/methods/__test/GenerateChange/randomValsUsed1.ts +20 -0
- package/src/storage/methods/__test/offsetKey.test.ts +274 -0
- package/src/storage/methods/attemptToPostReqsToNetwork.ts +389 -0
- package/src/storage/methods/createAction.ts +947 -0
- package/src/storage/methods/generateChange.ts +556 -0
- package/src/storage/methods/getBeefForTransaction.ts +139 -0
- package/src/storage/methods/getSyncChunk.ts +293 -0
- package/src/storage/methods/internalizeAction.ts +562 -0
- package/src/storage/methods/listActionsIdb.ts +183 -0
- package/src/storage/methods/listActionsKnex.ts +226 -0
- package/src/storage/methods/listCertificates.ts +73 -0
- package/src/storage/methods/listOutputsIdb.ts +203 -0
- package/src/storage/methods/listOutputsKnex.ts +263 -0
- package/src/storage/methods/offsetKey.ts +89 -0
- package/src/storage/methods/processAction.ts +420 -0
- package/src/storage/methods/purgeData.ts +251 -0
- package/src/storage/methods/purgeDataIdb.ts +10 -0
- package/src/storage/methods/reviewStatus.ts +101 -0
- package/src/storage/methods/reviewStatusIdb.ts +43 -0
- package/src/storage/methods/utils.Buffer.ts +33 -0
- package/src/storage/methods/utils.ts +56 -0
- package/src/storage/remoting/StorageClient.ts +567 -0
- package/src/storage/remoting/StorageMobile.ts +544 -0
- package/src/storage/remoting/StorageServer.ts +291 -0
- package/src/storage/remoting/__test/StorageClient.test.ts +113 -0
- package/src/storage/schema/KnexMigrations.ts +489 -0
- package/src/storage/schema/StorageIdbSchema.ts +150 -0
- package/src/storage/schema/entities/EntityBase.ts +210 -0
- package/src/storage/schema/entities/EntityCertificate.ts +188 -0
- package/src/storage/schema/entities/EntityCertificateField.ts +136 -0
- package/src/storage/schema/entities/EntityCommission.ts +148 -0
- package/src/storage/schema/entities/EntityOutput.ts +290 -0
- package/src/storage/schema/entities/EntityOutputBasket.ts +153 -0
- package/src/storage/schema/entities/EntityOutputTag.ts +121 -0
- package/src/storage/schema/entities/EntityOutputTagMap.ts +123 -0
- package/src/storage/schema/entities/EntityProvenTx.ts +319 -0
- package/src/storage/schema/entities/EntityProvenTxReq.ts +580 -0
- package/src/storage/schema/entities/EntitySyncState.ts +389 -0
- package/src/storage/schema/entities/EntityTransaction.ts +306 -0
- package/src/storage/schema/entities/EntityTxLabel.ts +121 -0
- package/src/storage/schema/entities/EntityTxLabelMap.ts +123 -0
- package/src/storage/schema/entities/EntityUser.ts +112 -0
- package/src/storage/schema/entities/MergeEntity.ts +73 -0
- package/src/storage/schema/entities/__tests/CertificateFieldTests.test.ts +353 -0
- package/src/storage/schema/entities/__tests/CertificateTests.test.ts +354 -0
- package/src/storage/schema/entities/__tests/CommissionTests.test.ts +371 -0
- package/src/storage/schema/entities/__tests/OutputBasketTests.test.ts +278 -0
- package/src/storage/schema/entities/__tests/OutputTagMapTests.test.ts +242 -0
- package/src/storage/schema/entities/__tests/OutputTagTests.test.ts +288 -0
- package/src/storage/schema/entities/__tests/OutputTests.test.ts +464 -0
- package/src/storage/schema/entities/__tests/ProvenTxReqTests.test.ts +340 -0
- package/src/storage/schema/entities/__tests/ProvenTxTests.test.ts +504 -0
- package/src/storage/schema/entities/__tests/SyncStateTests.test.ts +288 -0
- package/src/storage/schema/entities/__tests/TransactionTests.test.ts +604 -0
- package/src/storage/schema/entities/__tests/TxLabelMapTests.test.ts +361 -0
- package/src/storage/schema/entities/__tests/TxLabelTests.test.ts +198 -0
- package/src/storage/schema/entities/__tests/stampLogTests.test.ts +90 -0
- package/src/storage/schema/entities/__tests/usersTests.test.ts +340 -0
- package/src/storage/schema/entities/index.ts +16 -0
- package/src/storage/schema/tables/TableCertificate.ts +21 -0
- package/src/storage/schema/tables/TableCertificateField.ts +12 -0
- package/src/storage/schema/tables/TableCommission.ts +13 -0
- package/src/storage/schema/tables/TableMonitorEvent.ts +9 -0
- package/src/storage/schema/tables/TableOutput.ts +64 -0
- package/src/storage/schema/tables/TableOutputBasket.ts +12 -0
- package/src/storage/schema/tables/TableOutputTag.ts +10 -0
- package/src/storage/schema/tables/TableOutputTagMap.ts +9 -0
- package/src/storage/schema/tables/TableProvenTx.ts +14 -0
- package/src/storage/schema/tables/TableProvenTxReq.ts +65 -0
- package/src/storage/schema/tables/TableSettings.ts +17 -0
- package/src/storage/schema/tables/TableSyncState.ts +18 -0
- package/src/storage/schema/tables/TableTransaction.ts +54 -0
- package/src/storage/schema/tables/TableTxLabel.ts +10 -0
- package/src/storage/schema/tables/TableTxLabelMap.ts +9 -0
- package/src/storage/schema/tables/TableUser.ts +16 -0
- package/src/storage/schema/tables/index.ts +16 -0
- package/src/storage/sync/StorageMySQLDojoReader.ts +696 -0
- package/src/storage/sync/index.ts +1 -0
- package/src/utility/Format.ts +133 -0
- package/src/utility/README.md +3 -0
- package/src/utility/ReaderUint8Array.ts +187 -0
- package/src/utility/ScriptTemplateBRC29.ts +73 -0
- package/src/utility/__tests/utilityHelpers.noBuffer.test.ts +109 -0
- package/src/utility/aggregateResults.ts +68 -0
- package/src/utility/identityUtils.ts +159 -0
- package/src/utility/index.all.ts +7 -0
- package/src/utility/index.client.ts +7 -0
- package/src/utility/parseTxScriptOffsets.ts +29 -0
- package/src/utility/stampLog.ts +69 -0
- package/src/utility/tscProofToMerklePath.ts +48 -0
- package/src/utility/utilityHelpers.buffer.ts +34 -0
- package/src/utility/utilityHelpers.noBuffer.ts +60 -0
- package/src/utility/utilityHelpers.ts +275 -0
- package/src/wab-client/WABClient.ts +94 -0
- package/src/wab-client/__tests/WABClient.man.test.ts +59 -0
- package/src/wab-client/auth-method-interactors/AuthMethodInteractor.ts +47 -0
- package/src/wab-client/auth-method-interactors/DevConsoleInteractor.ts +73 -0
- package/src/wab-client/auth-method-interactors/PersonaIDInteractor.ts +35 -0
- package/src/wab-client/auth-method-interactors/TwilioPhoneInteractor.ts +72 -0
- package/syncVersions.js +71 -0
- package/test/Wallet/StorageClient/storageClient.man.test.ts +75 -0
- package/test/Wallet/action/abortAction.test.ts +47 -0
- package/test/Wallet/action/createAction.test.ts +299 -0
- package/test/Wallet/action/createAction2.test.ts +1273 -0
- package/test/Wallet/action/createActionToGenerateBeefs.man.test.ts +293 -0
- package/test/Wallet/action/internalizeAction.a.test.ts +286 -0
- package/test/Wallet/action/internalizeAction.test.ts +682 -0
- package/test/Wallet/action/relinquishOutput.test.ts +37 -0
- package/test/Wallet/certificate/acquireCertificate.test.ts +298 -0
- package/test/Wallet/certificate/listCertificates.test.ts +346 -0
- package/test/Wallet/construct/Wallet.constructor.test.ts +57 -0
- package/test/Wallet/get/getHeaderForHeight.test.ts +82 -0
- package/test/Wallet/get/getHeight.test.ts +52 -0
- package/test/Wallet/get/getKnownTxids.test.ts +86 -0
- package/test/Wallet/get/getNetwork.test.ts +27 -0
- package/test/Wallet/get/getVersion.test.ts +27 -0
- package/test/Wallet/list/listActions.test.ts +279 -0
- package/test/Wallet/list/listActions2.test.ts +1381 -0
- package/test/Wallet/list/listCertificates.test.ts +118 -0
- package/test/Wallet/list/listOutputs.test.ts +447 -0
- package/test/Wallet/live/walletLive.man.test.ts +521 -0
- package/test/Wallet/local/localWallet.man.test.ts +93 -0
- package/test/Wallet/local/localWallet2.man.test.ts +277 -0
- package/test/Wallet/signAction/mountaintop.man.test.ts +130 -0
- package/test/Wallet/specOps/specOps.man.test.ts +220 -0
- package/test/Wallet/support/janitor.man.test.ts +40 -0
- package/test/Wallet/support/operations.man.test.ts +407 -0
- package/test/Wallet/support/reqErrorReview.2025.05.06.man.test.ts +347 -0
- package/test/Wallet/sync/Wallet.sync.test.ts +215 -0
- package/test/Wallet/sync/Wallet.updateWalletLegacyTestData.man.test.ts +203 -0
- package/test/Wallet/sync/setActive.test.ts +170 -0
- package/test/WalletClient/LocalKVStore.man.test.ts +114 -0
- package/test/WalletClient/WERR.man.test.ts +35 -0
- package/test/bsv-ts-sdk/LocalKVStore.test.ts +102 -0
- package/test/checkDB.ts +57 -0
- package/test/checkdb +0 -0
- package/test/examples/backup.man.test.ts +59 -0
- package/test/examples/pushdrop.test.ts +282 -0
- package/test/monitor/Monitor.test.ts +620 -0
- package/test/services/Services.test.ts +263 -0
- package/test/storage/KnexMigrations.test.ts +86 -0
- package/test/storage/StorageMySQLDojoReader.man.test.ts +60 -0
- package/test/storage/count.test.ts +177 -0
- package/test/storage/find.test.ts +195 -0
- package/test/storage/findLegacy.test.ts +67 -0
- package/test/storage/idb/allocateChange.test.ts +251 -0
- package/test/storage/idb/count.test.ts +158 -0
- package/test/storage/idb/find.test.ts +177 -0
- package/test/storage/idb/idbSpeed.test.ts +36 -0
- package/test/storage/idb/insert.test.ts +268 -0
- package/test/storage/idb/transactionAbort.test.ts +108 -0
- package/test/storage/idb/update.test.ts +999 -0
- package/test/storage/insert.test.ts +278 -0
- package/test/storage/update.test.ts +1021 -0
- package/test/storage/update2.test.ts +897 -0
- package/test/utils/TestUtilsWalletStorage.ts +2526 -0
- package/test/utils/localWalletMethods.ts +363 -0
- package/test/utils/removeFailedFromDatabase.sql +17 -0
- package/ts2md.json +44 -0
- package/tsconfig.all.json +31 -0
- package/tsconfig.client.json +29 -0
- package/tsconfig.json +17 -0
- package/tsconfig.mobile.json +28 -0
|
@@ -0,0 +1,1425 @@
|
|
|
1
|
+
import { ListActionsResult, ListOutputsResult, Validation } from '@bsv/sdk'
|
|
2
|
+
import {
|
|
3
|
+
outputColumnsWithoutLockingScript,
|
|
4
|
+
TableCertificate,
|
|
5
|
+
TableCertificateField,
|
|
6
|
+
TableCertificateX,
|
|
7
|
+
TableCommission,
|
|
8
|
+
TableMonitorEvent,
|
|
9
|
+
TableOutput,
|
|
10
|
+
TableOutputBasket,
|
|
11
|
+
TableOutputTag,
|
|
12
|
+
TableOutputTagMap,
|
|
13
|
+
TableProvenTx,
|
|
14
|
+
TableProvenTxReq,
|
|
15
|
+
TableSettings,
|
|
16
|
+
TableSyncState,
|
|
17
|
+
TableTransaction,
|
|
18
|
+
TableTxLabel,
|
|
19
|
+
TableTxLabelMap,
|
|
20
|
+
TableUser,
|
|
21
|
+
transactionColumnsWithoutRawTx
|
|
22
|
+
} from './schema/tables'
|
|
23
|
+
import { KnexMigrations } from './schema/KnexMigrations'
|
|
24
|
+
import { Knex } from 'knex'
|
|
25
|
+
import { AdminStatsResult, StorageProvider, StorageProviderOptions } from './StorageProvider'
|
|
26
|
+
import { purgeData } from './methods/purgeData'
|
|
27
|
+
import { listActions } from './methods/listActionsKnex'
|
|
28
|
+
import { listOutputs } from './methods/listOutputsKnex'
|
|
29
|
+
import { DBType } from './StorageReader'
|
|
30
|
+
import { reviewStatus } from './methods/reviewStatus'
|
|
31
|
+
import { ServicesCallHistory } from '../sdk/WalletServices.interfaces'
|
|
32
|
+
import {
|
|
33
|
+
AuthId,
|
|
34
|
+
FindCertificateFieldsArgs,
|
|
35
|
+
FindCertificatesArgs,
|
|
36
|
+
FindCommissionsArgs,
|
|
37
|
+
FindForUserSincePagedArgs,
|
|
38
|
+
FindMonitorEventsArgs,
|
|
39
|
+
FindOutputBasketsArgs,
|
|
40
|
+
FindOutputsArgs,
|
|
41
|
+
FindOutputTagMapsArgs,
|
|
42
|
+
FindOutputTagsArgs,
|
|
43
|
+
FindPartialSincePagedArgs,
|
|
44
|
+
FindProvenTxReqsArgs,
|
|
45
|
+
FindProvenTxsArgs,
|
|
46
|
+
FindSyncStatesArgs,
|
|
47
|
+
FindTransactionsArgs,
|
|
48
|
+
FindTxLabelMapsArgs,
|
|
49
|
+
FindTxLabelsArgs,
|
|
50
|
+
FindUsersArgs,
|
|
51
|
+
ProvenOrRawTx,
|
|
52
|
+
PurgeParams,
|
|
53
|
+
PurgeResults,
|
|
54
|
+
TrxToken,
|
|
55
|
+
WalletStorageProvider
|
|
56
|
+
} from '../sdk/WalletStorage.interfaces'
|
|
57
|
+
import { WERR_INTERNAL, WERR_INVALID_PARAMETER, WERR_NOT_IMPLEMENTED, WERR_UNAUTHORIZED } from '../sdk/WERR_errors'
|
|
58
|
+
import { verifyOne, verifyOneOrNone, verifyTruthy } from '../utility/utilityHelpers'
|
|
59
|
+
import { EntityTimeStamp, TransactionStatus } from '../sdk/types'
|
|
60
|
+
|
|
61
|
+
export interface StorageKnexOptions extends StorageProviderOptions {
|
|
62
|
+
/**
|
|
63
|
+
* Knex database interface initialized with valid connection configuration.
|
|
64
|
+
*/
|
|
65
|
+
knex: Knex
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export class StorageKnex extends StorageProvider implements WalletStorageProvider {
|
|
69
|
+
knex: Knex
|
|
70
|
+
|
|
71
|
+
constructor(options: StorageKnexOptions) {
|
|
72
|
+
super(options)
|
|
73
|
+
if (!options.knex) throw new WERR_INVALID_PARAMETER('options.knex', `valid`)
|
|
74
|
+
this.knex = options.knex
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async readSettings(): Promise<TableSettings> {
|
|
78
|
+
return this.validateEntity(verifyOne(await this.toDb(undefined)<TableSettings>('settings')))
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
override async getProvenOrRawTx(txid: string, trx?: TrxToken): Promise<ProvenOrRawTx> {
|
|
82
|
+
const k = this.toDb(trx)
|
|
83
|
+
const r: ProvenOrRawTx = {
|
|
84
|
+
proven: undefined,
|
|
85
|
+
rawTx: undefined,
|
|
86
|
+
inputBEEF: undefined
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
r.proven = verifyOneOrNone(await this.findProvenTxs({ partial: { txid: txid } }))
|
|
90
|
+
if (!r.proven) {
|
|
91
|
+
const reqRawTx = verifyOneOrNone(
|
|
92
|
+
await k('proven_tx_reqs')
|
|
93
|
+
.where('txid', txid)
|
|
94
|
+
.whereIn('status', ['unsent', 'unmined', 'unconfirmed', 'sending', 'nosend', 'completed'])
|
|
95
|
+
.select('rawTx', 'inputBEEF')
|
|
96
|
+
)
|
|
97
|
+
if (reqRawTx) {
|
|
98
|
+
r.rawTx = Array.from(reqRawTx.rawTx)
|
|
99
|
+
r.inputBEEF = Array.from(reqRawTx.inputBEEF)
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return r
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
dbTypeSubstring(source: string, fromOffset: number, forLength?: number) {
|
|
106
|
+
if (this.dbtype === 'MySQL') return `substring(${source} from ${fromOffset} for ${forLength!})`
|
|
107
|
+
return `substr(${source}, ${fromOffset}, ${forLength})`
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
override async getRawTxOfKnownValidTransaction(
|
|
111
|
+
txid?: string,
|
|
112
|
+
offset?: number,
|
|
113
|
+
length?: number,
|
|
114
|
+
trx?: TrxToken
|
|
115
|
+
): Promise<number[] | undefined> {
|
|
116
|
+
if (!txid) return undefined
|
|
117
|
+
if (!this.isAvailable()) await this.makeAvailable()
|
|
118
|
+
|
|
119
|
+
let rawTx: number[] | undefined = undefined
|
|
120
|
+
if (Number.isInteger(offset) && Number.isInteger(length)) {
|
|
121
|
+
let rs: { rawTx: Buffer | null }[] = await this.toDb(trx).raw(
|
|
122
|
+
`select ${this.dbTypeSubstring('rawTx', offset! + 1, length)} as rawTx from proven_txs where txid = '${txid}'`
|
|
123
|
+
)
|
|
124
|
+
if (this.dbtype === 'MySQL') rs = (rs as unknown as { rawTx: Buffer | null }[][])[0]
|
|
125
|
+
const r = verifyOneOrNone(rs)
|
|
126
|
+
if (r && r.rawTx) {
|
|
127
|
+
rawTx = Array.from(r.rawTx)
|
|
128
|
+
} else {
|
|
129
|
+
let rs: { rawTx: Buffer | null }[] = await this.toDb(trx).raw(
|
|
130
|
+
`select ${this.dbTypeSubstring('rawTx', offset! + 1, length)} as rawTx from proven_tx_reqs where txid = '${txid}' and status in ('unsent', 'nosend', 'sending', 'unmined', 'completed', 'unfail')`
|
|
131
|
+
)
|
|
132
|
+
if (this.dbtype === 'MySQL') rs = (rs as unknown as { rawTx: Buffer | null }[][])[0]
|
|
133
|
+
const r = verifyOneOrNone(rs)
|
|
134
|
+
if (r && r.rawTx) {
|
|
135
|
+
rawTx = Array.from(r.rawTx)
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
} else {
|
|
139
|
+
const r = await this.getProvenOrRawTx(txid, trx)
|
|
140
|
+
if (r.proven) rawTx = r.proven.rawTx
|
|
141
|
+
else rawTx = r.rawTx
|
|
142
|
+
}
|
|
143
|
+
return rawTx
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
getProvenTxsForUserQuery(args: FindForUserSincePagedArgs): Knex.QueryBuilder {
|
|
147
|
+
const k = this.toDb(args.trx)
|
|
148
|
+
let q = k('proven_txs').where(function () {
|
|
149
|
+
this.whereExists(
|
|
150
|
+
k
|
|
151
|
+
.select('*')
|
|
152
|
+
.from('transactions')
|
|
153
|
+
.whereRaw(`proven_txs.provenTxId = transactions.provenTxId and transactions.userId = ${args.userId}`)
|
|
154
|
+
)
|
|
155
|
+
})
|
|
156
|
+
if (args.paged) {
|
|
157
|
+
q = q.limit(args.paged.limit)
|
|
158
|
+
q = q.offset(args.paged.offset || 0)
|
|
159
|
+
}
|
|
160
|
+
if (args.since) q = q.where('updated_at', '>=', this.validateDateForWhere(args.since))
|
|
161
|
+
return q
|
|
162
|
+
}
|
|
163
|
+
override async getProvenTxsForUser(args: FindForUserSincePagedArgs): Promise<TableProvenTx[]> {
|
|
164
|
+
const q = this.getProvenTxsForUserQuery(args)
|
|
165
|
+
const rs = await q
|
|
166
|
+
return this.validateEntities(rs)
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
getProvenTxReqsForUserQuery(args: FindForUserSincePagedArgs): Knex.QueryBuilder {
|
|
170
|
+
const k = this.toDb(args.trx)
|
|
171
|
+
let q = k('proven_tx_reqs').where(function () {
|
|
172
|
+
this.whereExists(
|
|
173
|
+
k
|
|
174
|
+
.select('*')
|
|
175
|
+
.from('transactions')
|
|
176
|
+
.whereRaw(`proven_tx_reqs.txid = transactions.txid and transactions.userId = ${args.userId}`)
|
|
177
|
+
)
|
|
178
|
+
})
|
|
179
|
+
if (args.paged) {
|
|
180
|
+
q = q.limit(args.paged.limit)
|
|
181
|
+
q = q.offset(args.paged.offset || 0)
|
|
182
|
+
}
|
|
183
|
+
if (args.since) q = q.where('updated_at', '>=', this.validateDateForWhere(args.since))
|
|
184
|
+
return q
|
|
185
|
+
}
|
|
186
|
+
override async getProvenTxReqsForUser(args: FindForUserSincePagedArgs): Promise<TableProvenTxReq[]> {
|
|
187
|
+
const q = this.getProvenTxReqsForUserQuery(args)
|
|
188
|
+
const rs = await q
|
|
189
|
+
return this.validateEntities(rs, undefined, ['notified'])
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
getTxLabelMapsForUserQuery(args: FindForUserSincePagedArgs): Knex.QueryBuilder {
|
|
193
|
+
const k = this.toDb(args.trx)
|
|
194
|
+
let q = k('tx_labels_map').whereExists(
|
|
195
|
+
k
|
|
196
|
+
.select('*')
|
|
197
|
+
.from('tx_labels')
|
|
198
|
+
.whereRaw(`tx_labels.txLabelId = tx_labels_map.txLabelId and tx_labels.userId = ${args.userId}`)
|
|
199
|
+
)
|
|
200
|
+
if (args.since) q = q.where('updated_at', '>=', this.validateDateForWhere(args.since))
|
|
201
|
+
if (args.paged) {
|
|
202
|
+
q = q.limit(args.paged.limit)
|
|
203
|
+
q = q.offset(args.paged.offset || 0)
|
|
204
|
+
}
|
|
205
|
+
return q
|
|
206
|
+
}
|
|
207
|
+
override async getTxLabelMapsForUser(args: FindForUserSincePagedArgs): Promise<TableTxLabelMap[]> {
|
|
208
|
+
const q = this.getTxLabelMapsForUserQuery(args)
|
|
209
|
+
const rs = await q
|
|
210
|
+
return this.validateEntities(rs, undefined, ['isDeleted'])
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
getOutputTagMapsForUserQuery(args: FindForUserSincePagedArgs): Knex.QueryBuilder {
|
|
214
|
+
const k = this.toDb(args.trx)
|
|
215
|
+
let q = k('output_tags_map').whereExists(
|
|
216
|
+
k
|
|
217
|
+
.select('*')
|
|
218
|
+
.from('output_tags')
|
|
219
|
+
.whereRaw(`output_tags.outputTagId = output_tags_map.outputTagId and output_tags.userId = ${args.userId}`)
|
|
220
|
+
)
|
|
221
|
+
if (args.since) q = q.where('updated_at', '>=', this.validateDateForWhere(args.since))
|
|
222
|
+
if (args.paged) {
|
|
223
|
+
q = q.limit(args.paged.limit)
|
|
224
|
+
q = q.offset(args.paged.offset || 0)
|
|
225
|
+
}
|
|
226
|
+
return q
|
|
227
|
+
}
|
|
228
|
+
override async getOutputTagMapsForUser(args: FindForUserSincePagedArgs): Promise<TableOutputTagMap[]> {
|
|
229
|
+
const q = this.getOutputTagMapsForUserQuery(args)
|
|
230
|
+
const rs = await q
|
|
231
|
+
return this.validateEntities(rs, undefined, ['isDeleted'])
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
override async listActions(auth: AuthId, vargs: Validation.ValidListActionsArgs): Promise<ListActionsResult> {
|
|
235
|
+
if (!auth.userId) throw new WERR_UNAUTHORIZED()
|
|
236
|
+
return await listActions(this, auth, vargs)
|
|
237
|
+
}
|
|
238
|
+
override async listOutputs(auth: AuthId, vargs: Validation.ValidListOutputsArgs): Promise<ListOutputsResult> {
|
|
239
|
+
if (!auth.userId) throw new WERR_UNAUTHORIZED()
|
|
240
|
+
return await listOutputs(this, auth, vargs)
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
override async insertProvenTx(tx: TableProvenTx, trx?: TrxToken): Promise<number> {
|
|
244
|
+
const e = await this.validateEntityForInsert(tx, trx)
|
|
245
|
+
if (e.provenTxId === 0) delete e.provenTxId
|
|
246
|
+
const [id] = await this.toDb(trx)<TableProvenTx>('proven_txs').insert(e)
|
|
247
|
+
tx.provenTxId = id
|
|
248
|
+
return tx.provenTxId
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
override async insertProvenTxReq(tx: TableProvenTxReq, trx?: TrxToken): Promise<number> {
|
|
252
|
+
const e = await this.validateEntityForInsert(tx, trx)
|
|
253
|
+
if (e.provenTxReqId === 0) delete e.provenTxReqId
|
|
254
|
+
const [id] = await this.toDb(trx)<TableProvenTxReq>('proven_tx_reqs').insert(e)
|
|
255
|
+
tx.provenTxReqId = id
|
|
256
|
+
return tx.provenTxReqId
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
override async insertUser(user: TableUser, trx?: TrxToken): Promise<number> {
|
|
260
|
+
const e = await this.validateEntityForInsert(user, trx)
|
|
261
|
+
if (e.userId === 0) delete e.userId
|
|
262
|
+
const [id] = await this.toDb(trx)<TableUser>('users').insert(e)
|
|
263
|
+
user.userId = id
|
|
264
|
+
return user.userId
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
override async insertCertificateAuth(auth: AuthId, certificate: TableCertificateX): Promise<number> {
|
|
268
|
+
if (!auth.userId || (certificate.userId && certificate.userId !== auth.userId)) throw new WERR_UNAUTHORIZED()
|
|
269
|
+
certificate.userId = auth.userId
|
|
270
|
+
return await this.insertCertificate(certificate)
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
override async insertCertificate(certificate: TableCertificateX, trx?: TrxToken): Promise<number> {
|
|
274
|
+
const e = await this.validateEntityForInsert(certificate, trx, undefined, ['isDeleted'])
|
|
275
|
+
if (e.certificateId === 0) delete e.certificateId
|
|
276
|
+
|
|
277
|
+
const logger = e.logger
|
|
278
|
+
if (e.logger) delete e.logger
|
|
279
|
+
|
|
280
|
+
const fields = e.fields
|
|
281
|
+
if (e.fields) delete e.fields
|
|
282
|
+
|
|
283
|
+
const [id] = await this.toDb(trx)<TableCertificate>('certificates').insert(e)
|
|
284
|
+
certificate.certificateId = id
|
|
285
|
+
|
|
286
|
+
if (fields) {
|
|
287
|
+
for (const field of fields) {
|
|
288
|
+
field.certificateId = id
|
|
289
|
+
field.userId = certificate.userId
|
|
290
|
+
await this.insertCertificateField(field, trx)
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
return certificate.certificateId
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
override async insertCertificateField(certificateField: TableCertificateField, trx?: TrxToken): Promise<void> {
|
|
298
|
+
const e = await this.validateEntityForInsert(certificateField, trx)
|
|
299
|
+
await this.toDb(trx)<TableCertificate>('certificate_fields').insert(e)
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
override async insertOutputBasket(basket: TableOutputBasket, trx?: TrxToken): Promise<number> {
|
|
303
|
+
const e = await this.validateEntityForInsert(basket, trx, undefined, ['isDeleted'])
|
|
304
|
+
if (e.basketId === 0) delete e.basketId
|
|
305
|
+
const [id] = await this.toDb(trx)<TableOutputBasket>('output_baskets').insert(e)
|
|
306
|
+
basket.basketId = id
|
|
307
|
+
return basket.basketId
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
override async insertTransaction(tx: TableTransaction, trx?: TrxToken): Promise<number> {
|
|
311
|
+
const e = await this.validateEntityForInsert(tx, trx)
|
|
312
|
+
if (e.transactionId === 0) delete e.transactionId
|
|
313
|
+
const [id] = await this.toDb(trx)<TableTransaction>('transactions').insert(e)
|
|
314
|
+
tx.transactionId = id
|
|
315
|
+
return tx.transactionId
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
override async insertCommission(commission: TableCommission, trx?: TrxToken): Promise<number> {
|
|
319
|
+
const e = await this.validateEntityForInsert(commission, trx)
|
|
320
|
+
if (e.commissionId === 0) delete e.commissionId
|
|
321
|
+
const [id] = await this.toDb(trx)<TableCommission>('commissions').insert(e)
|
|
322
|
+
commission.commissionId = id
|
|
323
|
+
return commission.commissionId
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
override async insertOutput(output: TableOutput, trx?: TrxToken): Promise<number> {
|
|
327
|
+
try {
|
|
328
|
+
const e = await this.validateEntityForInsert(output, trx)
|
|
329
|
+
if (e.outputId === 0) delete e.outputId
|
|
330
|
+
const [id] = await this.toDb(trx)<TableOutput>('outputs').insert(e)
|
|
331
|
+
output.outputId = id
|
|
332
|
+
return output.outputId
|
|
333
|
+
} catch (e) {
|
|
334
|
+
throw e
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
override async insertOutputTag(tag: TableOutputTag, trx?: TrxToken): Promise<number> {
|
|
339
|
+
const e = await this.validateEntityForInsert(tag, trx, undefined, ['isDeleted'])
|
|
340
|
+
if (e.outputTagId === 0) delete e.outputTagId
|
|
341
|
+
const [id] = await this.toDb(trx)<TableOutputTag>('output_tags').insert(e)
|
|
342
|
+
tag.outputTagId = id
|
|
343
|
+
return tag.outputTagId
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
override async insertOutputTagMap(tagMap: TableOutputTagMap, trx?: TrxToken): Promise<void> {
|
|
347
|
+
const e = await this.validateEntityForInsert(tagMap, trx, undefined, ['isDeleted'])
|
|
348
|
+
const [id] = await this.toDb(trx)<TableOutputTagMap>('output_tags_map').insert(e)
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
override async insertTxLabel(label: TableTxLabel, trx?: TrxToken): Promise<number> {
|
|
352
|
+
const e = await this.validateEntityForInsert(label, trx, undefined, ['isDeleted'])
|
|
353
|
+
if (e.txLabelId === 0) delete e.txLabelId
|
|
354
|
+
const [id] = await this.toDb(trx)<TableTxLabel>('tx_labels').insert(e)
|
|
355
|
+
label.txLabelId = id
|
|
356
|
+
return label.txLabelId
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
override async insertTxLabelMap(labelMap: TableTxLabelMap, trx?: TrxToken): Promise<void> {
|
|
360
|
+
const e = await this.validateEntityForInsert(labelMap, trx, undefined, ['isDeleted'])
|
|
361
|
+
const [id] = await this.toDb(trx)<TableTxLabelMap>('tx_labels_map').insert(e)
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
override async insertMonitorEvent(event: TableMonitorEvent, trx?: TrxToken): Promise<number> {
|
|
365
|
+
const e = await this.validateEntityForInsert(event, trx)
|
|
366
|
+
if (e.id === 0) delete e.id
|
|
367
|
+
const [id] = await this.toDb(trx)<TableMonitorEvent>('monitor_events').insert(e)
|
|
368
|
+
event.id = id
|
|
369
|
+
return event.id
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
override async insertSyncState(syncState: TableSyncState, trx?: TrxToken): Promise<number> {
|
|
373
|
+
const e = await this.validateEntityForInsert(syncState, trx, ['when'], ['init'])
|
|
374
|
+
if (e.syncStateId === 0) delete e.syncStateId
|
|
375
|
+
const [id] = await this.toDb(trx)<TableSyncState>('sync_states').insert(e)
|
|
376
|
+
syncState.syncStateId = id
|
|
377
|
+
return syncState.syncStateId
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
override async updateCertificateField(
|
|
381
|
+
certificateId: number,
|
|
382
|
+
fieldName: string,
|
|
383
|
+
update: Partial<TableCertificateField>,
|
|
384
|
+
trx?: TrxToken
|
|
385
|
+
): Promise<number> {
|
|
386
|
+
await this.verifyReadyForDatabaseAccess(trx)
|
|
387
|
+
return await this.toDb(trx)<TableCertificateField>('certificate_fields')
|
|
388
|
+
.where({ certificateId, fieldName })
|
|
389
|
+
.update(this.validatePartialForUpdate(update))
|
|
390
|
+
}
|
|
391
|
+
override async updateCertificate(id: number, update: Partial<TableCertificate>, trx?: TrxToken): Promise<number> {
|
|
392
|
+
await this.verifyReadyForDatabaseAccess(trx)
|
|
393
|
+
return await this.toDb(trx)<TableCertificate>('certificates')
|
|
394
|
+
.where({ certificateId: id })
|
|
395
|
+
.update(this.validatePartialForUpdate(update, undefined, ['isDeleted']))
|
|
396
|
+
}
|
|
397
|
+
override async updateCommission(id: number, update: Partial<TableCommission>, trx?: TrxToken): Promise<number> {
|
|
398
|
+
await this.verifyReadyForDatabaseAccess(trx)
|
|
399
|
+
return await this.toDb(trx)<TableCommission>('commissions')
|
|
400
|
+
.where({ commissionId: id })
|
|
401
|
+
.update(this.validatePartialForUpdate(update))
|
|
402
|
+
}
|
|
403
|
+
override async updateOutputBasket(id: number, update: Partial<TableOutputBasket>, trx?: TrxToken): Promise<number> {
|
|
404
|
+
await this.verifyReadyForDatabaseAccess(trx)
|
|
405
|
+
return await this.toDb(trx)<TableOutputBasket>('output_baskets')
|
|
406
|
+
.where({ basketId: id })
|
|
407
|
+
.update(this.validatePartialForUpdate(update, undefined, ['isDeleted']))
|
|
408
|
+
}
|
|
409
|
+
override async updateOutput(id: number, update: Partial<TableOutput>, trx?: TrxToken): Promise<number> {
|
|
410
|
+
await this.verifyReadyForDatabaseAccess(trx)
|
|
411
|
+
return await this.toDb(trx)<TableOutput>('outputs')
|
|
412
|
+
.where({ outputId: id })
|
|
413
|
+
.update(this.validatePartialForUpdate(update))
|
|
414
|
+
}
|
|
415
|
+
override async updateOutputTagMap(
|
|
416
|
+
outputId: number,
|
|
417
|
+
tagId: number,
|
|
418
|
+
update: Partial<TableOutputTagMap>,
|
|
419
|
+
trx?: TrxToken
|
|
420
|
+
): Promise<number> {
|
|
421
|
+
await this.verifyReadyForDatabaseAccess(trx)
|
|
422
|
+
return await this.toDb(trx)<TableOutputTagMap>('output_tags_map')
|
|
423
|
+
.where({ outputId, outputTagId: tagId })
|
|
424
|
+
.update(this.validatePartialForUpdate(update, undefined, ['isDeleted']))
|
|
425
|
+
}
|
|
426
|
+
override async updateOutputTag(id: number, update: Partial<TableOutputTag>, trx?: TrxToken): Promise<number> {
|
|
427
|
+
await this.verifyReadyForDatabaseAccess(trx)
|
|
428
|
+
return await this.toDb(trx)<TableOutputTag>('output_tags')
|
|
429
|
+
.where({ outputTagId: id })
|
|
430
|
+
.update(this.validatePartialForUpdate(update, undefined, ['isDeleted']))
|
|
431
|
+
}
|
|
432
|
+
override async updateProvenTxReq(
|
|
433
|
+
id: number | number[],
|
|
434
|
+
update: Partial<TableProvenTxReq>,
|
|
435
|
+
trx?: TrxToken
|
|
436
|
+
): Promise<number> {
|
|
437
|
+
await this.verifyReadyForDatabaseAccess(trx)
|
|
438
|
+
let r: number
|
|
439
|
+
if (Array.isArray(id)) {
|
|
440
|
+
r = await this.toDb(trx)<TableProvenTxReq>('proven_tx_reqs')
|
|
441
|
+
.whereIn('provenTxReqId', id)
|
|
442
|
+
.update(this.validatePartialForUpdate(update))
|
|
443
|
+
} else if (Number.isInteger(id)) {
|
|
444
|
+
r = await this.toDb(trx)<TableProvenTxReq>('proven_tx_reqs')
|
|
445
|
+
.where({ provenTxReqId: id })
|
|
446
|
+
.update(this.validatePartialForUpdate(update))
|
|
447
|
+
} else {
|
|
448
|
+
throw new WERR_INVALID_PARAMETER('id', 'transactionId or array of transactionId')
|
|
449
|
+
}
|
|
450
|
+
return r
|
|
451
|
+
}
|
|
452
|
+
override async updateProvenTx(id: number, update: Partial<TableProvenTx>, trx?: TrxToken): Promise<number> {
|
|
453
|
+
await this.verifyReadyForDatabaseAccess(trx)
|
|
454
|
+
return await this.toDb(trx)<TableProvenTx>('proven_txs')
|
|
455
|
+
.where({ provenTxId: id })
|
|
456
|
+
.update(this.validatePartialForUpdate(update))
|
|
457
|
+
}
|
|
458
|
+
override async updateSyncState(id: number, update: Partial<TableSyncState>, trx?: TrxToken): Promise<number> {
|
|
459
|
+
await this.verifyReadyForDatabaseAccess(trx)
|
|
460
|
+
return await this.toDb(trx)<TableSyncState>('sync_states')
|
|
461
|
+
.where({ syncStateId: id })
|
|
462
|
+
.update(this.validatePartialForUpdate(update, ['when'], ['init']))
|
|
463
|
+
}
|
|
464
|
+
override async updateTransaction(
|
|
465
|
+
id: number | number[],
|
|
466
|
+
update: Partial<TableTransaction>,
|
|
467
|
+
trx?: TrxToken
|
|
468
|
+
): Promise<number> {
|
|
469
|
+
await this.verifyReadyForDatabaseAccess(trx)
|
|
470
|
+
let r: number
|
|
471
|
+
if (Array.isArray(id)) {
|
|
472
|
+
r = await this.toDb(trx)<TableTransaction>('transactions')
|
|
473
|
+
.whereIn('transactionId', id)
|
|
474
|
+
.update(await this.validatePartialForUpdate(update))
|
|
475
|
+
} else if (Number.isInteger(id)) {
|
|
476
|
+
r = await this.toDb(trx)<TableTransaction>('transactions')
|
|
477
|
+
.where({ transactionId: id })
|
|
478
|
+
.update(await this.validatePartialForUpdate(update))
|
|
479
|
+
} else {
|
|
480
|
+
throw new WERR_INVALID_PARAMETER('id', 'transactionId or array of transactionId')
|
|
481
|
+
}
|
|
482
|
+
return r
|
|
483
|
+
}
|
|
484
|
+
override async updateTxLabelMap(
|
|
485
|
+
transactionId: number,
|
|
486
|
+
txLabelId: number,
|
|
487
|
+
update: Partial<TableTxLabelMap>,
|
|
488
|
+
trx?: TrxToken
|
|
489
|
+
): Promise<number> {
|
|
490
|
+
await this.verifyReadyForDatabaseAccess(trx)
|
|
491
|
+
return await this.toDb(trx)<TableTxLabelMap>('tx_labels_map')
|
|
492
|
+
.where({ transactionId, txLabelId })
|
|
493
|
+
.update(this.validatePartialForUpdate(update, undefined, ['isDeleted']))
|
|
494
|
+
}
|
|
495
|
+
override async updateTxLabel(id: number, update: Partial<TableTxLabel>, trx?: TrxToken): Promise<number> {
|
|
496
|
+
await this.verifyReadyForDatabaseAccess(trx)
|
|
497
|
+
return await this.toDb(trx)<TableTxLabel>('tx_labels')
|
|
498
|
+
.where({ txLabelId: id })
|
|
499
|
+
.update(this.validatePartialForUpdate(update, undefined, ['isDeleted']))
|
|
500
|
+
}
|
|
501
|
+
override async updateUser(id: number, update: Partial<TableUser>, trx?: TrxToken): Promise<number> {
|
|
502
|
+
await this.verifyReadyForDatabaseAccess(trx)
|
|
503
|
+
return await this.toDb(trx)<TableUser>('users').where({ userId: id }).update(this.validatePartialForUpdate(update))
|
|
504
|
+
}
|
|
505
|
+
override async updateMonitorEvent(id: number, update: Partial<TableMonitorEvent>, trx?: TrxToken): Promise<number> {
|
|
506
|
+
await this.verifyReadyForDatabaseAccess(trx)
|
|
507
|
+
return await this.toDb(trx)<TableMonitorEvent>('monitor_events')
|
|
508
|
+
.where({ id })
|
|
509
|
+
.update(this.validatePartialForUpdate(update))
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
setupQuery<T extends object>(table: string, args: FindPartialSincePagedArgs<T>): Knex.QueryBuilder {
|
|
513
|
+
let q = this.toDb(args.trx)<T>(table)
|
|
514
|
+
if (args.partial && Object.keys(args.partial).length > 0) q.where(args.partial)
|
|
515
|
+
if (args.since) q.where('updated_at', '>=', this.validateDateForWhere(args.since))
|
|
516
|
+
if (args.orderDescending) {
|
|
517
|
+
let sortColumn = ''
|
|
518
|
+
switch (table) {
|
|
519
|
+
case 'certificates':
|
|
520
|
+
sortColumn = 'certificateId'
|
|
521
|
+
break
|
|
522
|
+
case 'commissions':
|
|
523
|
+
sortColumn = 'commissionId'
|
|
524
|
+
break
|
|
525
|
+
case 'output_baskets':
|
|
526
|
+
sortColumn = 'basketId'
|
|
527
|
+
break
|
|
528
|
+
case 'outputs':
|
|
529
|
+
sortColumn = 'outputId'
|
|
530
|
+
break
|
|
531
|
+
case 'output_tags':
|
|
532
|
+
sortColumn = 'outputTagId'
|
|
533
|
+
break
|
|
534
|
+
case 'proven_tx_reqs':
|
|
535
|
+
sortColumn = 'provenTxReqId'
|
|
536
|
+
break
|
|
537
|
+
case 'proven_txs':
|
|
538
|
+
sortColumn = 'provenTxId'
|
|
539
|
+
break
|
|
540
|
+
case 'sync_states':
|
|
541
|
+
sortColumn = 'syncStateId'
|
|
542
|
+
break
|
|
543
|
+
case 'transactions':
|
|
544
|
+
sortColumn = 'transactionId'
|
|
545
|
+
break
|
|
546
|
+
case 'tx_labels':
|
|
547
|
+
sortColumn = 'txLabelId'
|
|
548
|
+
break
|
|
549
|
+
case 'users':
|
|
550
|
+
sortColumn = 'userId'
|
|
551
|
+
break
|
|
552
|
+
case 'monitor_events':
|
|
553
|
+
sortColumn = 'id'
|
|
554
|
+
break
|
|
555
|
+
default:
|
|
556
|
+
break
|
|
557
|
+
}
|
|
558
|
+
if (sortColumn !== '') {
|
|
559
|
+
q.orderBy(sortColumn, 'desc')
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
if (args.paged) {
|
|
563
|
+
q.limit(args.paged.limit)
|
|
564
|
+
q.offset(args.paged.offset || 0)
|
|
565
|
+
}
|
|
566
|
+
return q
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
findCertificateFieldsQuery(args: FindCertificateFieldsArgs): Knex.QueryBuilder {
|
|
570
|
+
return this.setupQuery('certificate_fields', args)
|
|
571
|
+
}
|
|
572
|
+
findCertificatesQuery(args: FindCertificatesArgs): Knex.QueryBuilder {
|
|
573
|
+
const q = this.setupQuery('certificates', args)
|
|
574
|
+
if (args.certifiers && args.certifiers.length > 0) q.whereIn('certifier', args.certifiers)
|
|
575
|
+
if (args.types && args.types.length > 0) q.whereIn('type', args.types)
|
|
576
|
+
return q
|
|
577
|
+
}
|
|
578
|
+
findCommissionsQuery(args: FindCommissionsArgs): Knex.QueryBuilder {
|
|
579
|
+
if (args.partial.lockingScript)
|
|
580
|
+
throw new WERR_INVALID_PARAMETER(
|
|
581
|
+
'partial.lockingScript',
|
|
582
|
+
`undefined. Commissions may not be found by lockingScript value.`
|
|
583
|
+
)
|
|
584
|
+
return this.setupQuery('commissions', args)
|
|
585
|
+
}
|
|
586
|
+
findOutputBasketsQuery(args: FindOutputBasketsArgs): Knex.QueryBuilder {
|
|
587
|
+
return this.setupQuery('output_baskets', args)
|
|
588
|
+
}
|
|
589
|
+
findOutputsQuery(args: FindOutputsArgs, count?: boolean): Knex.QueryBuilder {
|
|
590
|
+
if (args.partial.lockingScript)
|
|
591
|
+
throw new WERR_INVALID_PARAMETER(
|
|
592
|
+
'args.partial.lockingScript',
|
|
593
|
+
`undefined. Outputs may not be found by lockingScript value.`
|
|
594
|
+
)
|
|
595
|
+
const q = this.setupQuery('outputs', args)
|
|
596
|
+
if (args.txStatus && args.txStatus.length > 0) {
|
|
597
|
+
q.whereRaw(
|
|
598
|
+
`(select status from transactions where transactions.transactionId = outputs.transactionId) in (${args.txStatus.map(s => `'${s}'`).join(',')})`
|
|
599
|
+
)
|
|
600
|
+
}
|
|
601
|
+
if (args.noScript && !count) {
|
|
602
|
+
const columns = outputColumnsWithoutLockingScript.map(c => `outputs.${c}`)
|
|
603
|
+
q.select(columns)
|
|
604
|
+
}
|
|
605
|
+
return q
|
|
606
|
+
}
|
|
607
|
+
findOutputTagMapsQuery(args: FindOutputTagMapsArgs): Knex.QueryBuilder {
|
|
608
|
+
const q = this.setupQuery('output_tags_map', args)
|
|
609
|
+
if (args.tagIds && args.tagIds.length > 0) q.whereIn('outputTagId', args.tagIds)
|
|
610
|
+
return q
|
|
611
|
+
}
|
|
612
|
+
findOutputTagsQuery(args: FindOutputTagsArgs): Knex.QueryBuilder {
|
|
613
|
+
return this.setupQuery('output_tags', args)
|
|
614
|
+
}
|
|
615
|
+
findProvenTxReqsQuery(args: FindProvenTxReqsArgs): Knex.QueryBuilder {
|
|
616
|
+
if (args.partial.rawTx)
|
|
617
|
+
throw new WERR_INVALID_PARAMETER('args.partial.rawTx', `undefined. ProvenTxReqs may not be found by rawTx value.`)
|
|
618
|
+
if (args.partial.inputBEEF)
|
|
619
|
+
throw new WERR_INVALID_PARAMETER(
|
|
620
|
+
'args.partial.inputBEEF',
|
|
621
|
+
`undefined. ProvenTxReqs may not be found by inputBEEF value.`
|
|
622
|
+
)
|
|
623
|
+
const q = this.setupQuery('proven_tx_reqs', args)
|
|
624
|
+
if (args.status && args.status.length > 0) q.whereIn('status', args.status)
|
|
625
|
+
if (args.txids) {
|
|
626
|
+
const txids = args.txids.filter(txid => txid !== undefined)
|
|
627
|
+
if (txids.length > 0) q.whereIn('txid', txids)
|
|
628
|
+
}
|
|
629
|
+
return q
|
|
630
|
+
}
|
|
631
|
+
findProvenTxsQuery(args: FindProvenTxsArgs): Knex.QueryBuilder {
|
|
632
|
+
if (args.partial.rawTx)
|
|
633
|
+
throw new WERR_INVALID_PARAMETER('args.partial.rawTx', `undefined. ProvenTxs may not be found by rawTx value.`)
|
|
634
|
+
if (args.partial.merklePath)
|
|
635
|
+
throw new WERR_INVALID_PARAMETER(
|
|
636
|
+
'args.partial.merklePath',
|
|
637
|
+
`undefined. ProvenTxs may not be found by merklePath value.`
|
|
638
|
+
)
|
|
639
|
+
return this.setupQuery('proven_txs', args)
|
|
640
|
+
}
|
|
641
|
+
findSyncStatesQuery(args: FindSyncStatesArgs): Knex.QueryBuilder {
|
|
642
|
+
return this.setupQuery('sync_states', args)
|
|
643
|
+
}
|
|
644
|
+
findTransactionsQuery(args: FindTransactionsArgs, count?: boolean): Knex.QueryBuilder {
|
|
645
|
+
if (args.partial.rawTx)
|
|
646
|
+
throw new WERR_INVALID_PARAMETER('args.partial.rawTx', `undefined. Transactions may not be found by rawTx value.`)
|
|
647
|
+
if (args.partial.inputBEEF)
|
|
648
|
+
throw new WERR_INVALID_PARAMETER(
|
|
649
|
+
'args.partial.inputBEEF',
|
|
650
|
+
`undefined. Transactions may not be found by inputBEEF value.`
|
|
651
|
+
)
|
|
652
|
+
const q = this.setupQuery('transactions', args)
|
|
653
|
+
if (args.status && args.status.length > 0) q.whereIn('status', args.status)
|
|
654
|
+
if (args.noRawTx && !count) {
|
|
655
|
+
const columns = transactionColumnsWithoutRawTx.map(c => `transactions.${c}`)
|
|
656
|
+
q.select(columns)
|
|
657
|
+
}
|
|
658
|
+
return q
|
|
659
|
+
}
|
|
660
|
+
findTxLabelMapsQuery(args: FindTxLabelMapsArgs): Knex.QueryBuilder {
|
|
661
|
+
const q = this.setupQuery('tx_labels_map', args)
|
|
662
|
+
if (args.labelIds && args.labelIds.length > 0) q.whereIn('txLabelId', args.labelIds)
|
|
663
|
+
return q
|
|
664
|
+
}
|
|
665
|
+
findTxLabelsQuery(args: FindTxLabelsArgs): Knex.QueryBuilder {
|
|
666
|
+
return this.setupQuery('tx_labels', args)
|
|
667
|
+
}
|
|
668
|
+
findUsersQuery(args: FindUsersArgs): Knex.QueryBuilder {
|
|
669
|
+
return this.setupQuery('users', args)
|
|
670
|
+
}
|
|
671
|
+
findMonitorEventsQuery(args: FindMonitorEventsArgs): Knex.QueryBuilder {
|
|
672
|
+
return this.setupQuery('monitor_events', args)
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
override async findCertificatesAuth(auth: AuthId, args: FindCertificatesArgs): Promise<TableCertificateX[]> {
|
|
676
|
+
if (!auth.userId || (args.partial.userId && args.partial.userId !== auth.userId)) throw new WERR_UNAUTHORIZED()
|
|
677
|
+
args.partial.userId = auth.userId
|
|
678
|
+
return await this.findCertificates(args)
|
|
679
|
+
}
|
|
680
|
+
override async findOutputBasketsAuth(auth: AuthId, args: FindOutputBasketsArgs): Promise<TableOutputBasket[]> {
|
|
681
|
+
if (!auth.userId || (args.partial.userId && args.partial.userId !== auth.userId)) throw new WERR_UNAUTHORIZED()
|
|
682
|
+
args.partial.userId = auth.userId
|
|
683
|
+
return await this.findOutputBaskets(args)
|
|
684
|
+
}
|
|
685
|
+
override async findOutputsAuth(auth: AuthId, args: FindOutputsArgs): Promise<TableOutput[]> {
|
|
686
|
+
if (!auth.userId || (args.partial.userId && args.partial.userId !== auth.userId)) throw new WERR_UNAUTHORIZED()
|
|
687
|
+
args.partial.userId = auth.userId
|
|
688
|
+
return await this.findOutputs(args)
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
override async findCertificateFields(args: FindCertificateFieldsArgs): Promise<TableCertificateField[]> {
|
|
692
|
+
return this.validateEntities(await this.findCertificateFieldsQuery(args))
|
|
693
|
+
}
|
|
694
|
+
override async findCertificates(args: FindCertificatesArgs): Promise<TableCertificateX[]> {
|
|
695
|
+
const q = this.findCertificatesQuery(args)
|
|
696
|
+
let r: TableCertificateX[] = await q
|
|
697
|
+
r = this.validateEntities(r, undefined, ['isDeleted'])
|
|
698
|
+
if (args.includeFields) {
|
|
699
|
+
for (const c of r) {
|
|
700
|
+
c.fields = this.validateEntities(
|
|
701
|
+
await this.findCertificateFields({
|
|
702
|
+
partial: { certificateId: c.certificateId, userId: c.userId },
|
|
703
|
+
trx: args.trx
|
|
704
|
+
})
|
|
705
|
+
)
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
return r
|
|
709
|
+
}
|
|
710
|
+
override async findCommissions(args: FindCommissionsArgs): Promise<TableCommission[]> {
|
|
711
|
+
const q = this.findCommissionsQuery(args)
|
|
712
|
+
const r = await q
|
|
713
|
+
return this.validateEntities(r, undefined, ['isRedeemed'])
|
|
714
|
+
}
|
|
715
|
+
override async findOutputBaskets(args: FindOutputBasketsArgs): Promise<TableOutputBasket[]> {
|
|
716
|
+
const q = this.findOutputBasketsQuery(args)
|
|
717
|
+
const r = await q
|
|
718
|
+
return this.validateEntities(r, undefined, ['isDeleted'])
|
|
719
|
+
}
|
|
720
|
+
override async findOutputs(args: FindOutputsArgs): Promise<TableOutput[]> {
|
|
721
|
+
const q = this.findOutputsQuery(args)
|
|
722
|
+
const r = await q
|
|
723
|
+
if (!args.noScript) {
|
|
724
|
+
for (const o of r) {
|
|
725
|
+
await this.validateOutputScript(o, args.trx)
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
return this.validateEntities(r, undefined, ['spendable', 'change'])
|
|
729
|
+
}
|
|
730
|
+
override async findOutputTagMaps(args: FindOutputTagMapsArgs): Promise<TableOutputTagMap[]> {
|
|
731
|
+
const q = this.findOutputTagMapsQuery(args)
|
|
732
|
+
const r = await q
|
|
733
|
+
return this.validateEntities(r, undefined, ['isDeleted'])
|
|
734
|
+
}
|
|
735
|
+
override async findOutputTags(args: FindOutputTagsArgs): Promise<TableOutputTag[]> {
|
|
736
|
+
const q = this.findOutputTagsQuery(args)
|
|
737
|
+
const r = await q
|
|
738
|
+
return this.validateEntities(r, undefined, ['isDeleted'])
|
|
739
|
+
}
|
|
740
|
+
override async findProvenTxReqs(args: FindProvenTxReqsArgs): Promise<TableProvenTxReq[]> {
|
|
741
|
+
const q = this.findProvenTxReqsQuery(args)
|
|
742
|
+
const r = await q
|
|
743
|
+
return this.validateEntities(r, undefined, ['notified'])
|
|
744
|
+
}
|
|
745
|
+
override async findProvenTxs(args: FindProvenTxsArgs): Promise<TableProvenTx[]> {
|
|
746
|
+
const q = this.findProvenTxsQuery(args)
|
|
747
|
+
const r = await q
|
|
748
|
+
return this.validateEntities(r)
|
|
749
|
+
}
|
|
750
|
+
override async findSyncStates(args: FindSyncStatesArgs): Promise<TableSyncState[]> {
|
|
751
|
+
const q = this.findSyncStatesQuery(args)
|
|
752
|
+
const r = await q
|
|
753
|
+
return this.validateEntities(r, ['when'], ['init'])
|
|
754
|
+
}
|
|
755
|
+
override async findTransactions(args: FindTransactionsArgs): Promise<TableTransaction[]> {
|
|
756
|
+
const q = this.findTransactionsQuery(args)
|
|
757
|
+
const r = await q
|
|
758
|
+
if (!args.noRawTx) {
|
|
759
|
+
for (const t of r) {
|
|
760
|
+
await this.validateRawTransaction(t, args.trx)
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
return this.validateEntities(r, undefined, ['isOutgoing'])
|
|
764
|
+
}
|
|
765
|
+
override async findTxLabelMaps(args: FindTxLabelMapsArgs): Promise<TableTxLabelMap[]> {
|
|
766
|
+
const q = this.findTxLabelMapsQuery(args)
|
|
767
|
+
const r = await q
|
|
768
|
+
return this.validateEntities(r, undefined, ['isDeleted'])
|
|
769
|
+
}
|
|
770
|
+
override async findTxLabels(args: FindTxLabelsArgs): Promise<TableTxLabel[]> {
|
|
771
|
+
const q = this.findTxLabelsQuery(args)
|
|
772
|
+
const r = await q
|
|
773
|
+
return this.validateEntities(r, undefined, ['isDeleted'])
|
|
774
|
+
}
|
|
775
|
+
override async findUsers(args: FindUsersArgs): Promise<TableUser[]> {
|
|
776
|
+
const q = this.findUsersQuery(args)
|
|
777
|
+
const r = await q
|
|
778
|
+
return this.validateEntities(r)
|
|
779
|
+
}
|
|
780
|
+
override async findMonitorEvents(args: FindMonitorEventsArgs): Promise<TableMonitorEvent[]> {
|
|
781
|
+
const q = this.findMonitorEventsQuery(args)
|
|
782
|
+
const r = await q
|
|
783
|
+
return this.validateEntities(r, ['when'], undefined)
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
async getCount<T extends object>(q: Knex.QueryBuilder<T, T[]>): Promise<number> {
|
|
787
|
+
q.count()
|
|
788
|
+
const r = await q
|
|
789
|
+
return r[0]['count(*)']
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
override async countCertificateFields(args: FindCertificateFieldsArgs): Promise<number> {
|
|
793
|
+
return await this.getCount(this.findCertificateFieldsQuery(args))
|
|
794
|
+
}
|
|
795
|
+
override async countCertificates(args: FindCertificatesArgs): Promise<number> {
|
|
796
|
+
return await this.getCount(this.findCertificatesQuery(args))
|
|
797
|
+
}
|
|
798
|
+
override async countCommissions(args: FindCommissionsArgs): Promise<number> {
|
|
799
|
+
return await this.getCount(this.findCommissionsQuery(args))
|
|
800
|
+
}
|
|
801
|
+
override async countOutputBaskets(args: FindOutputBasketsArgs): Promise<number> {
|
|
802
|
+
return await this.getCount(this.findOutputBasketsQuery(args))
|
|
803
|
+
}
|
|
804
|
+
override async countOutputs(args: FindOutputsArgs): Promise<number> {
|
|
805
|
+
return await this.getCount(this.findOutputsQuery(args, true))
|
|
806
|
+
}
|
|
807
|
+
override async countOutputTagMaps(args: FindOutputTagMapsArgs): Promise<number> {
|
|
808
|
+
return await this.getCount(this.findOutputTagMapsQuery(args))
|
|
809
|
+
}
|
|
810
|
+
override async countOutputTags(args: FindOutputTagsArgs): Promise<number> {
|
|
811
|
+
return await this.getCount(this.findOutputTagsQuery(args))
|
|
812
|
+
}
|
|
813
|
+
override async countProvenTxReqs(args: FindProvenTxReqsArgs): Promise<number> {
|
|
814
|
+
return await this.getCount(this.findProvenTxReqsQuery(args))
|
|
815
|
+
}
|
|
816
|
+
override async countProvenTxs(args: FindProvenTxsArgs): Promise<number> {
|
|
817
|
+
return await this.getCount(this.findProvenTxsQuery(args))
|
|
818
|
+
}
|
|
819
|
+
override async countSyncStates(args: FindSyncStatesArgs): Promise<number> {
|
|
820
|
+
return await this.getCount(this.findSyncStatesQuery(args))
|
|
821
|
+
}
|
|
822
|
+
override async countTransactions(args: FindTransactionsArgs): Promise<number> {
|
|
823
|
+
return await this.getCount(this.findTransactionsQuery(args, true))
|
|
824
|
+
}
|
|
825
|
+
override async countTxLabelMaps(args: FindTxLabelMapsArgs): Promise<number> {
|
|
826
|
+
return await this.getCount(this.findTxLabelMapsQuery(args))
|
|
827
|
+
}
|
|
828
|
+
override async countTxLabels(args: FindTxLabelsArgs): Promise<number> {
|
|
829
|
+
return await this.getCount(this.findTxLabelsQuery(args))
|
|
830
|
+
}
|
|
831
|
+
override async countUsers(args: FindUsersArgs): Promise<number> {
|
|
832
|
+
return await this.getCount(this.findUsersQuery(args))
|
|
833
|
+
}
|
|
834
|
+
override async countMonitorEvents(args: FindMonitorEventsArgs): Promise<number> {
|
|
835
|
+
return await this.getCount(this.findMonitorEventsQuery(args))
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
override async destroy(): Promise<void> {
|
|
839
|
+
await this.knex?.destroy()
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
override async migrate(storageName: string, storageIdentityKey: string): Promise<string> {
|
|
843
|
+
const config = {
|
|
844
|
+
migrationSource: new KnexMigrations(this.chain, storageName, storageIdentityKey, 1024)
|
|
845
|
+
}
|
|
846
|
+
await this.knex.migrate.latest(config)
|
|
847
|
+
const version = await this.knex.migrate.currentVersion(config)
|
|
848
|
+
return version
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
override async dropAllData(): Promise<void> {
|
|
852
|
+
// Only using migrations to migrate down, don't need valid properties for settings table.
|
|
853
|
+
const config = {
|
|
854
|
+
migrationSource: new KnexMigrations('test', '', '', 1024)
|
|
855
|
+
}
|
|
856
|
+
const count = Object.keys(config.migrationSource.migrations).length
|
|
857
|
+
for (let i = 0; i < count; i++) {
|
|
858
|
+
try {
|
|
859
|
+
const r = await this.knex.migrate.down(config)
|
|
860
|
+
if (!r) {
|
|
861
|
+
console.error(`Migration returned falsy result await this.knex.migrate.down(config)`)
|
|
862
|
+
break
|
|
863
|
+
}
|
|
864
|
+
} catch (eu: unknown) {
|
|
865
|
+
break
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
override async transaction<T>(scope: (trx: TrxToken) => Promise<T>, trx?: TrxToken): Promise<T> {
|
|
871
|
+
if (trx) return await scope(trx)
|
|
872
|
+
|
|
873
|
+
return await this.knex.transaction<T>(async knextrx => {
|
|
874
|
+
const trx = knextrx as TrxToken
|
|
875
|
+
return await scope(trx)
|
|
876
|
+
})
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
/**
|
|
880
|
+
* Convert the standard optional `TrxToken` parameter into either a direct knex database instance,
|
|
881
|
+
* or a Knex.Transaction as appropriate.
|
|
882
|
+
*/
|
|
883
|
+
toDb(trx?: TrxToken) {
|
|
884
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
885
|
+
const db = !trx ? this.knex : <Knex.Transaction<any, any[]>>trx
|
|
886
|
+
this.whenLastAccess = new Date()
|
|
887
|
+
return db
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
async validateRawTransaction(t: TableTransaction, trx?: TrxToken): Promise<void> {
|
|
891
|
+
// if there is no txid or there is a rawTransaction return what we have.
|
|
892
|
+
if (t.rawTx || !t.txid) return
|
|
893
|
+
|
|
894
|
+
// rawTransaction is missing, see if we moved it ...
|
|
895
|
+
|
|
896
|
+
const rawTx = await this.getRawTxOfKnownValidTransaction(t.txid, undefined, undefined, trx)
|
|
897
|
+
if (!rawTx) return
|
|
898
|
+
t.rawTx = rawTx
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
_verifiedReadyForDatabaseAccess: boolean = false
|
|
902
|
+
|
|
903
|
+
/**
|
|
904
|
+
* Make sure database is ready for access:
|
|
905
|
+
*
|
|
906
|
+
* - dateScheme is known
|
|
907
|
+
* - foreign key constraints are enabled
|
|
908
|
+
*
|
|
909
|
+
* @param trx
|
|
910
|
+
*/
|
|
911
|
+
async verifyReadyForDatabaseAccess(trx?: TrxToken): Promise<DBType> {
|
|
912
|
+
if (!this._settings) {
|
|
913
|
+
this._settings = await this.readSettings()
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
if (!this._verifiedReadyForDatabaseAccess) {
|
|
917
|
+
// Make sure foreign key constraint checking is turned on in SQLite.
|
|
918
|
+
if (this._settings.dbtype === 'SQLite') {
|
|
919
|
+
await this.toDb(trx).raw('PRAGMA foreign_keys = ON;')
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
this._verifiedReadyForDatabaseAccess = true
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
return this._settings.dbtype
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
/**
|
|
929
|
+
* Helper to force uniform behavior across database engines.
|
|
930
|
+
* Use to process the update template for entities being updated.
|
|
931
|
+
*/
|
|
932
|
+
validatePartialForUpdate<T extends EntityTimeStamp>(
|
|
933
|
+
update: Partial<T>,
|
|
934
|
+
dateFields?: string[],
|
|
935
|
+
booleanFields?: string[]
|
|
936
|
+
): Partial<T> {
|
|
937
|
+
if (!this.dbtype) throw new WERR_INTERNAL('must call verifyReadyForDatabaseAccess first')
|
|
938
|
+
const v: any = update
|
|
939
|
+
if (v.created_at) v.created_at = this.validateEntityDate(v.created_at)
|
|
940
|
+
if (v.updated_at) v.updated_at = this.validateEntityDate(v.updated_at)
|
|
941
|
+
if (!v.created_at) delete v.created_at
|
|
942
|
+
if (!v.updated_at) v.updated_at = this.validateEntityDate(new Date())
|
|
943
|
+
|
|
944
|
+
if (dateFields) {
|
|
945
|
+
for (const df of dateFields) {
|
|
946
|
+
if (v[df]) v[df] = this.validateOptionalEntityDate(v[df])
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
if (booleanFields) {
|
|
950
|
+
for (const df of booleanFields) {
|
|
951
|
+
if (update[df] !== undefined) update[df] = !!update[df] ? 1 : 0
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
for (const key of Object.keys(v)) {
|
|
955
|
+
const val = v[key]
|
|
956
|
+
if (Array.isArray(val) && (val.length === 0 || typeof val[0] === 'number')) {
|
|
957
|
+
v[key] = Buffer.from(val)
|
|
958
|
+
} else if (val === undefined) {
|
|
959
|
+
v[key] = null
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
this.isDirty = true
|
|
963
|
+
return v
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
/**
|
|
967
|
+
* Helper to force uniform behavior across database engines.
|
|
968
|
+
* Use to process new entities being inserted into the database.
|
|
969
|
+
*/
|
|
970
|
+
async validateEntityForInsert<T extends EntityTimeStamp>(
|
|
971
|
+
entity: T,
|
|
972
|
+
trx?: TrxToken,
|
|
973
|
+
dateFields?: string[],
|
|
974
|
+
booleanFields?: string[]
|
|
975
|
+
): Promise<any> {
|
|
976
|
+
await this.verifyReadyForDatabaseAccess(trx)
|
|
977
|
+
const v: any = { ...entity }
|
|
978
|
+
v.created_at = this.validateOptionalEntityDate(v.created_at, true)!
|
|
979
|
+
v.updated_at = this.validateOptionalEntityDate(v.updated_at, true)!
|
|
980
|
+
if (!v.created_at) delete v.created_at
|
|
981
|
+
if (!v.updated_at) delete v.updated_at
|
|
982
|
+
if (dateFields) {
|
|
983
|
+
for (const df of dateFields) {
|
|
984
|
+
if (v[df]) v[df] = this.validateOptionalEntityDate(v[df])
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
if (booleanFields) {
|
|
988
|
+
for (const df of booleanFields) {
|
|
989
|
+
if (entity[df] !== undefined) entity[df] = !!entity[df] ? 1 : 0
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
for (const key of Object.keys(v)) {
|
|
993
|
+
const val = v[key]
|
|
994
|
+
if (Array.isArray(val) && (val.length === 0 || typeof val[0] === 'number')) {
|
|
995
|
+
v[key] = Buffer.from(val)
|
|
996
|
+
} else if (val === undefined) {
|
|
997
|
+
v[key] = null
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
this.isDirty = true
|
|
1001
|
+
return v
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
override async getLabelsForTransactionId(transactionId?: number, trx?: TrxToken): Promise<TableTxLabel[]> {
|
|
1005
|
+
if (transactionId === undefined) return []
|
|
1006
|
+
const labels = await this.toDb(trx)<TableTxLabel>('tx_labels')
|
|
1007
|
+
.join('tx_labels_map', 'tx_labels_map.txLabelId', 'tx_labels.txLabelId')
|
|
1008
|
+
.where('tx_labels_map.transactionId', transactionId)
|
|
1009
|
+
.whereNot('tx_labels_map.isDeleted', true)
|
|
1010
|
+
.whereNot('tx_labels.isDeleted', true)
|
|
1011
|
+
return this.validateEntities(labels, undefined, ['isDeleted'])
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
override async getTagsForOutputId(outputId: number, trx?: TrxToken): Promise<TableOutputTag[]> {
|
|
1015
|
+
const tags = await this.toDb(trx)<TableOutputTag>('output_tags')
|
|
1016
|
+
.join('output_tags_map', 'output_tags_map.outputTagId', 'output_tags.outputTagId')
|
|
1017
|
+
.where('output_tags_map.outputId', outputId)
|
|
1018
|
+
.whereNot('output_tags_map.isDeleted', true)
|
|
1019
|
+
.whereNot('output_tags.isDeleted', true)
|
|
1020
|
+
return this.validateEntities(tags, undefined, ['isDeleted'])
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
override async purgeData(params: PurgeParams, trx?: TrxToken): Promise<PurgeResults> {
|
|
1024
|
+
return await purgeData(this, params, trx)
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
override async reviewStatus(args: { agedLimit: Date; trx?: TrxToken }): Promise<{ log: string }> {
|
|
1028
|
+
return await reviewStatus(this, args)
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
/**
|
|
1032
|
+
* Counts the outputs for userId in basketId that are spendable: true
|
|
1033
|
+
* AND whose transaction status is one of:
|
|
1034
|
+
* - completed
|
|
1035
|
+
* - unproven
|
|
1036
|
+
* - sending (if excludeSending is false)
|
|
1037
|
+
*/
|
|
1038
|
+
async countChangeInputs(userId: number, basketId: number, excludeSending: boolean): Promise<number> {
|
|
1039
|
+
const status: TransactionStatus[] = ['completed', 'unproven']
|
|
1040
|
+
if (!excludeSending) status.push('sending')
|
|
1041
|
+
const statusText = status.map(s => `'${s}'`).join(',')
|
|
1042
|
+
const txStatusCondition = `(SELECT status FROM transactions WHERE outputs.transactionId = transactions.transactionId) in (${statusText})`
|
|
1043
|
+
let q = this.knex<TableOutput>('outputs').where({ userId, spendable: true, basketId }).whereRaw(txStatusCondition)
|
|
1044
|
+
const count = await this.getCount(q)
|
|
1045
|
+
return count
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
/**
|
|
1049
|
+
* Finds closest matching available change output to use as input for new transaction.
|
|
1050
|
+
*
|
|
1051
|
+
* Transactionally allocate the output such that
|
|
1052
|
+
*/
|
|
1053
|
+
async allocateChangeInput(
|
|
1054
|
+
userId: number,
|
|
1055
|
+
basketId: number,
|
|
1056
|
+
targetSatoshis: number,
|
|
1057
|
+
exactSatoshis: number | undefined,
|
|
1058
|
+
excludeSending: boolean,
|
|
1059
|
+
transactionId: number
|
|
1060
|
+
): Promise<TableOutput | undefined> {
|
|
1061
|
+
const status: TransactionStatus[] = ['completed', 'unproven']
|
|
1062
|
+
if (!excludeSending) status.push('sending')
|
|
1063
|
+
const statusText = status.map(s => `'${s}'`).join(',')
|
|
1064
|
+
|
|
1065
|
+
const r: TableOutput | undefined = await this.knex.transaction(async trx => {
|
|
1066
|
+
const txStatusCondition = `AND (SELECT status FROM transactions WHERE outputs.transactionId = transactions.transactionId) in (${statusText})`
|
|
1067
|
+
|
|
1068
|
+
let outputId: number | undefined
|
|
1069
|
+
const setOutputId = async (rawQuery: string): Promise<void> => {
|
|
1070
|
+
let oidr = await trx.raw(rawQuery)
|
|
1071
|
+
outputId = undefined
|
|
1072
|
+
if (!oidr['outputId'] && oidr.length > 0) oidr = oidr[0]
|
|
1073
|
+
if (!oidr['outputId'] && oidr.length > 0) oidr = oidr[0]
|
|
1074
|
+
if (oidr['outputId']) outputId = Number(oidr['outputId'])
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
if (exactSatoshis !== undefined) {
|
|
1078
|
+
// Find outputId of output that with exactSatoshis
|
|
1079
|
+
await setOutputId(`
|
|
1080
|
+
SELECT outputId
|
|
1081
|
+
FROM outputs
|
|
1082
|
+
WHERE userId = ${userId}
|
|
1083
|
+
AND spendable = 1
|
|
1084
|
+
AND basketId = ${basketId}
|
|
1085
|
+
${txStatusCondition}
|
|
1086
|
+
AND satoshis = ${exactSatoshis}
|
|
1087
|
+
LIMIT 1;
|
|
1088
|
+
`)
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
if (outputId === undefined) {
|
|
1092
|
+
// Find outputId of output that would at least fund targetSatoshis
|
|
1093
|
+
await setOutputId(`
|
|
1094
|
+
SELECT outputId
|
|
1095
|
+
FROM outputs
|
|
1096
|
+
WHERE userId = ${userId}
|
|
1097
|
+
AND spendable = 1
|
|
1098
|
+
AND basketId = ${basketId}
|
|
1099
|
+
${txStatusCondition}
|
|
1100
|
+
AND satoshis - ${targetSatoshis} = (
|
|
1101
|
+
SELECT MIN(satoshis - ${targetSatoshis})
|
|
1102
|
+
FROM outputs
|
|
1103
|
+
WHERE userId = ${userId}
|
|
1104
|
+
AND spendable = 1
|
|
1105
|
+
AND basketId = ${basketId}
|
|
1106
|
+
${txStatusCondition}
|
|
1107
|
+
AND satoshis - ${targetSatoshis} >= 0
|
|
1108
|
+
)
|
|
1109
|
+
LIMIT 1;
|
|
1110
|
+
`)
|
|
1111
|
+
}
|
|
1112
|
+
|
|
1113
|
+
if (outputId === undefined) {
|
|
1114
|
+
// Find outputId of output that would add the most fund targetSatoshis
|
|
1115
|
+
await setOutputId(`
|
|
1116
|
+
SELECT outputId
|
|
1117
|
+
FROM outputs
|
|
1118
|
+
WHERE userId = ${userId}
|
|
1119
|
+
AND spendable = 1
|
|
1120
|
+
AND basketId = ${basketId}
|
|
1121
|
+
${txStatusCondition}
|
|
1122
|
+
AND satoshis - ${targetSatoshis} = (
|
|
1123
|
+
SELECT MAX(satoshis - ${targetSatoshis})
|
|
1124
|
+
FROM outputs
|
|
1125
|
+
WHERE userId = ${userId}
|
|
1126
|
+
AND spendable = 1
|
|
1127
|
+
AND basketId = ${basketId}
|
|
1128
|
+
${txStatusCondition}
|
|
1129
|
+
AND satoshis - ${targetSatoshis} < 0
|
|
1130
|
+
)
|
|
1131
|
+
LIMIT 1;
|
|
1132
|
+
`)
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
if (outputId === undefined) return undefined
|
|
1136
|
+
|
|
1137
|
+
await this.updateOutput(
|
|
1138
|
+
outputId,
|
|
1139
|
+
{
|
|
1140
|
+
spendable: false,
|
|
1141
|
+
spentBy: transactionId
|
|
1142
|
+
},
|
|
1143
|
+
trx
|
|
1144
|
+
)
|
|
1145
|
+
|
|
1146
|
+
const r = verifyTruthy(await this.findOutputById(outputId, trx))
|
|
1147
|
+
return r
|
|
1148
|
+
})
|
|
1149
|
+
|
|
1150
|
+
return r
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
/**
|
|
1154
|
+
* Helper to force uniform behavior across database engines.
|
|
1155
|
+
* Use to process all individual records with time stamps retreived from database.
|
|
1156
|
+
*/
|
|
1157
|
+
validateEntity<T extends EntityTimeStamp>(entity: T, dateFields?: string[], booleanFields?: string[]): T {
|
|
1158
|
+
entity.created_at = this.validateDate(entity.created_at)
|
|
1159
|
+
entity.updated_at = this.validateDate(entity.updated_at)
|
|
1160
|
+
if (dateFields) {
|
|
1161
|
+
for (const df of dateFields) {
|
|
1162
|
+
if (entity[df]) entity[df] = this.validateDate(entity[df])
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
if (booleanFields) {
|
|
1166
|
+
for (const df of booleanFields) {
|
|
1167
|
+
if (entity[df] !== undefined) entity[df] = !!entity[df]
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
for (const key of Object.keys(entity)) {
|
|
1171
|
+
const val = entity[key]
|
|
1172
|
+
if (val === null) {
|
|
1173
|
+
entity[key] = undefined
|
|
1174
|
+
} else if (Buffer.isBuffer(val)) {
|
|
1175
|
+
entity[key] = Array.from(val)
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
return entity
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
/**
|
|
1182
|
+
* Helper to force uniform behavior across database engines.
|
|
1183
|
+
* Use to process all arrays of records with time stamps retreived from database.
|
|
1184
|
+
* @returns input `entities` array with contained values validated.
|
|
1185
|
+
*/
|
|
1186
|
+
validateEntities<T extends EntityTimeStamp>(entities: T[], dateFields?: string[], booleanFields?: string[]): T[] {
|
|
1187
|
+
for (let i = 0; i < entities.length; i++) {
|
|
1188
|
+
entities[i] = this.validateEntity(entities[i], dateFields, booleanFields)
|
|
1189
|
+
}
|
|
1190
|
+
return entities
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
async adminStats(adminIdentityKey: string): Promise<AdminStatsResult> {
|
|
1194
|
+
if (this.dbtype !== 'MySQL') throw new WERR_NOT_IMPLEMENTED('adminStats, only MySQL is supported')
|
|
1195
|
+
|
|
1196
|
+
const monitorEvent = verifyOneOrNone(
|
|
1197
|
+
await this.findMonitorEvents({
|
|
1198
|
+
partial: { event: 'MonitorCallHistory' },
|
|
1199
|
+
orderDescending: true,
|
|
1200
|
+
paged: { limit: 1 }
|
|
1201
|
+
})
|
|
1202
|
+
)
|
|
1203
|
+
const monitorStats: ServicesCallHistory | undefined = monitorEvent ? JSON.parse(monitorEvent.details!) : undefined
|
|
1204
|
+
const servicesStats = this.getServices().getServicesCallHistory(true)
|
|
1205
|
+
await this.insertMonitorEvent({
|
|
1206
|
+
event: 'ServicesCallHistory',
|
|
1207
|
+
details: JSON.stringify(servicesStats),
|
|
1208
|
+
created_at: new Date(),
|
|
1209
|
+
updated_at: new Date(),
|
|
1210
|
+
id: 0
|
|
1211
|
+
})
|
|
1212
|
+
|
|
1213
|
+
const one_day_ago = new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString()
|
|
1214
|
+
const one_week_ago = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString()
|
|
1215
|
+
const one_month_ago = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000).toISOString()
|
|
1216
|
+
|
|
1217
|
+
const [
|
|
1218
|
+
[
|
|
1219
|
+
{
|
|
1220
|
+
usersDay,
|
|
1221
|
+
usersMonth,
|
|
1222
|
+
usersWeek,
|
|
1223
|
+
usersTotal,
|
|
1224
|
+
transactionsDay,
|
|
1225
|
+
transactionsMonth,
|
|
1226
|
+
transactionsWeek,
|
|
1227
|
+
transactionsTotal,
|
|
1228
|
+
txCompletedDay,
|
|
1229
|
+
txCompletedMonth,
|
|
1230
|
+
txCompletedWeek,
|
|
1231
|
+
txCompletedTotal,
|
|
1232
|
+
txFailedDay,
|
|
1233
|
+
txFailedMonth,
|
|
1234
|
+
txFailedWeek,
|
|
1235
|
+
txFailedTotal,
|
|
1236
|
+
txUnprocessedDay,
|
|
1237
|
+
txUnprocessedMonth,
|
|
1238
|
+
txUnprocessedWeek,
|
|
1239
|
+
txUnprocessedTotal,
|
|
1240
|
+
txSendingDay,
|
|
1241
|
+
txSendingMonth,
|
|
1242
|
+
txSendingWeek,
|
|
1243
|
+
txSendingTotal,
|
|
1244
|
+
txUnprovenDay,
|
|
1245
|
+
txUnprovenMonth,
|
|
1246
|
+
txUnprovenWeek,
|
|
1247
|
+
txUnprovenTotal,
|
|
1248
|
+
txUnsignedDay,
|
|
1249
|
+
txUnsignedMonth,
|
|
1250
|
+
txUnsignedWeek,
|
|
1251
|
+
txUnsignedTotal,
|
|
1252
|
+
txNosendDay,
|
|
1253
|
+
txNosendMonth,
|
|
1254
|
+
txNosendWeek,
|
|
1255
|
+
txNosendTotal,
|
|
1256
|
+
txNonfinalDay,
|
|
1257
|
+
txNonfinalMonth,
|
|
1258
|
+
txNonfinalWeek,
|
|
1259
|
+
txNonfinalTotal,
|
|
1260
|
+
txUnfailDay,
|
|
1261
|
+
txUnfailMonth,
|
|
1262
|
+
txUnfailWeek,
|
|
1263
|
+
txUnfailTotal,
|
|
1264
|
+
satoshisDefaultDay,
|
|
1265
|
+
satoshisDefaultMonth,
|
|
1266
|
+
satoshisDefaultWeek,
|
|
1267
|
+
satoshisDefaultTotal,
|
|
1268
|
+
satoshisOtherDay,
|
|
1269
|
+
satoshisOtherMonth,
|
|
1270
|
+
satoshisOtherWeek,
|
|
1271
|
+
satoshisOtherTotal,
|
|
1272
|
+
basketsDay,
|
|
1273
|
+
basketsMonth,
|
|
1274
|
+
basketsWeek,
|
|
1275
|
+
basketsTotal,
|
|
1276
|
+
labelsDay,
|
|
1277
|
+
labelsMonth,
|
|
1278
|
+
labelsWeek,
|
|
1279
|
+
labelsTotal,
|
|
1280
|
+
tagsDay,
|
|
1281
|
+
tagsMonth,
|
|
1282
|
+
tagsWeek,
|
|
1283
|
+
tagsTotal
|
|
1284
|
+
}
|
|
1285
|
+
]
|
|
1286
|
+
] = await this.knex.raw(`
|
|
1287
|
+
select
|
|
1288
|
+
(select count(*) from users where created_at > '${one_day_ago}') as usersDay,
|
|
1289
|
+
(select count(*) from users where created_at > '${one_week_ago}') as usersWeek,
|
|
1290
|
+
(select count(*) from users where created_at > '${one_month_ago}') as usersMonth,
|
|
1291
|
+
(select count(*) from users) as usersTotal,
|
|
1292
|
+
(select count(*) from transactions where created_at > '${one_day_ago}') as transactionsDay,
|
|
1293
|
+
(select count(*) from transactions where created_at > '${one_week_ago}') as transactionsWeek,
|
|
1294
|
+
(select count(*) from transactions where created_at > '${one_month_ago}') as transactionsMonth,
|
|
1295
|
+
(select count(*) from transactions) as transactionsTotal,
|
|
1296
|
+
(select count(*) from transactions where status = 'completed' and created_at > '${one_day_ago}') as txCompletedDay,
|
|
1297
|
+
(select count(*) from transactions where status = 'completed' and created_at > '${one_week_ago}') as txCompletedWeek,
|
|
1298
|
+
(select count(*) from transactions where status = 'completed' and created_at > '${one_month_ago}') as txCompletedMonth,
|
|
1299
|
+
(select count(*) from transactions where status = 'completed') as txCompletedTotal,
|
|
1300
|
+
(select count(*) from transactions where status = 'failed' and created_at > '${one_day_ago}') as txFailedDay,
|
|
1301
|
+
(select count(*) from transactions where status = 'failed' and created_at > '${one_week_ago}') as txFailedWeek,
|
|
1302
|
+
(select count(*) from transactions where status = 'failed' and created_at > '${one_month_ago}') as txFailedMonth,
|
|
1303
|
+
(select count(*) from transactions where status = 'failed') as txFailedTotal,
|
|
1304
|
+
(select count(*) from transactions where status = 'unprocessed' and created_at > '${one_day_ago}') as txUnprocessedDay,
|
|
1305
|
+
(select count(*) from transactions where status = 'unprocessed' and created_at > '${one_week_ago}') as txUnprocessedWeek,
|
|
1306
|
+
(select count(*) from transactions where status = 'unprocessed' and created_at > '${one_month_ago}') as txUnprocessedMonth,
|
|
1307
|
+
(select count(*) from transactions where status = 'unprocessed') as txUnprocessedTotal,
|
|
1308
|
+
(select count(*) from transactions where status = 'sending' and created_at > '${one_day_ago}') as txSendingDay,
|
|
1309
|
+
(select count(*) from transactions where status = 'sending' and created_at > '${one_week_ago}') as txSendingWeek,
|
|
1310
|
+
(select count(*) from transactions where status = 'sending' and created_at > '${one_month_ago}') as txSendingMonth,
|
|
1311
|
+
(select count(*) from transactions where status = 'sending') as txSendingTotal,
|
|
1312
|
+
(select count(*) from transactions where status = 'unproven' and created_at > '${one_day_ago}') as txUnprovenDay,
|
|
1313
|
+
(select count(*) from transactions where status = 'unproven' and created_at > '${one_week_ago}') as txUnprovenWeek,
|
|
1314
|
+
(select count(*) from transactions where status = 'unproven' and created_at > '${one_month_ago}') as txUnprovenMonth,
|
|
1315
|
+
(select count(*) from transactions where status = 'unproven') as txUnprovenTotal,
|
|
1316
|
+
(select count(*) from transactions where status = 'unsigned' and created_at > '${one_day_ago}') as txUnsignedDay,
|
|
1317
|
+
(select count(*) from transactions where status = 'unsigned' and created_at > '${one_week_ago}') as txUnsignedWeek,
|
|
1318
|
+
(select count(*) from transactions where status = 'unsigned' and created_at > '${one_month_ago}') as txUnsignedMonth,
|
|
1319
|
+
(select count(*) from transactions where status = 'unsigned') as txUnsignedTotal,
|
|
1320
|
+
(select count(*) from transactions where status = 'nosend' and created_at > '${one_day_ago}') as txNosendDay,
|
|
1321
|
+
(select count(*) from transactions where status = 'nosend' and created_at > '${one_week_ago}') as txNosendWeek,
|
|
1322
|
+
(select count(*) from transactions where status = 'nosend' and created_at > '${one_month_ago}') as txNosendMonth,
|
|
1323
|
+
(select count(*) from transactions where status = 'nosend') as txNosendTotal,
|
|
1324
|
+
(select count(*) from transactions where status = 'nonfinal' and created_at > '${one_day_ago}') as txNonfinalDay,
|
|
1325
|
+
(select count(*) from transactions where status = 'nonfinal' and created_at > '${one_week_ago}') as txNonfinalWeek,
|
|
1326
|
+
(select count(*) from transactions where status = 'nonfinal' and created_at > '${one_month_ago}') as txNonfinalMonth,
|
|
1327
|
+
(select count(*) from transactions where status = 'nonfinal') as txNonfinalTotal,
|
|
1328
|
+
(select count(*) from transactions where status = 'unfail' and created_at > '${one_day_ago}') as txUnfailDay,
|
|
1329
|
+
(select count(*) from transactions where status = 'unfail' and created_at > '${one_week_ago}') as txUnfailWeek,
|
|
1330
|
+
(select count(*) from transactions where status = 'unfail' and created_at > '${one_month_ago}') as txUnfailMonth,
|
|
1331
|
+
(select count(*) from transactions where status = 'unfail') as txUnfailTotal,
|
|
1332
|
+
(select sum(satoshis) from outputs where spendable = 1 and \`change\` = 1 and created_at > '${one_day_ago}') as satoshisDefaultDay,
|
|
1333
|
+
(select sum(satoshis) from outputs where spendable = 1 and \`change\` = 1 and created_at > '${one_week_ago}') as satoshisDefaultWeek,
|
|
1334
|
+
(select sum(satoshis) from outputs where spendable = 1 and \`change\` = 1 and created_at > '${one_month_ago}') as satoshisDefaultMonth,
|
|
1335
|
+
(select sum(satoshis) from outputs where spendable = 1 and \`change\` = 1) as satoshisDefaultTotal,
|
|
1336
|
+
(select sum(satoshis) from outputs where spendable = 1 and \`change\` = 0 and not basketId is null and created_at > '${one_day_ago}') as satoshisOtherDay,
|
|
1337
|
+
(select sum(satoshis) from outputs where spendable = 1 and \`change\` = 0 and not basketId is null and created_at > '${one_week_ago}') as satoshisOtherWeek,
|
|
1338
|
+
(select sum(satoshis) from outputs where spendable = 1 and \`change\` = 0 and not basketId is null and created_at > '${one_month_ago}') as satoshisOtherMonth,
|
|
1339
|
+
(select sum(satoshis) from outputs where spendable = 1 and \`change\` = 0 and not basketId is null) as satoshisOtherTotal,
|
|
1340
|
+
(select count(*) from output_baskets where created_at > '${one_day_ago}') as basketsDay,
|
|
1341
|
+
(select count(*) from output_baskets where created_at > '${one_week_ago}') as basketsWeek,
|
|
1342
|
+
(select count(*) from output_baskets where created_at > '${one_month_ago}') as basketsMonth,
|
|
1343
|
+
(select count(*) from output_baskets) as basketsTotal,
|
|
1344
|
+
(select count(*) from tx_labels where created_at > '${one_day_ago}') as labelsDay,
|
|
1345
|
+
(select count(*) from tx_labels where created_at > '${one_week_ago}') as labelsWeek,
|
|
1346
|
+
(select count(*) from tx_labels where created_at > '${one_month_ago}') as labelsMonth,
|
|
1347
|
+
(select count(*) from tx_labels) as labelsTotal,
|
|
1348
|
+
(select count(*) from output_tags where created_at > '${one_day_ago}') as tagsDay,
|
|
1349
|
+
(select count(*) from output_tags where created_at > '${one_week_ago}') as tagsWeek,
|
|
1350
|
+
(select count(*) from output_tags where created_at > '${one_month_ago}') as tagsMonth,
|
|
1351
|
+
(select count(*) from output_tags) as tagsTotal
|
|
1352
|
+
`)
|
|
1353
|
+
const r: AdminStatsResult = {
|
|
1354
|
+
monitorStats,
|
|
1355
|
+
servicesStats,
|
|
1356
|
+
requestedBy: adminIdentityKey,
|
|
1357
|
+
when: new Date().toISOString(),
|
|
1358
|
+
usersDay,
|
|
1359
|
+
usersWeek,
|
|
1360
|
+
usersMonth,
|
|
1361
|
+
usersTotal,
|
|
1362
|
+
transactionsDay,
|
|
1363
|
+
transactionsWeek,
|
|
1364
|
+
transactionsMonth,
|
|
1365
|
+
transactionsTotal,
|
|
1366
|
+
txCompletedDay,
|
|
1367
|
+
txCompletedWeek,
|
|
1368
|
+
txCompletedMonth,
|
|
1369
|
+
txCompletedTotal,
|
|
1370
|
+
txFailedDay,
|
|
1371
|
+
txFailedWeek,
|
|
1372
|
+
txFailedMonth,
|
|
1373
|
+
txFailedTotal,
|
|
1374
|
+
txUnprocessedDay,
|
|
1375
|
+
txUnprocessedWeek,
|
|
1376
|
+
txUnprocessedMonth,
|
|
1377
|
+
txUnprocessedTotal,
|
|
1378
|
+
txSendingDay,
|
|
1379
|
+
txSendingWeek,
|
|
1380
|
+
txSendingMonth,
|
|
1381
|
+
txSendingTotal,
|
|
1382
|
+
txUnprovenDay,
|
|
1383
|
+
txUnprovenWeek,
|
|
1384
|
+
txUnprovenMonth,
|
|
1385
|
+
txUnprovenTotal,
|
|
1386
|
+
txUnsignedDay,
|
|
1387
|
+
txUnsignedWeek,
|
|
1388
|
+
txUnsignedMonth,
|
|
1389
|
+
txUnsignedTotal,
|
|
1390
|
+
txNosendDay,
|
|
1391
|
+
txNosendWeek,
|
|
1392
|
+
txNosendMonth,
|
|
1393
|
+
txNosendTotal,
|
|
1394
|
+
txNonfinalDay,
|
|
1395
|
+
txNonfinalWeek,
|
|
1396
|
+
txNonfinalMonth,
|
|
1397
|
+
txNonfinalTotal,
|
|
1398
|
+
txUnfailDay,
|
|
1399
|
+
txUnfailWeek,
|
|
1400
|
+
txUnfailMonth,
|
|
1401
|
+
txUnfailTotal,
|
|
1402
|
+
satoshisDefaultDay: Number(satoshisDefaultDay),
|
|
1403
|
+
satoshisDefaultWeek: Number(satoshisDefaultWeek),
|
|
1404
|
+
satoshisDefaultMonth: Number(satoshisDefaultMonth),
|
|
1405
|
+
satoshisDefaultTotal: Number(satoshisDefaultTotal),
|
|
1406
|
+
satoshisOtherDay: Number(satoshisOtherDay),
|
|
1407
|
+
satoshisOtherWeek: Number(satoshisOtherWeek),
|
|
1408
|
+
satoshisOtherMonth: Number(satoshisOtherMonth),
|
|
1409
|
+
satoshisOtherTotal: Number(satoshisOtherTotal),
|
|
1410
|
+
basketsDay,
|
|
1411
|
+
basketsWeek,
|
|
1412
|
+
basketsMonth,
|
|
1413
|
+
basketsTotal,
|
|
1414
|
+
labelsDay,
|
|
1415
|
+
labelsWeek,
|
|
1416
|
+
labelsMonth,
|
|
1417
|
+
labelsTotal,
|
|
1418
|
+
tagsDay,
|
|
1419
|
+
tagsWeek,
|
|
1420
|
+
tagsMonth,
|
|
1421
|
+
tagsTotal
|
|
1422
|
+
}
|
|
1423
|
+
return r
|
|
1424
|
+
}
|
|
1425
|
+
}
|