@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,350 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Beef,
|
|
3
|
+
BEEF_V1,
|
|
4
|
+
BEEF_V2,
|
|
5
|
+
defaultHttpClient,
|
|
6
|
+
HexString,
|
|
7
|
+
HttpClient,
|
|
8
|
+
HttpClientRequestOptions,
|
|
9
|
+
Random,
|
|
10
|
+
Utils
|
|
11
|
+
} from '@bsv/sdk'
|
|
12
|
+
import { PostBeefResult, PostTxResultForTxid, PostTxResultForTxidError } from '../../sdk/WalletServices.interfaces'
|
|
13
|
+
import { doubleSha256BE } from '../../utility/utilityHelpers'
|
|
14
|
+
import { ReqHistoryNote } from '../../sdk/types'
|
|
15
|
+
import { WalletError } from '../../sdk/WalletError'
|
|
16
|
+
|
|
17
|
+
/** Configuration options for the ARC broadcaster. */
|
|
18
|
+
export interface ArcConfig {
|
|
19
|
+
/** Authentication token for the ARC API */
|
|
20
|
+
apiKey?: string
|
|
21
|
+
/** The HTTP client used to make requests to the ARC API. */
|
|
22
|
+
httpClient?: HttpClient
|
|
23
|
+
/** Deployment id used annotating api calls in XDeployment-ID header - this value will be randomly generated if not set */
|
|
24
|
+
deploymentId?: string
|
|
25
|
+
/** notification callback endpoint for proofs and double spend notification */
|
|
26
|
+
callbackUrl?: string
|
|
27
|
+
/** default access token for notification callback endpoint. It will be used as a Authorization header for the http callback */
|
|
28
|
+
callbackToken?: string
|
|
29
|
+
/** additional headers to be attached to all tx submissions. */
|
|
30
|
+
headers?: Record<string, string>
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function defaultDeploymentId(): string {
|
|
34
|
+
return `ts-sdk-${Utils.toHex(Random(16))}`
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Represents an ARC transaction broadcaster.
|
|
39
|
+
*/
|
|
40
|
+
export class ARC {
|
|
41
|
+
readonly name: string
|
|
42
|
+
readonly URL: string
|
|
43
|
+
readonly apiKey: string | undefined
|
|
44
|
+
readonly deploymentId: string
|
|
45
|
+
readonly callbackUrl: string | undefined
|
|
46
|
+
readonly callbackToken: string | undefined
|
|
47
|
+
readonly headers: Record<string, string> | undefined
|
|
48
|
+
private readonly httpClient: HttpClient
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Constructs an instance of the ARC broadcaster.
|
|
52
|
+
*
|
|
53
|
+
* @param {string} URL - The URL endpoint for the ARC API.
|
|
54
|
+
* @param {ArcConfig} config - Configuration options for the ARC broadcaster.
|
|
55
|
+
*/
|
|
56
|
+
constructor(URL: string, config?: ArcConfig, name?: string)
|
|
57
|
+
/**
|
|
58
|
+
* Constructs an instance of the ARC broadcaster.
|
|
59
|
+
*
|
|
60
|
+
* @param {string} URL - The URL endpoint for the ARC API.
|
|
61
|
+
* @param {string} apiKey - The API key used for authorization with the ARC API.
|
|
62
|
+
*/
|
|
63
|
+
constructor(URL: string, apiKey?: string, name?: string)
|
|
64
|
+
|
|
65
|
+
constructor(URL: string, config?: string | ArcConfig, name?: string) {
|
|
66
|
+
this.name = name ?? 'ARC'
|
|
67
|
+
this.URL = URL
|
|
68
|
+
if (typeof config === 'string') {
|
|
69
|
+
this.apiKey = config
|
|
70
|
+
this.httpClient = defaultHttpClient()
|
|
71
|
+
this.deploymentId = defaultDeploymentId()
|
|
72
|
+
this.callbackToken = undefined
|
|
73
|
+
this.callbackUrl = undefined
|
|
74
|
+
} else {
|
|
75
|
+
const configObj: ArcConfig = config ?? {}
|
|
76
|
+
const { apiKey, deploymentId, httpClient, callbackToken, callbackUrl, headers } = configObj
|
|
77
|
+
this.apiKey = apiKey
|
|
78
|
+
this.httpClient = httpClient ?? defaultHttpClient()
|
|
79
|
+
this.deploymentId = deploymentId ?? defaultDeploymentId()
|
|
80
|
+
this.callbackToken = callbackToken
|
|
81
|
+
this.callbackUrl = callbackUrl
|
|
82
|
+
this.headers = headers
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Constructs a dictionary of the default & supplied request headers.
|
|
88
|
+
*/
|
|
89
|
+
private requestHeaders(): Record<string, string> {
|
|
90
|
+
const headers: Record<string, string> = {
|
|
91
|
+
'Content-Type': 'application/json',
|
|
92
|
+
'XDeployment-ID': this.deploymentId
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (this.apiKey != null && this.apiKey !== '') {
|
|
96
|
+
headers.Authorization = `Bearer ${this.apiKey}`
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (this.callbackUrl != null && this.callbackUrl !== '') {
|
|
100
|
+
headers['X-CallbackUrl'] = this.callbackUrl
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (this.callbackToken != null && this.callbackToken !== '') {
|
|
104
|
+
headers['X-CallbackToken'] = this.callbackToken
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (this.headers != null) {
|
|
108
|
+
for (const key in this.headers) {
|
|
109
|
+
headers[key] = this.headers[key]
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return headers
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* The ARC '/v1/tx' endpoint, as of 2025-02-17 supports all of the following hex string formats:
|
|
118
|
+
* 1. Single serialized raw transaction.
|
|
119
|
+
* 2. Single EF serialized raw transaction (untested).
|
|
120
|
+
* 3. V1 serialized Beef (results returned reflect only the last transaction in the beef)
|
|
121
|
+
*
|
|
122
|
+
* The ARC '/v1/tx' endpoint, as of 2025-02-17 DOES NOT support the following hex string formats:
|
|
123
|
+
* 1. V2 serialized Beef
|
|
124
|
+
*
|
|
125
|
+
* @param rawTx
|
|
126
|
+
* @param txids
|
|
127
|
+
* @returns
|
|
128
|
+
*/
|
|
129
|
+
async postRawTx(rawTx: HexString, txids?: string[]): Promise<PostTxResultForTxid> {
|
|
130
|
+
let txid = Utils.toHex(doubleSha256BE(Utils.toArray(rawTx, 'hex')))
|
|
131
|
+
if (txids) {
|
|
132
|
+
txid = txids.slice(-1)[0]
|
|
133
|
+
} else {
|
|
134
|
+
txids = [txid]
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const requestOptions: HttpClientRequestOptions = {
|
|
138
|
+
method: 'POST',
|
|
139
|
+
headers: this.requestHeaders(),
|
|
140
|
+
data: { rawTx },
|
|
141
|
+
signal: AbortSignal.timeout(1000 * 30) // 30 seconds timeout, error.code will be 'ABORT_ERR'
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const r: PostTxResultForTxid = {
|
|
145
|
+
txid,
|
|
146
|
+
status: 'success',
|
|
147
|
+
notes: []
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const url = `${this.URL}/v1/tx`
|
|
151
|
+
const nn = () => ({ name: this.name, when: new Date().toISOString() })
|
|
152
|
+
const nne = () => ({ ...nn(), rawTx, txids: txids.join(','), url })
|
|
153
|
+
|
|
154
|
+
try {
|
|
155
|
+
const response = await this.httpClient.request<ArcResponse>(url, requestOptions)
|
|
156
|
+
|
|
157
|
+
const { txid, extraInfo, txStatus, competingTxs } = response.data
|
|
158
|
+
const nnr = () => ({
|
|
159
|
+
txid,
|
|
160
|
+
extraInfo,
|
|
161
|
+
txStatus,
|
|
162
|
+
competingTxs: competingTxs?.join(',')
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
if (response.ok) {
|
|
166
|
+
r.data = `${txStatus} ${extraInfo}`
|
|
167
|
+
if (r.txid !== txid) r.data += ` txid altered from ${r.txid} to ${txid}`
|
|
168
|
+
r.txid = txid
|
|
169
|
+
if (txStatus === 'DOUBLE_SPEND_ATTEMPTED' || txStatus === 'SEEN_IN_ORPHAN_MEMPOOL') {
|
|
170
|
+
r.status = 'error'
|
|
171
|
+
r.doubleSpend = true
|
|
172
|
+
r.competingTxs = competingTxs
|
|
173
|
+
r.notes!.push({ ...nne(), ...nnr(), what: 'postRawTxDoubleSpend' })
|
|
174
|
+
} else {
|
|
175
|
+
r.notes!.push({ ...nn(), ...nnr(), what: 'postRawTxSuccess' })
|
|
176
|
+
}
|
|
177
|
+
} else if (typeof response === 'string') {
|
|
178
|
+
r.notes!.push({ ...nne(), what: 'postRawTxString', response })
|
|
179
|
+
r.status = 'error'
|
|
180
|
+
// response is not normally a string
|
|
181
|
+
r.serviceError = true
|
|
182
|
+
} else {
|
|
183
|
+
r.status = 'error'
|
|
184
|
+
// Treat unknown errors as service errors
|
|
185
|
+
r.serviceError = true
|
|
186
|
+
const n: ReqHistoryNote = {
|
|
187
|
+
...nn(),
|
|
188
|
+
...nne(),
|
|
189
|
+
...nnr(),
|
|
190
|
+
what: 'postRawTxError'
|
|
191
|
+
}
|
|
192
|
+
const ed: PostTxResultForTxidError = {}
|
|
193
|
+
r.data = ed
|
|
194
|
+
const st = typeof response.status
|
|
195
|
+
if (st === 'number' || st === 'string') {
|
|
196
|
+
n.status = response.status
|
|
197
|
+
ed.status = response.status.toString()
|
|
198
|
+
} else {
|
|
199
|
+
n.status = st
|
|
200
|
+
ed.status = 'ERR_UNKNOWN'
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
let d = response.data
|
|
204
|
+
if (d && typeof d === 'string') {
|
|
205
|
+
n.data = response.data.slice(0, 128)
|
|
206
|
+
try {
|
|
207
|
+
d = JSON.parse(d)
|
|
208
|
+
} catch {
|
|
209
|
+
// Intentionally left empty
|
|
210
|
+
}
|
|
211
|
+
} else if (d && typeof d === 'object') {
|
|
212
|
+
ed.more = d
|
|
213
|
+
ed.detail = d['detail']
|
|
214
|
+
if (typeof ed.detail !== 'string') ed.detail = undefined
|
|
215
|
+
if (ed.detail) {
|
|
216
|
+
n.detail = ed.detail
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
r.notes!.push(n)
|
|
220
|
+
}
|
|
221
|
+
} catch (eu: unknown) {
|
|
222
|
+
const e = WalletError.fromUnknown(eu)
|
|
223
|
+
r.status = 'error'
|
|
224
|
+
r.serviceError = true
|
|
225
|
+
r.data = `${e.code} ${e.message}`
|
|
226
|
+
r.notes!.push({
|
|
227
|
+
...nne(),
|
|
228
|
+
what: 'postRawTxCatch',
|
|
229
|
+
code: e.code,
|
|
230
|
+
description: e.description
|
|
231
|
+
})
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return r
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* ARC does not natively support a postBeef end-point aware of multiple txids of interest in the Beef.
|
|
239
|
+
*
|
|
240
|
+
* It does process multiple new transactions, however, which allows results for all txids of interest
|
|
241
|
+
* to be collected by the `/v1/tx/${txid}` endpoint.
|
|
242
|
+
*
|
|
243
|
+
* @param beef
|
|
244
|
+
* @param txids
|
|
245
|
+
* @returns
|
|
246
|
+
*/
|
|
247
|
+
async postBeef(beef: Beef, txids: string[]): Promise<PostBeefResult> {
|
|
248
|
+
const r: PostBeefResult = {
|
|
249
|
+
name: this.name,
|
|
250
|
+
status: 'success',
|
|
251
|
+
txidResults: [],
|
|
252
|
+
notes: []
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
const nn = () => ({ name: this.name, when: new Date().toISOString() })
|
|
256
|
+
|
|
257
|
+
if (beef.version === BEEF_V2 && beef.txs.every(btx => !btx.isTxidOnly)) {
|
|
258
|
+
beef.version = BEEF_V1
|
|
259
|
+
r.notes!.push({ ...nn(), what: 'postBeefV2ToV1' })
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
const beefHex = beef.toHex()
|
|
263
|
+
|
|
264
|
+
const prtr = await this.postRawTx(beefHex, txids)
|
|
265
|
+
|
|
266
|
+
r.status = prtr.status
|
|
267
|
+
r.txidResults = [prtr]
|
|
268
|
+
|
|
269
|
+
// Since postRawTx only returns results for a single txid,
|
|
270
|
+
// replicate the basic results any additional txids.
|
|
271
|
+
// TODO: Temporary hack...
|
|
272
|
+
for (const txid of txids) {
|
|
273
|
+
if (prtr.txid === txid) continue
|
|
274
|
+
const tr: PostTxResultForTxid = {
|
|
275
|
+
txid,
|
|
276
|
+
status: 'success',
|
|
277
|
+
notes: []
|
|
278
|
+
}
|
|
279
|
+
// For the extra txids, go back to the service for confirmation...
|
|
280
|
+
const dr = await this.getTxData(txid)
|
|
281
|
+
if (dr.txid !== txid) {
|
|
282
|
+
tr.status = 'error'
|
|
283
|
+
tr.data = 'internal error'
|
|
284
|
+
tr.notes!.push({
|
|
285
|
+
...nn(),
|
|
286
|
+
what: 'postBeefGetTxDataInternal',
|
|
287
|
+
txid,
|
|
288
|
+
returnedTxid: dr.txid
|
|
289
|
+
})
|
|
290
|
+
} else if (dr.txStatus === 'SEEN_ON_NETWORK' || dr.txStatus === 'STORED') {
|
|
291
|
+
tr.data = dr.txStatus
|
|
292
|
+
tr.notes!.push({
|
|
293
|
+
...nn(),
|
|
294
|
+
what: 'postBeefGetTxDataSuccess',
|
|
295
|
+
txid,
|
|
296
|
+
txStatus: dr.txStatus
|
|
297
|
+
})
|
|
298
|
+
} else {
|
|
299
|
+
tr.status = 'error'
|
|
300
|
+
tr.data = dr
|
|
301
|
+
tr.notes!.push({
|
|
302
|
+
...nn(),
|
|
303
|
+
what: 'postBeefGetTxDataError',
|
|
304
|
+
txid,
|
|
305
|
+
txStatus: dr.txStatus
|
|
306
|
+
})
|
|
307
|
+
}
|
|
308
|
+
r.txidResults.push(tr)
|
|
309
|
+
if (r.status === 'success' && tr.status === 'error') r.status = 'error'
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
return r
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* This seems to only work for recently submitted txids...but that's all we need to complete postBeef!
|
|
317
|
+
* @param txid
|
|
318
|
+
* @returns
|
|
319
|
+
*/
|
|
320
|
+
async getTxData(txid: string): Promise<ArcMinerGetTxData> {
|
|
321
|
+
const requestOptions: HttpClientRequestOptions = {
|
|
322
|
+
method: 'GET',
|
|
323
|
+
headers: this.requestHeaders()
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
const response = await this.httpClient.request<ArcMinerGetTxData>(`${this.URL}/v1/tx/${txid}`, requestOptions)
|
|
327
|
+
|
|
328
|
+
return response.data
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
interface ArcResponse {
|
|
333
|
+
txid: string
|
|
334
|
+
extraInfo: string
|
|
335
|
+
txStatus: string
|
|
336
|
+
competingTxs?: string[]
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
export interface ArcMinerGetTxData {
|
|
340
|
+
status: number // 200
|
|
341
|
+
title: string // OK
|
|
342
|
+
blockHash: string
|
|
343
|
+
blockHeight: number
|
|
344
|
+
competingTxs: null | string[]
|
|
345
|
+
extraInfo: string
|
|
346
|
+
merklePath: string
|
|
347
|
+
timestamp: string // ISO Z
|
|
348
|
+
txid: string
|
|
349
|
+
txStatus: string // 'SEEN_IN_ORPHAN_MEMPOOL'
|
|
350
|
+
}
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import { Beef, defaultHttpClient, HexString, HttpClient, Utils } from '@bsv/sdk'
|
|
2
|
+
import { Chain, ReqHistoryNote } from '../../sdk/types'
|
|
3
|
+
import { GetMerklePathResult, PostBeefResult, WalletServices } from '../../sdk/WalletServices.interfaces'
|
|
4
|
+
import { doubleSha256BE } from '../../utility/utilityHelpers'
|
|
5
|
+
import { WalletError } from '../../sdk/WalletError'
|
|
6
|
+
import { convertProofToMerklePath } from '../../utility/tscProofToMerklePath'
|
|
7
|
+
|
|
8
|
+
export interface BitailsConfig {
|
|
9
|
+
/** Authentication token for BitTails API */
|
|
10
|
+
apiKey?: string
|
|
11
|
+
/** The HTTP client used to make requests to the API. */
|
|
12
|
+
httpClient?: HttpClient
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
*
|
|
17
|
+
*/
|
|
18
|
+
export class Bitails {
|
|
19
|
+
readonly chain: Chain
|
|
20
|
+
readonly apiKey: string
|
|
21
|
+
readonly URL: string
|
|
22
|
+
readonly httpClient: HttpClient
|
|
23
|
+
|
|
24
|
+
constructor(chain: Chain = 'main', config: BitailsConfig = {}) {
|
|
25
|
+
const { apiKey, httpClient } = config
|
|
26
|
+
this.chain = chain
|
|
27
|
+
this.URL = chain === 'main' ? `https://api.bitails.io/` : `https://test-api.bitails.io/`
|
|
28
|
+
this.httpClient = httpClient ?? defaultHttpClient()
|
|
29
|
+
this.apiKey = apiKey ?? ''
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
getHttpHeaders(): Record<string, string> {
|
|
33
|
+
const headers: Record<string, string> = {
|
|
34
|
+
Accept: 'application/json'
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (typeof this.apiKey === 'string' && this.apiKey.trim() !== '') {
|
|
38
|
+
headers.Authorization = this.apiKey
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return headers
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Bitails does not natively support a postBeef end-point aware of multiple txids of interest in the Beef.
|
|
46
|
+
*
|
|
47
|
+
* Send rawTx in `txids` order from beef.
|
|
48
|
+
*
|
|
49
|
+
* @param beef
|
|
50
|
+
* @param txids
|
|
51
|
+
* @returns
|
|
52
|
+
*/
|
|
53
|
+
async postBeef(beef: Beef, txids: string[]): Promise<PostBeefResult> {
|
|
54
|
+
const nn = () => ({
|
|
55
|
+
name: 'BitailsPostBeef',
|
|
56
|
+
when: new Date().toISOString()
|
|
57
|
+
})
|
|
58
|
+
const nne = () => ({ ...nn(), beef: beef.toHex(), txids: txids.join(',') })
|
|
59
|
+
|
|
60
|
+
const note: ReqHistoryNote = { ...nn(), what: 'postBeef' }
|
|
61
|
+
|
|
62
|
+
const raws: string[] = []
|
|
63
|
+
for (const txid of txids) {
|
|
64
|
+
const rawTx = Utils.toHex(beef.findTxid(txid)!.rawTx!)
|
|
65
|
+
raws.push(rawTx)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const r = await this.postRaws(raws, txids)
|
|
69
|
+
|
|
70
|
+
r.notes!.unshift(note)
|
|
71
|
+
if (r.status !== 'success') r.notes!.push({ ...nne(), what: 'postBeefError' })
|
|
72
|
+
else r.notes!.push({ ...nn(), what: 'postBeefSuccess' })
|
|
73
|
+
|
|
74
|
+
return r
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* @param raws Array of raw transactions to broadcast as hex strings
|
|
79
|
+
* @param txids Array of txids for transactions in raws for which results are requested, remaining raws are supporting only.
|
|
80
|
+
* @returns
|
|
81
|
+
*/
|
|
82
|
+
async postRaws(raws: HexString[], txids?: string[]): Promise<PostBeefResult> {
|
|
83
|
+
const r: PostBeefResult = {
|
|
84
|
+
name: 'BitailsPostRaws',
|
|
85
|
+
status: 'success',
|
|
86
|
+
txidResults: [],
|
|
87
|
+
notes: []
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const rawTxids: string[] = []
|
|
91
|
+
|
|
92
|
+
for (const raw of raws) {
|
|
93
|
+
const txid = Utils.toHex(doubleSha256BE(Utils.toArray(raw, 'hex')))
|
|
94
|
+
// Results aren't always identified by txid.
|
|
95
|
+
rawTxids.push(txid)
|
|
96
|
+
if (!txids || txids.indexOf(txid) >= 0) {
|
|
97
|
+
r.txidResults.push({
|
|
98
|
+
txid,
|
|
99
|
+
status: 'success',
|
|
100
|
+
notes: []
|
|
101
|
+
})
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const headers = this.getHttpHeaders()
|
|
106
|
+
headers['Content-Type'] = 'application/json'
|
|
107
|
+
//headers['Accept'] = 'text/json'
|
|
108
|
+
|
|
109
|
+
const data = { raws: raws }
|
|
110
|
+
const requestOptions = {
|
|
111
|
+
method: 'POST',
|
|
112
|
+
headers,
|
|
113
|
+
data
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const url = `${this.URL}tx/broadcast/multi`
|
|
117
|
+
const nn = () => ({
|
|
118
|
+
name: 'BitailsPostRawTx',
|
|
119
|
+
when: new Date().toISOString()
|
|
120
|
+
})
|
|
121
|
+
const nne = () => ({
|
|
122
|
+
...nn(),
|
|
123
|
+
raws: raws.join(','),
|
|
124
|
+
txids: r.txidResults.map(r => r.txid).join(','),
|
|
125
|
+
url
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
try {
|
|
129
|
+
const response = await this.httpClient.request<BitailsPostRawsResult[]>(url, requestOptions)
|
|
130
|
+
if (response.ok) {
|
|
131
|
+
// status: 201, statusText: 'Created'
|
|
132
|
+
const btrs: BitailsPostRawsResult[] = response.data
|
|
133
|
+
if (btrs.length !== raws.length) {
|
|
134
|
+
r.status = 'error'
|
|
135
|
+
r.notes!.push({ ...nne(), what: 'postRawsErrorResultsCount' })
|
|
136
|
+
} else {
|
|
137
|
+
// Check that each response result has a txid that matches corresponding rawTxids
|
|
138
|
+
let i = -1
|
|
139
|
+
for (const btr of btrs) {
|
|
140
|
+
i++
|
|
141
|
+
if (!btr.txid) {
|
|
142
|
+
btr.txid = rawTxids[i]
|
|
143
|
+
r.notes!.push({ ...nn(), what: 'postRawsResultMissingTxids', i, rawsTxid: rawTxids[i] })
|
|
144
|
+
} else if (btr.txid !== rawTxids[i]) {
|
|
145
|
+
r.status = 'error'
|
|
146
|
+
r.notes!.push({ ...nn(), what: 'postRawsResultTxids', i, txid: btr.txid, rawsTxid: rawTxids[i] })
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
if (r.status === 'success') {
|
|
150
|
+
// btrs has correct number of results and each one has expected txid.
|
|
151
|
+
// focus on results for requested txids
|
|
152
|
+
for (const rt of r.txidResults) {
|
|
153
|
+
const btr = btrs.find(btr => btr.txid! === rt.txid)!
|
|
154
|
+
const txid = rt.txid
|
|
155
|
+
if (btr.error) {
|
|
156
|
+
// code: -25, message: 'missing-inputs'
|
|
157
|
+
// code: -27, message: 'already-in-mempool'
|
|
158
|
+
const { code, message } = btr.error
|
|
159
|
+
if (code === -27) {
|
|
160
|
+
rt.notes!.push({ ...nne(), what: 'postRawsSuccessAlreadyInMempool' })
|
|
161
|
+
} else {
|
|
162
|
+
rt.status = 'error'
|
|
163
|
+
if (code === -25) {
|
|
164
|
+
rt.doubleSpend = true // this is a possible double spend attempt
|
|
165
|
+
rt.competingTxs = undefined // not provided with any data for this.
|
|
166
|
+
rt.notes!.push({ ...nne(), what: 'postRawsErrorMissingInputs' })
|
|
167
|
+
} else if ((btr['code'] as string) === 'ECONNRESET') {
|
|
168
|
+
rt.notes!.push({ ...nne(), what: 'postRawsErrorECONNRESET', txid, message })
|
|
169
|
+
} else {
|
|
170
|
+
rt.notes!.push({ ...nne(), what: 'postRawsError', txid, code, message })
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
} else {
|
|
174
|
+
rt.notes!.push({ ...nn(), what: 'postRawsSuccess' })
|
|
175
|
+
}
|
|
176
|
+
if (rt.status !== 'success' && r.status === 'success') r.status = 'error'
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
} else {
|
|
181
|
+
r.status = 'error'
|
|
182
|
+
const n: ReqHistoryNote = { ...nne(), what: 'postRawsError' }
|
|
183
|
+
r.notes!.push(n)
|
|
184
|
+
}
|
|
185
|
+
} catch (eu: unknown) {
|
|
186
|
+
r.status = 'error'
|
|
187
|
+
const e = WalletError.fromUnknown(eu)
|
|
188
|
+
const { code, description } = e
|
|
189
|
+
r.notes!.push({ ...nne(), what: 'postRawsCatch', code, description })
|
|
190
|
+
}
|
|
191
|
+
return r
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
*
|
|
196
|
+
* @param txid
|
|
197
|
+
* @param services
|
|
198
|
+
* @returns
|
|
199
|
+
*/
|
|
200
|
+
async getMerklePath(txid: string, services: WalletServices): Promise<GetMerklePathResult> {
|
|
201
|
+
const r: GetMerklePathResult = { name: 'BitailsTsc', notes: [] }
|
|
202
|
+
|
|
203
|
+
const url = `${this.URL}tx/${txid}/proof/tsc`
|
|
204
|
+
|
|
205
|
+
const nn = () => ({ name: 'BitailsProofTsc', when: new Date().toISOString(), txid, url })
|
|
206
|
+
|
|
207
|
+
const headers = this.getHttpHeaders()
|
|
208
|
+
const requestOptions = { method: 'GET', headers }
|
|
209
|
+
|
|
210
|
+
try {
|
|
211
|
+
const response = await this.httpClient.request<BitailsMerkleProof>(url, requestOptions)
|
|
212
|
+
|
|
213
|
+
const nne = () => ({ ...nn(), txid, url, status: response.status, statusText: response.statusText })
|
|
214
|
+
|
|
215
|
+
if (response.status === 404 && response.statusText === 'Not Found') {
|
|
216
|
+
r.notes!.push({ ...nn(), what: 'getMerklePathNotFound' })
|
|
217
|
+
} else if (!response.ok || response.status !== 200 || response.statusText !== 'OK') {
|
|
218
|
+
r.notes!.push({ ...nne(), what: 'getMerklePathBadStatus' })
|
|
219
|
+
} else if (!response.data) {
|
|
220
|
+
r.notes!.push({ ...nne(), what: 'getMerklePathNoData' })
|
|
221
|
+
} else {
|
|
222
|
+
const p = response.data
|
|
223
|
+
const header = await services.hashToHeader(p.target)
|
|
224
|
+
if (header) {
|
|
225
|
+
const proof = { index: p.index, nodes: p.nodes, height: header.height }
|
|
226
|
+
r.merklePath = convertProofToMerklePath(txid, proof)
|
|
227
|
+
r.header = header
|
|
228
|
+
r.notes!.push({ ...nne(), what: 'getMerklePathSuccess' })
|
|
229
|
+
} else {
|
|
230
|
+
r.notes!.push({ ...nne(), what: 'getMerklePathNoHeader', target: p.target })
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
} catch (eu: unknown) {
|
|
234
|
+
const e = WalletError.fromUnknown(eu)
|
|
235
|
+
const { code, description } = e
|
|
236
|
+
r.notes!.push({ ...nn(), what: 'getMerklePathCatch', code, description })
|
|
237
|
+
r.error = e
|
|
238
|
+
}
|
|
239
|
+
return r
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
interface BitailsPostRawsResult {
|
|
244
|
+
txid?: string
|
|
245
|
+
error?: {
|
|
246
|
+
code: number
|
|
247
|
+
message: string
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
export interface BitailsMerkleProof {
|
|
252
|
+
index: number
|
|
253
|
+
txOrId: string
|
|
254
|
+
target: string
|
|
255
|
+
nodes: string[]
|
|
256
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { ChainTracker, defaultHttpClient, HttpClient, WhatsOnChainConfig } from '@bsv/sdk'
|
|
2
|
+
|
|
3
|
+
interface WhatsOnChainBlockHeader {
|
|
4
|
+
merkleroot: string
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Represents a chain tracker based on What's On Chain .
|
|
9
|
+
*/
|
|
10
|
+
export default class SdkWhatsOnChain implements ChainTracker {
|
|
11
|
+
readonly network: string
|
|
12
|
+
readonly apiKey: string
|
|
13
|
+
protected readonly URL: string
|
|
14
|
+
protected readonly httpClient: HttpClient
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Constructs an instance of the WhatsOnChain ChainTracker.
|
|
18
|
+
*
|
|
19
|
+
* @param {'main' | 'test' | 'stn'} network - The BSV network to use when calling the WhatsOnChain API.
|
|
20
|
+
* @param {WhatsOnChainConfig} config - Configuration options for the WhatsOnChain ChainTracker.
|
|
21
|
+
*/
|
|
22
|
+
constructor(network: 'main' | 'test' | 'stn' = 'main', config: WhatsOnChainConfig = {}) {
|
|
23
|
+
const { apiKey, httpClient } = config
|
|
24
|
+
this.network = network
|
|
25
|
+
this.URL = `https://api.whatsonchain.com/v1/bsv/${network}`
|
|
26
|
+
this.httpClient = httpClient ?? defaultHttpClient()
|
|
27
|
+
this.apiKey = apiKey ?? ''
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async isValidRootForHeight(root: string, height: number): Promise<boolean> {
|
|
31
|
+
const requestOptions = {
|
|
32
|
+
method: 'GET',
|
|
33
|
+
headers: this.getHttpHeaders()
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const response = await this.httpClient.request<WhatsOnChainBlockHeader>(
|
|
37
|
+
`${this.URL}/block/${height}/header`,
|
|
38
|
+
requestOptions
|
|
39
|
+
)
|
|
40
|
+
if (response.ok) {
|
|
41
|
+
const { merkleroot } = response.data
|
|
42
|
+
return merkleroot === root
|
|
43
|
+
} else if (response.status === 404) {
|
|
44
|
+
return false
|
|
45
|
+
} else {
|
|
46
|
+
throw new Error(
|
|
47
|
+
`Failed to verify merkleroot for height ${height} because of an error: ${JSON.stringify(response.data)} `
|
|
48
|
+
)
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async currentHeight(): Promise<number> {
|
|
53
|
+
try {
|
|
54
|
+
const requestOptions = {
|
|
55
|
+
method: 'GET',
|
|
56
|
+
headers: this.getHttpHeaders()
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const response = await this.httpClient.request<{ height: number }>(`${this.URL}/block/headers`, requestOptions)
|
|
60
|
+
if (response.ok) {
|
|
61
|
+
return response.data[0].height
|
|
62
|
+
} else {
|
|
63
|
+
throw new Error(`Failed to get current height because of an error: ${JSON.stringify(response.data)} `)
|
|
64
|
+
}
|
|
65
|
+
} catch (error) {
|
|
66
|
+
throw new Error(
|
|
67
|
+
`Failed to get current height because of an error: ${error instanceof Error ? error.message : String(error)}`
|
|
68
|
+
)
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
protected getHttpHeaders(): Record<string, string> {
|
|
73
|
+
const headers: Record<string, string> = {
|
|
74
|
+
Accept: 'application/json'
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (typeof this.apiKey === 'string' && this.apiKey.trim() !== '') {
|
|
78
|
+
headers.Authorization = this.apiKey
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return headers
|
|
82
|
+
}
|
|
83
|
+
}
|