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