@bopen-io/wallet-toolbox 2.6.2-brc153.3 → 2.14.5
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/CHANGELOG.md +744 -1
- package/LICENSES/Open-BSV-License-4-wallet-pre-2026.txt +28 -0
- package/README.md +823 -14
- package/THIRD_PARTY_NOTICES.md +35 -0
- package/docs/README.md +44 -31
- package/docs/action-batch-planning.md +80 -37
- package/docs/client.md +12996 -4571
- package/docs/identity-verification.md +218 -0
- package/docs/local-first-chaintracks.md +129 -0
- package/docs/managed-change-liquidity.md +258 -0
- package/docs/managed-change-policy.md +14 -1
- package/docs/monitor.md +505 -190
- package/docs/no-send-expiry.md +167 -0
- package/docs/prepared-beef.md +197 -0
- package/docs/services.md +4013 -1153
- package/docs/setup.md +107 -56
- package/docs/storage.md +5781 -1599
- package/docs/sync-transfer.md +144 -0
- package/docs/wab-shamir.md +5 -1
- package/docs/wallet.md +10188 -10904
- package/out/src/CWIStyleWalletManager.d.ts +39 -31
- package/out/src/CWIStyleWalletManager.d.ts.map +1 -1
- package/out/src/CWIStyleWalletManager.js +309 -258
- package/out/src/CWIStyleWalletManager.js.map +1 -1
- package/out/src/Setup.d.ts +14 -0
- package/out/src/Setup.d.ts.map +1 -1
- package/out/src/Setup.js +6 -2
- package/out/src/Setup.js.map +1 -1
- package/out/src/SetupClient.d.ts +3 -0
- package/out/src/SetupClient.d.ts.map +1 -1
- package/out/src/SetupClient.js +1 -0
- package/out/src/SetupClient.js.map +1 -1
- package/out/src/SetupWallet.d.ts +3 -0
- package/out/src/SetupWallet.d.ts.map +1 -1
- package/out/src/ShamirWalletManager.d.ts.map +1 -1
- package/out/src/ShamirWalletManager.js +34 -19
- package/out/src/ShamirWalletManager.js.map +1 -1
- package/out/src/SimpleWalletManager.d.ts.map +1 -1
- package/out/src/SimpleWalletManager.js +7 -6
- package/out/src/SimpleWalletManager.js.map +1 -1
- package/out/src/Wallet.d.ts +54 -14
- package/out/src/Wallet.d.ts.map +1 -1
- package/out/src/Wallet.js +216 -114
- package/out/src/Wallet.js.map +1 -1
- package/out/src/WalletAuthenticationManager.d.ts +32 -0
- package/out/src/WalletAuthenticationManager.d.ts.map +1 -1
- package/out/src/WalletAuthenticationManager.js +531 -78
- package/out/src/WalletAuthenticationManager.js.map +1 -1
- package/out/src/WalletLogger.js +1 -1
- package/out/src/WalletLogger.js.map +1 -1
- package/out/src/WalletPermissionsManager.d.ts +101 -43
- package/out/src/WalletPermissionsManager.d.ts.map +1 -1
- package/out/src/WalletPermissionsManager.js +897 -414
- package/out/src/WalletPermissionsManager.js.map +1 -1
- package/out/src/WalletSettingsManager.d.ts +3 -2
- package/out/src/WalletSettingsManager.d.ts.map +1 -1
- package/out/src/WalletSettingsManager.js +143 -8
- package/out/src/WalletSettingsManager.js.map +1 -1
- package/out/src/entropy/EntropyCollector.d.ts.map +1 -1
- package/out/src/entropy/EntropyCollector.js +3 -2
- package/out/src/entropy/EntropyCollector.js.map +1 -1
- package/out/src/fundWalletP2PKH.d.ts.map +1 -1
- package/out/src/fundWalletP2PKH.js +143 -44
- package/out/src/fundWalletP2PKH.js.map +1 -1
- package/out/src/index.client.d.ts +6 -0
- package/out/src/index.client.d.ts.map +1 -1
- package/out/src/index.client.js +16 -1
- package/out/src/index.client.js.map +1 -1
- package/out/src/index.mobile.d.ts +7 -0
- package/out/src/index.mobile.d.ts.map +1 -1
- package/out/src/index.mobile.js +17 -1
- package/out/src/index.mobile.js.map +1 -1
- package/out/src/mockchain/MockChainTracker.d.ts.map +1 -1
- package/out/src/mockchain/MockChainTracker.js +5 -5
- package/out/src/mockchain/MockChainTracker.js.map +1 -1
- package/out/src/mockchain/MockServices.d.ts +2 -0
- package/out/src/mockchain/MockServices.d.ts.map +1 -1
- package/out/src/mockchain/MockServices.js +54 -14
- package/out/src/mockchain/MockServices.js.map +1 -1
- package/out/src/monitor/Monitor.d.ts +51 -0
- package/out/src/monitor/Monitor.d.ts.map +1 -1
- package/out/src/monitor/Monitor.js +282 -41
- package/out/src/monitor/Monitor.js.map +1 -1
- package/out/src/monitor/MonitorDaemon.d.ts.map +1 -1
- package/out/src/monitor/MonitorDaemon.js +64 -16
- package/out/src/monitor/MonitorDaemon.js.map +1 -1
- package/out/src/monitor/monitorValidation.d.ts +12 -0
- package/out/src/monitor/monitorValidation.d.ts.map +1 -0
- package/out/src/monitor/monitorValidation.js +133 -0
- package/out/src/monitor/monitorValidation.js.map +1 -0
- package/out/src/monitor/tasks/TaskArcSSE.d.ts +6 -1
- package/out/src/monitor/tasks/TaskArcSSE.d.ts.map +1 -1
- package/out/src/monitor/tasks/TaskArcSSE.js +117 -74
- package/out/src/monitor/tasks/TaskArcSSE.js.map +1 -1
- package/out/src/monitor/tasks/TaskCheckForProofs.d.ts +5 -0
- package/out/src/monitor/tasks/TaskCheckForProofs.d.ts.map +1 -1
- package/out/src/monitor/tasks/TaskCheckForProofs.js +29 -24
- package/out/src/monitor/tasks/TaskCheckForProofs.js.map +1 -1
- package/out/src/monitor/tasks/TaskCheckNoSends.d.ts.map +1 -1
- package/out/src/monitor/tasks/TaskCheckNoSends.js +11 -3
- package/out/src/monitor/tasks/TaskCheckNoSends.js.map +1 -1
- package/out/src/monitor/tasks/TaskFailAbandoned.d.ts.map +1 -1
- package/out/src/monitor/tasks/TaskFailAbandoned.js +9 -4
- package/out/src/monitor/tasks/TaskFailAbandoned.js.map +1 -1
- package/out/src/monitor/tasks/TaskNewHeader.d.ts.map +1 -1
- package/out/src/monitor/tasks/TaskNewHeader.js +3 -1
- package/out/src/monitor/tasks/TaskNewHeader.js.map +1 -1
- package/out/src/monitor/tasks/TaskNoSendExpiry.d.ts +19 -0
- package/out/src/monitor/tasks/TaskNoSendExpiry.d.ts.map +1 -0
- package/out/src/monitor/tasks/TaskNoSendExpiry.js +47 -0
- package/out/src/monitor/tasks/TaskNoSendExpiry.js.map +1 -0
- package/out/src/monitor/tasks/TaskReconcilePendingTransactions.d.ts +27 -0
- package/out/src/monitor/tasks/TaskReconcilePendingTransactions.d.ts.map +1 -0
- package/out/src/monitor/tasks/TaskReconcilePendingTransactions.js +242 -0
- package/out/src/monitor/tasks/TaskReconcilePendingTransactions.js.map +1 -0
- package/out/src/monitor/tasks/TaskReorg.d.ts.map +1 -1
- package/out/src/monitor/tasks/TaskReorg.js +4 -4
- package/out/src/monitor/tasks/TaskReorg.js.map +1 -1
- package/out/src/monitor/tasks/TaskReviewDoubleSpends.d.ts.map +1 -1
- package/out/src/monitor/tasks/TaskReviewDoubleSpends.js +31 -9
- package/out/src/monitor/tasks/TaskReviewDoubleSpends.js.map +1 -1
- package/out/src/monitor/tasks/TaskReviewProvenTxs.d.ts +18 -1
- package/out/src/monitor/tasks/TaskReviewProvenTxs.d.ts.map +1 -1
- package/out/src/monitor/tasks/TaskReviewProvenTxs.js +99 -21
- package/out/src/monitor/tasks/TaskReviewProvenTxs.js.map +1 -1
- package/out/src/monitor/tasks/TaskReviewUtxos.d.ts +33 -6
- package/out/src/monitor/tasks/TaskReviewUtxos.d.ts.map +1 -1
- package/out/src/monitor/tasks/TaskReviewUtxos.js +189 -13
- package/out/src/monitor/tasks/TaskReviewUtxos.js.map +1 -1
- package/out/src/monitor/tasks/TaskSendWaiting.d.ts.map +1 -1
- package/out/src/monitor/tasks/TaskSendWaiting.js +52 -11
- package/out/src/monitor/tasks/TaskSendWaiting.js.map +1 -1
- package/out/src/monitor/tasks/TaskUnFail.d.ts +1 -0
- package/out/src/monitor/tasks/TaskUnFail.d.ts.map +1 -1
- package/out/src/monitor/tasks/TaskUnFail.js +26 -8
- package/out/src/monitor/tasks/TaskUnFail.js.map +1 -1
- package/out/src/monitor/tasks/index.all.d.ts +2 -0
- package/out/src/monitor/tasks/index.all.d.ts.map +1 -1
- package/out/src/monitor/tasks/index.all.js +2 -0
- package/out/src/monitor/tasks/index.all.js.map +1 -1
- package/out/src/sdk/ActionBatch.interfaces.d.ts +23 -0
- package/out/src/sdk/ActionBatch.interfaces.d.ts.map +1 -1
- package/out/src/sdk/PrivilegedKeyManager.d.ts.map +1 -1
- package/out/src/sdk/PrivilegedKeyManager.js +3 -2
- package/out/src/sdk/PrivilegedKeyManager.js.map +1 -1
- package/out/src/sdk/WERR_errors.d.ts +23 -0
- package/out/src/sdk/WERR_errors.d.ts.map +1 -1
- package/out/src/sdk/WERR_errors.js +51 -7
- package/out/src/sdk/WERR_errors.js.map +1 -1
- package/out/src/sdk/WalletError.d.ts.map +1 -1
- package/out/src/sdk/WalletError.js +7 -21
- package/out/src/sdk/WalletError.js.map +1 -1
- package/out/src/sdk/WalletErrorFromJson.d.ts.map +1 -1
- package/out/src/sdk/WalletErrorFromJson.js +121 -3
- package/out/src/sdk/WalletErrorFromJson.js.map +1 -1
- package/out/src/sdk/WalletServices.interfaces.d.ts +45 -2
- package/out/src/sdk/WalletServices.interfaces.d.ts.map +1 -1
- package/out/src/sdk/WalletStorage.interfaces.d.ts +87 -4
- package/out/src/sdk/WalletStorage.interfaces.d.ts.map +1 -1
- package/out/src/sdk/types.d.ts +3 -2
- package/out/src/sdk/types.d.ts.map +1 -1
- package/out/src/sdk/types.js +3 -2
- package/out/src/sdk/types.js.map +1 -1
- package/out/src/services/ServiceCollection.js +2 -2
- package/out/src/services/ServiceCollection.js.map +1 -1
- package/out/src/services/Services.d.ts +5 -0
- package/out/src/services/Services.d.ts.map +1 -1
- package/out/src/services/Services.js +346 -120
- package/out/src/services/Services.js.map +1 -1
- package/out/src/services/chaintracker/BHServiceClient.d.ts +21 -4
- package/out/src/services/chaintracker/BHServiceClient.d.ts.map +1 -1
- package/out/src/services/chaintracker/BHServiceClient.js +269 -66
- package/out/src/services/chaintracker/BHServiceClient.js.map +1 -1
- package/out/src/services/chaintracker/ChaintracksChainTracker.d.ts +25 -3
- package/out/src/services/chaintracker/ChaintracksChainTracker.d.ts.map +1 -1
- package/out/src/services/chaintracker/ChaintracksChainTracker.js +188 -53
- package/out/src/services/chaintracker/ChaintracksChainTracker.js.map +1 -1
- package/out/src/services/chaintracker/LocalChainTracker.d.ts +122 -0
- package/out/src/services/chaintracker/LocalChainTracker.d.ts.map +1 -0
- package/out/src/services/chaintracker/LocalChainTracker.js +465 -0
- package/out/src/services/chaintracker/LocalChainTracker.js.map +1 -0
- package/out/src/services/chaintracker/chaintracks/Api/BlockHeaderApi.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Api/BlockHeaderApi.js +59 -7
- package/out/src/services/chaintracker/chaintracks/Api/BlockHeaderApi.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Api/BulkFileDataCacheApi.d.ts +48 -0
- package/out/src/services/chaintracker/chaintracks/Api/BulkFileDataCacheApi.d.ts.map +1 -0
- package/out/src/services/chaintracker/chaintracks/Api/BulkFileDataCacheApi.js +3 -0
- package/out/src/services/chaintracker/chaintracks/Api/BulkFileDataCacheApi.js.map +1 -0
- package/out/src/services/chaintracker/chaintracks/Api/BulkFileDataValidatorApi.d.ts +70 -0
- package/out/src/services/chaintracker/chaintracks/Api/BulkFileDataValidatorApi.d.ts.map +1 -0
- package/out/src/services/chaintracker/chaintracks/Api/BulkFileDataValidatorApi.js +21 -0
- package/out/src/services/chaintracker/chaintracks/Api/BulkFileDataValidatorApi.js.map +1 -0
- package/out/src/services/chaintracker/chaintracks/Api/ChaintracksApi.d.ts +6 -0
- package/out/src/services/chaintracker/chaintracks/Api/ChaintracksApi.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Api/ChaintracksClientApi.d.ts +53 -0
- package/out/src/services/chaintracker/chaintracks/Api/ChaintracksClientApi.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Api/ChaintracksFetchApi.d.ts +9 -2
- package/out/src/services/chaintracker/chaintracks/Api/ChaintracksFetchApi.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Api/ChaintracksStorageApi.d.ts +9 -0
- package/out/src/services/chaintracker/chaintracks/Api/ChaintracksStorageApi.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Chaintracks.d.ts +28 -3
- package/out/src/services/chaintracker/chaintracks/Chaintracks.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Chaintracks.js +282 -64
- package/out/src/services/chaintracker/chaintracks/Chaintracks.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/ChaintracksService.d.ts +16 -0
- package/out/src/services/chaintracker/chaintracks/ChaintracksService.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/ChaintracksService.js +150 -26
- package/out/src/services/chaintracker/chaintracks/ChaintracksService.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/ChaintracksServiceClient.d.ts +30 -1
- package/out/src/services/chaintracker/chaintracks/ChaintracksServiceClient.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/ChaintracksServiceClient.js +348 -30
- package/out/src/services/chaintracker/chaintracks/ChaintracksServiceClient.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/GoChaintracksServiceClient.d.ts +32 -1
- package/out/src/services/chaintracker/chaintracks/GoChaintracksServiceClient.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/GoChaintracksServiceClient.js +378 -44
- package/out/src/services/chaintracker/chaintracks/GoChaintracksServiceClient.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Ingest/BulkIngestorBase.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Ingest/BulkIngestorBase.js +28 -3
- package/out/src/services/chaintracker/chaintracks/Ingest/BulkIngestorBase.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Ingest/BulkIngestorCDN.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Ingest/BulkIngestorCDN.js +33 -9
- package/out/src/services/chaintracker/chaintracks/Ingest/BulkIngestorCDN.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Ingest/BulkIngestorCDNBabbage.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Ingest/BulkIngestorCDNBabbage.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Ingest/BulkIngestorChaintracks.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Ingest/BulkIngestorChaintracks.js +4 -2
- package/out/src/services/chaintracker/chaintracks/Ingest/BulkIngestorChaintracks.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Ingest/BulkIngestorWhatsOnChainCdn.d.ts +2 -0
- package/out/src/services/chaintracker/chaintracks/Ingest/BulkIngestorWhatsOnChainCdn.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Ingest/BulkIngestorWhatsOnChainCdn.js +17 -4
- package/out/src/services/chaintracker/chaintracks/Ingest/BulkIngestorWhatsOnChainCdn.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Ingest/BulkIngestorWhatsOnChainWs.d.ts +2 -0
- package/out/src/services/chaintracker/chaintracks/Ingest/BulkIngestorWhatsOnChainWs.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Ingest/BulkIngestorWhatsOnChainWs.js +40 -20
- package/out/src/services/chaintracker/chaintracks/Ingest/BulkIngestorWhatsOnChainWs.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Ingest/LiveIngestorBase.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Ingest/LiveIngestorBase.js +14 -0
- package/out/src/services/chaintracker/chaintracks/Ingest/LiveIngestorBase.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Ingest/LiveIngestorChaintracksSSE.d.ts +6 -0
- package/out/src/services/chaintracker/chaintracks/Ingest/LiveIngestorChaintracksSSE.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Ingest/LiveIngestorChaintracksSSE.js +56 -9
- package/out/src/services/chaintracker/chaintracks/Ingest/LiveIngestorChaintracksSSE.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Ingest/LiveIngestorTeranodeP2P.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Ingest/LiveIngestorTeranodeP2P.js +6 -3
- package/out/src/services/chaintracker/chaintracks/Ingest/LiveIngestorTeranodeP2P.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Ingest/LiveIngestorWhatsOnChainPoll.d.ts +4 -0
- package/out/src/services/chaintracker/chaintracks/Ingest/LiveIngestorWhatsOnChainPoll.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Ingest/LiveIngestorWhatsOnChainPoll.js +27 -9
- package/out/src/services/chaintracker/chaintracks/Ingest/LiveIngestorWhatsOnChainPoll.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Ingest/LiveIngestorWhatsOnChainWs.d.ts +8 -0
- package/out/src/services/chaintracker/chaintracks/Ingest/LiveIngestorWhatsOnChainWs.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Ingest/LiveIngestorWhatsOnChainWs.js +49 -5
- package/out/src/services/chaintracker/chaintracks/Ingest/LiveIngestorWhatsOnChainWs.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Ingest/WhatsOnChainIngestorWs.d.ts +1 -1
- package/out/src/services/chaintracker/chaintracks/Ingest/WhatsOnChainIngestorWs.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Ingest/WhatsOnChainIngestorWs.js +90 -21
- package/out/src/services/chaintracker/chaintracks/Ingest/WhatsOnChainIngestorWs.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Ingest/WhatsOnChainServices.d.ts +3 -1
- package/out/src/services/chaintracker/chaintracks/Ingest/WhatsOnChainServices.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Ingest/WhatsOnChainServices.js +185 -38
- package/out/src/services/chaintracker/chaintracks/Ingest/WhatsOnChainServices.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Storage/BulkStorageBase.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Storage/BulkStorageBase.js +59 -6
- package/out/src/services/chaintracker/chaintracks/Storage/BulkStorageBase.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksKnexMigrations.d.ts +2 -0
- package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksKnexMigrations.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksKnexMigrations.js +89 -39
- package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksKnexMigrations.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageBase.d.ts +10 -0
- package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageBase.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageBase.js +230 -28
- package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageBase.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageIdb.d.ts +2 -1
- package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageIdb.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageIdb.js +265 -96
- package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageIdb.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageKnex.d.ts +3 -1
- package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageKnex.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageKnex.js +240 -87
- package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageKnex.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageNoDb.d.ts +3 -0
- package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageNoDb.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageNoDb.js +121 -35
- package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageNoDb.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/configureChaintracksIngestors.d.ts +8 -0
- package/out/src/services/chaintracker/chaintracks/configureChaintracksIngestors.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/configureChaintracksIngestors.js +6 -3
- package/out/src/services/chaintracker/chaintracks/configureChaintracksIngestors.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/createDefaultIdbChaintracksOptions.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/createDefaultIdbChaintracksOptions.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/createDefaultKnexChaintracksOptions.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/createDefaultKnexChaintracksOptions.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/createDefaultNoDbChaintracksOptions.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/createDefaultNoDbChaintracksOptions.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/createIdbChaintracks.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/createIdbChaintracks.js +1 -7
- package/out/src/services/chaintracker/chaintracks/createIdbChaintracks.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/createKnexChaintracks.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/createKnexChaintracks.js +1 -7
- package/out/src/services/chaintracker/chaintracks/createKnexChaintracks.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/createNoDbChaintracks.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/createNoDbChaintracks.js +1 -7
- package/out/src/services/chaintracker/chaintracks/createNoDbChaintracks.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/index.all.d.ts +3 -0
- package/out/src/services/chaintracker/chaintracks/index.all.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/index.all.js +3 -0
- package/out/src/services/chaintracker/chaintracks/index.all.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/index.mobile.d.ts +5 -0
- package/out/src/services/chaintracker/chaintracks/index.mobile.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/index.mobile.js +5 -0
- package/out/src/services/chaintracker/chaintracks/index.mobile.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/util/BulkFileDataCacheFs.d.ts +51 -0
- package/out/src/services/chaintracker/chaintracks/util/BulkFileDataCacheFs.d.ts.map +1 -0
- package/out/src/services/chaintracker/chaintracks/util/BulkFileDataCacheFs.js +394 -0
- package/out/src/services/chaintracker/chaintracks/util/BulkFileDataCacheFs.js.map +1 -0
- package/out/src/services/chaintracker/chaintracks/util/BulkFileDataManager.d.ts +45 -1
- package/out/src/services/chaintracker/chaintracks/util/BulkFileDataManager.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/util/BulkFileDataManager.js +733 -166
- package/out/src/services/chaintracker/chaintracks/util/BulkFileDataManager.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/util/BulkFileDataReader.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/util/BulkFileDataReader.js +17 -1
- package/out/src/services/chaintracker/chaintracks/util/BulkFileDataReader.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/util/BulkFileDataValidator.worker.d.ts +32 -0
- package/out/src/services/chaintracker/chaintracks/util/BulkFileDataValidator.worker.d.ts.map +1 -0
- package/out/src/services/chaintracker/chaintracks/util/BulkFileDataValidator.worker.js +40 -0
- package/out/src/services/chaintracker/chaintracks/util/BulkFileDataValidator.worker.js.map +1 -0
- package/out/src/services/chaintracker/chaintracks/util/BulkFilesReader.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/util/BulkFilesReader.js +99 -30
- package/out/src/services/chaintracker/chaintracks/util/BulkFilesReader.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/util/BulkHeaderFile.d.ts +3 -1
- package/out/src/services/chaintracker/chaintracks/util/BulkHeaderFile.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/util/BulkHeaderFile.js +23 -15
- package/out/src/services/chaintracker/chaintracks/util/BulkHeaderFile.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/util/ChaintracksFetch.d.ts +38 -4
- package/out/src/services/chaintracker/chaintracks/util/ChaintracksFetch.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/util/ChaintracksFetch.js +191 -47
- package/out/src/services/chaintracker/chaintracks/util/ChaintracksFetch.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/util/ChaintracksFs.d.ts +2 -1
- package/out/src/services/chaintracker/chaintracks/util/ChaintracksFs.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/util/ChaintracksFs.js +57 -11
- package/out/src/services/chaintracker/chaintracks/util/ChaintracksFs.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/util/DurableFileBulkFileDownloadBudget.d.ts +48 -0
- package/out/src/services/chaintracker/chaintracks/util/DurableFileBulkFileDownloadBudget.d.ts.map +1 -0
- package/out/src/services/chaintracker/chaintracks/util/DurableFileBulkFileDownloadBudget.js +280 -0
- package/out/src/services/chaintracker/chaintracks/util/DurableFileBulkFileDownloadBudget.js.map +1 -0
- package/out/src/services/chaintracker/chaintracks/util/FixedWindowBulkFileDownloadBudget.d.ts +30 -0
- package/out/src/services/chaintracker/chaintracks/util/FixedWindowBulkFileDownloadBudget.d.ts.map +1 -0
- package/out/src/services/chaintracker/chaintracks/util/FixedWindowBulkFileDownloadBudget.js +57 -0
- package/out/src/services/chaintracker/chaintracks/util/FixedWindowBulkFileDownloadBudget.js.map +1 -0
- package/out/src/services/chaintracker/chaintracks/util/HeightRange.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/util/HeightRange.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/util/InlineBulkFileDataValidator.d.ts +14 -0
- package/out/src/services/chaintracker/chaintracks/util/InlineBulkFileDataValidator.d.ts.map +1 -0
- package/out/src/services/chaintracker/chaintracks/util/InlineBulkFileDataValidator.js +148 -0
- package/out/src/services/chaintracker/chaintracks/util/InlineBulkFileDataValidator.js.map +1 -0
- package/out/src/services/chaintracker/chaintracks/util/NodeBulkFileDataValidator.d.ts +41 -0
- package/out/src/services/chaintracker/chaintracks/util/NodeBulkFileDataValidator.d.ts.map +1 -0
- package/out/src/services/chaintracker/chaintracks/util/NodeBulkFileDataValidator.js +271 -0
- package/out/src/services/chaintracker/chaintracks/util/NodeBulkFileDataValidator.js.map +1 -0
- package/out/src/services/chaintracker/chaintracks/util/SingleWriterMultiReaderLock.d.ts +3 -0
- package/out/src/services/chaintracker/chaintracks/util/SingleWriterMultiReaderLock.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/util/SingleWriterMultiReaderLock.js +15 -0
- package/out/src/services/chaintracker/chaintracks/util/SingleWriterMultiReaderLock.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/util/blockHeaderUtilities.d.ts +17 -4
- package/out/src/services/chaintracker/chaintracks/util/blockHeaderUtilities.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/util/blockHeaderUtilities.js +362 -105
- package/out/src/services/chaintracker/chaintracks/util/blockHeaderUtilities.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/util/safeDiagnostic.d.ts +4 -0
- package/out/src/services/chaintracker/chaintracks/util/safeDiagnostic.d.ts.map +1 -0
- package/out/src/services/chaintracker/chaintracks/util/safeDiagnostic.js +33 -0
- package/out/src/services/chaintracker/chaintracks/util/safeDiagnostic.js.map +1 -0
- package/out/src/services/chaintracker/chaintracks/util/validBulkHeaderFilesByFileHash.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/util/validBulkHeaderFilesByFileHash.js.map +1 -1
- package/out/src/services/chaintracker/index.all.d.ts +1 -0
- package/out/src/services/chaintracker/index.all.d.ts.map +1 -1
- package/out/src/services/chaintracker/index.all.js +1 -0
- package/out/src/services/chaintracker/index.all.js.map +1 -1
- package/out/src/services/chaintracker/index.client.d.ts +1 -0
- package/out/src/services/chaintracker/index.client.d.ts.map +1 -1
- package/out/src/services/chaintracker/index.client.js +1 -0
- package/out/src/services/chaintracker/index.client.js.map +1 -1
- package/out/src/services/chaintracker/index.mobile.d.ts +1 -0
- package/out/src/services/chaintracker/index.mobile.d.ts.map +1 -1
- package/out/src/services/chaintracker/index.mobile.js +1 -0
- package/out/src/services/chaintracker/index.mobile.js.map +1 -1
- package/out/src/services/classifyOutputUtxo.d.ts +25 -0
- package/out/src/services/classifyOutputUtxo.d.ts.map +1 -0
- package/out/src/services/classifyOutputUtxo.js +96 -0
- package/out/src/services/classifyOutputUtxo.js.map +1 -0
- package/out/src/services/createDefaultWalletServicesOptions.d.ts +16 -3
- package/out/src/services/createDefaultWalletServicesOptions.d.ts.map +1 -1
- package/out/src/services/createDefaultWalletServicesOptions.js +38 -8
- package/out/src/services/createDefaultWalletServicesOptions.js.map +1 -1
- package/out/src/services/fiatRateValidation.d.ts +12 -0
- package/out/src/services/fiatRateValidation.d.ts.map +1 -0
- package/out/src/services/fiatRateValidation.js +138 -0
- package/out/src/services/fiatRateValidation.js.map +1 -0
- package/out/src/services/getCanonicalMerklePath.d.ts +15 -0
- package/out/src/services/getCanonicalMerklePath.d.ts.map +1 -0
- package/out/src/services/getCanonicalMerklePath.js +90 -0
- package/out/src/services/getCanonicalMerklePath.js.map +1 -0
- package/out/src/services/providers/ARC.d.ts +3 -16
- package/out/src/services/providers/ARC.d.ts.map +1 -1
- package/out/src/services/providers/ARC.js +36 -37
- package/out/src/services/providers/ARC.js.map +1 -1
- package/out/src/services/providers/ArcSSEClient.d.ts +38 -23
- package/out/src/services/providers/ArcSSEClient.d.ts.map +1 -1
- package/out/src/services/providers/ArcSSEClient.js +384 -63
- package/out/src/services/providers/ArcSSEClient.js.map +1 -1
- package/out/src/services/providers/Arcade.d.ts +11 -1
- package/out/src/services/providers/Arcade.d.ts.map +1 -1
- package/out/src/services/providers/Arcade.js +111 -33
- package/out/src/services/providers/Arcade.js.map +1 -1
- package/out/src/services/providers/Bitails.d.ts +3 -0
- package/out/src/services/providers/Bitails.d.ts.map +1 -1
- package/out/src/services/providers/Bitails.js +79 -12
- package/out/src/services/providers/Bitails.js.map +1 -1
- package/out/src/services/providers/SdkWhatsOnChain.d.ts +8 -2
- package/out/src/services/providers/SdkWhatsOnChain.d.ts.map +1 -1
- package/out/src/services/providers/SdkWhatsOnChain.js +83 -10
- package/out/src/services/providers/SdkWhatsOnChain.js.map +1 -1
- package/out/src/services/providers/WhatsOnChain.d.ts +3 -0
- package/out/src/services/providers/WhatsOnChain.d.ts.map +1 -1
- package/out/src/services/providers/WhatsOnChain.js +221 -69
- package/out/src/services/providers/WhatsOnChain.js.map +1 -1
- package/out/src/services/providers/arcProviderConfig.d.ts +27 -0
- package/out/src/services/providers/arcProviderConfig.d.ts.map +1 -0
- package/out/src/services/providers/arcProviderConfig.js +83 -0
- package/out/src/services/providers/arcProviderConfig.js.map +1 -0
- package/out/src/services/providers/arcTxDataValidation.d.ts +4 -0
- package/out/src/services/providers/arcTxDataValidation.d.ts.map +1 -0
- package/out/src/services/providers/arcTxDataValidation.js +92 -0
- package/out/src/services/providers/arcTxDataValidation.js.map +1 -0
- package/out/src/services/providers/arcadeStatus.d.ts +18 -0
- package/out/src/services/providers/arcadeStatus.d.ts.map +1 -0
- package/out/src/services/providers/arcadeStatus.js +56 -0
- package/out/src/services/providers/arcadeStatus.js.map +1 -0
- package/out/src/services/providers/exchangeRates.d.ts +3 -3
- package/out/src/services/providers/exchangeRates.d.ts.map +1 -1
- package/out/src/services/providers/exchangeRates.js +153 -226
- package/out/src/services/providers/exchangeRates.js.map +1 -1
- package/out/src/services/providers/getBeefForTxid.d.ts.map +1 -1
- package/out/src/services/providers/getBeefForTxid.js.map +1 -1
- package/out/src/services/providers/whatsOnChainHelpers.d.ts +2 -2
- package/out/src/services/providers/whatsOnChainHelpers.d.ts.map +1 -1
- package/out/src/services/providers/whatsOnChainHelpers.js +11 -8
- package/out/src/services/providers/whatsOnChainHelpers.js.map +1 -1
- package/out/src/services/validateMerklePathResult.d.ts +30 -0
- package/out/src/services/validateMerklePathResult.d.ts.map +1 -0
- package/out/src/services/validateMerklePathResult.js +272 -0
- package/out/src/services/validateMerklePathResult.js.map +1 -0
- package/out/src/services/validatePostBeefResult.d.ts +17 -0
- package/out/src/services/validatePostBeefResult.d.ts.map +1 -0
- package/out/src/services/validatePostBeefResult.js +334 -0
- package/out/src/services/validatePostBeefResult.js.map +1 -0
- package/out/src/services/validateRawTxResult.d.ts +6 -0
- package/out/src/services/validateRawTxResult.d.ts.map +1 -0
- package/out/src/services/validateRawTxResult.js +77 -0
- package/out/src/services/validateRawTxResult.js.map +1 -0
- package/out/src/services/validateScriptHashHistoryResult.d.ts +5 -0
- package/out/src/services/validateScriptHashHistoryResult.d.ts.map +1 -0
- package/out/src/services/validateScriptHashHistoryResult.js +99 -0
- package/out/src/services/validateScriptHashHistoryResult.js.map +1 -0
- package/out/src/services/validateStatusForTxidsResult.d.ts +8 -0
- package/out/src/services/validateStatusForTxidsResult.d.ts.map +1 -0
- package/out/src/services/validateStatusForTxidsResult.js +181 -0
- package/out/src/services/validateStatusForTxidsResult.js.map +1 -0
- package/out/src/services/validateUtxoStatusResult.d.ts +6 -0
- package/out/src/services/validateUtxoStatusResult.d.ts.map +1 -0
- package/out/src/services/validateUtxoStatusResult.js +126 -0
- package/out/src/services/validateUtxoStatusResult.js.map +1 -0
- package/out/src/signer/actionBatch/ActionBatchPlanner.d.ts +3 -2
- package/out/src/signer/actionBatch/ActionBatchPlanner.d.ts.map +1 -1
- package/out/src/signer/actionBatch/ActionBatchPlanner.js +29 -6
- package/out/src/signer/actionBatch/ActionBatchPlanner.js.map +1 -1
- package/out/src/signer/actionBatch/ActionBatchWorkspace.d.ts +8 -5
- package/out/src/signer/actionBatch/ActionBatchWorkspace.d.ts.map +1 -1
- package/out/src/signer/actionBatch/ActionBatchWorkspace.js +186 -73
- package/out/src/signer/actionBatch/ActionBatchWorkspace.js.map +1 -1
- package/out/src/signer/actionBatch/actionBatchBootstrap.d.ts +2 -2
- package/out/src/signer/actionBatch/actionBatchBootstrap.d.ts.map +1 -1
- package/out/src/signer/actionBatch/actionBatchBootstrap.js +3 -3
- package/out/src/signer/actionBatch/actionBatchBootstrap.js.map +1 -1
- package/out/src/signer/methods/acquireDirectCertificate.d.ts +3 -2
- package/out/src/signer/methods/acquireDirectCertificate.d.ts.map +1 -1
- package/out/src/signer/methods/acquireDirectCertificate.js.map +1 -1
- package/out/src/signer/methods/buildSignableTransaction.d.ts +6 -5
- package/out/src/signer/methods/buildSignableTransaction.d.ts.map +1 -1
- package/out/src/signer/methods/buildSignableTransaction.js +6 -11
- package/out/src/signer/methods/buildSignableTransaction.js.map +1 -1
- package/out/src/signer/methods/createAction.d.ts +4 -3
- package/out/src/signer/methods/createAction.d.ts.map +1 -1
- package/out/src/signer/methods/createAction.js +3 -1
- package/out/src/signer/methods/createAction.js.map +1 -1
- package/out/src/signer/methods/createNoSendExpiryAction.d.ts +7 -0
- package/out/src/signer/methods/createNoSendExpiryAction.d.ts.map +1 -0
- package/out/src/signer/methods/createNoSendExpiryAction.js +254 -0
- package/out/src/signer/methods/createNoSendExpiryAction.js.map +1 -0
- package/out/src/signer/methods/internalizeAction.d.ts.map +1 -1
- package/out/src/signer/methods/internalizeAction.js +9 -5
- package/out/src/signer/methods/internalizeAction.js.map +1 -1
- package/out/src/signer/methods/proveCertificate.d.ts +3 -2
- package/out/src/signer/methods/proveCertificate.d.ts.map +1 -1
- package/out/src/signer/methods/proveCertificate.js.map +1 -1
- package/out/src/signer/methods/signAction.d.ts.map +1 -1
- package/out/src/signer/methods/signAction.js +12 -2
- package/out/src/signer/methods/signAction.js.map +1 -1
- package/out/src/signer/methods/verifyUnlockScripts.d.ts.map +1 -1
- package/out/src/signer/methods/verifyUnlockScripts.js +12 -17
- package/out/src/signer/methods/verifyUnlockScripts.js.map +1 -1
- package/out/src/storage/StorageIdb.d.ts +11 -3
- package/out/src/storage/StorageIdb.d.ts.map +1 -1
- package/out/src/storage/StorageIdb.js +134 -44
- package/out/src/storage/StorageIdb.js.map +1 -1
- package/out/src/storage/StorageKnex.d.ts +68 -7
- package/out/src/storage/StorageKnex.d.ts.map +1 -1
- package/out/src/storage/StorageKnex.js +551 -105
- package/out/src/storage/StorageKnex.js.map +1 -1
- package/out/src/storage/StorageProvider.d.ts +41 -10
- package/out/src/storage/StorageProvider.d.ts.map +1 -1
- package/out/src/storage/StorageProvider.js +397 -107
- package/out/src/storage/StorageProvider.js.map +1 -1
- package/out/src/storage/StorageReader.d.ts +9 -3
- package/out/src/storage/StorageReader.d.ts.map +1 -1
- package/out/src/storage/StorageReader.js +21 -43
- package/out/src/storage/StorageReader.js.map +1 -1
- package/out/src/storage/StorageReaderWriter.d.ts +4 -0
- package/out/src/storage/StorageReaderWriter.d.ts.map +1 -1
- package/out/src/storage/StorageReaderWriter.js +68 -38
- package/out/src/storage/StorageReaderWriter.js.map +1 -1
- package/out/src/storage/StorageSyncReader.d.ts +1 -1
- package/out/src/storage/StorageSyncReader.d.ts.map +1 -1
- package/out/src/storage/StorageSyncReader.js +3 -36
- package/out/src/storage/StorageSyncReader.js.map +1 -1
- package/out/src/storage/WalletStorageManager.d.ts +31 -6
- package/out/src/storage/WalletStorageManager.d.ts.map +1 -1
- package/out/src/storage/WalletStorageManager.js +166 -75
- package/out/src/storage/WalletStorageManager.js.map +1 -1
- package/out/src/storage/adminServer/adminServer.d.ts +3 -1
- package/out/src/storage/adminServer/adminServer.d.ts.map +1 -1
- package/out/src/storage/adminServer/adminServer.js +38 -49
- package/out/src/storage/adminServer/adminServer.js.map +1 -1
- package/out/src/storage/adminServer/adminUi.d.ts.map +1 -1
- package/out/src/storage/adminServer/adminUi.js +32 -9
- package/out/src/storage/adminServer/adminUi.js.map +1 -1
- package/out/src/storage/adminServer/reviewUtxos.d.ts +27 -0
- package/out/src/storage/adminServer/reviewUtxos.d.ts.map +1 -0
- package/out/src/storage/adminServer/reviewUtxos.js +62 -0
- package/out/src/storage/adminServer/reviewUtxos.js.map +1 -0
- package/out/src/storage/idbHelpers.d.ts.map +1 -1
- package/out/src/storage/idbHelpers.js +14 -2
- package/out/src/storage/idbHelpers.js.map +1 -1
- package/out/src/storage/index.all.d.ts +3 -0
- package/out/src/storage/index.all.d.ts.map +1 -1
- package/out/src/storage/index.all.js +3 -0
- package/out/src/storage/index.all.js.map +1 -1
- package/out/src/storage/index.client.d.ts +1 -0
- package/out/src/storage/index.client.d.ts.map +1 -1
- package/out/src/storage/index.client.js +1 -0
- package/out/src/storage/index.client.js.map +1 -1
- package/out/src/storage/index.mobile.d.ts +1 -0
- package/out/src/storage/index.mobile.d.ts.map +1 -1
- package/out/src/storage/index.mobile.js +1 -0
- package/out/src/storage/index.mobile.js.map +1 -1
- package/out/src/storage/methods/ListActionsSpecOp.d.ts +2 -2
- package/out/src/storage/methods/ListActionsSpecOp.d.ts.map +1 -1
- package/out/src/storage/methods/ListActionsSpecOp.js.map +1 -1
- package/out/src/storage/methods/ListOutputsSpecOp.d.ts +7 -4
- package/out/src/storage/methods/ListOutputsSpecOp.d.ts.map +1 -1
- package/out/src/storage/methods/ListOutputsSpecOp.js +5 -44
- package/out/src/storage/methods/ListOutputsSpecOp.js.map +1 -1
- package/out/src/storage/methods/actionBatch.d.ts +9 -2
- package/out/src/storage/methods/actionBatch.d.ts.map +1 -1
- package/out/src/storage/methods/actionBatch.js +260 -67
- package/out/src/storage/methods/actionBatch.js.map +1 -1
- package/out/src/storage/methods/actionBatchBlobs.d.ts +2 -0
- package/out/src/storage/methods/actionBatchBlobs.d.ts.map +1 -1
- package/out/src/storage/methods/actionBatchBlobs.js +47 -26
- package/out/src/storage/methods/actionBatchBlobs.js.map +1 -1
- package/out/src/storage/methods/actionBatchValidation.d.ts.map +1 -1
- package/out/src/storage/methods/actionBatchValidation.js +22 -30
- package/out/src/storage/methods/actionBatchValidation.js.map +1 -1
- package/out/src/storage/methods/attemptToPostReqsToNetwork.d.ts +7 -2
- package/out/src/storage/methods/attemptToPostReqsToNetwork.d.ts.map +1 -1
- package/out/src/storage/methods/attemptToPostReqsToNetwork.js +59 -110
- package/out/src/storage/methods/attemptToPostReqsToNetwork.js.map +1 -1
- package/out/src/storage/methods/availableManagedChange.d.ts +8 -1
- package/out/src/storage/methods/availableManagedChange.d.ts.map +1 -1
- package/out/src/storage/methods/availableManagedChange.js.map +1 -1
- package/out/src/storage/methods/createAction.d.ts +60 -3
- package/out/src/storage/methods/createAction.d.ts.map +1 -1
- package/out/src/storage/methods/createAction.js +391 -107
- package/out/src/storage/methods/createAction.js.map +1 -1
- package/out/src/storage/methods/generateChange.d.ts +15 -5
- package/out/src/storage/methods/generateChange.d.ts.map +1 -1
- package/out/src/storage/methods/generateChange.js +187 -27
- package/out/src/storage/methods/generateChange.js.map +1 -1
- package/out/src/storage/methods/getBeefForTransaction.js +5 -7
- package/out/src/storage/methods/getBeefForTransaction.js.map +1 -1
- package/out/src/storage/methods/getSyncChunk.d.ts.map +1 -1
- package/out/src/storage/methods/getSyncChunk.js +42 -11
- package/out/src/storage/methods/getSyncChunk.js.map +1 -1
- package/out/src/storage/methods/internalizeAction.d.ts +3 -3
- package/out/src/storage/methods/internalizeAction.d.ts.map +1 -1
- package/out/src/storage/methods/internalizeAction.js +172 -135
- package/out/src/storage/methods/internalizeAction.js.map +1 -1
- package/out/src/storage/methods/listActionsIdb.d.ts +3 -2
- package/out/src/storage/methods/listActionsIdb.d.ts.map +1 -1
- package/out/src/storage/methods/listActionsIdb.js +2 -2
- package/out/src/storage/methods/listActionsIdb.js.map +1 -1
- package/out/src/storage/methods/listActionsKnex.d.ts +3 -2
- package/out/src/storage/methods/listActionsKnex.d.ts.map +1 -1
- package/out/src/storage/methods/listActionsKnex.js +22 -11
- package/out/src/storage/methods/listActionsKnex.js.map +1 -1
- package/out/src/storage/methods/listCertificates.d.ts +3 -2
- package/out/src/storage/methods/listCertificates.d.ts.map +1 -1
- package/out/src/storage/methods/listCertificates.js.map +1 -1
- package/out/src/storage/methods/listOutputsIdb.d.ts +3 -2
- package/out/src/storage/methods/listOutputsIdb.d.ts.map +1 -1
- package/out/src/storage/methods/listOutputsIdb.js +25 -18
- package/out/src/storage/methods/listOutputsIdb.js.map +1 -1
- package/out/src/storage/methods/listOutputsKnex.d.ts +3 -2
- package/out/src/storage/methods/listOutputsKnex.d.ts.map +1 -1
- package/out/src/storage/methods/listOutputsKnex.js +32 -30
- package/out/src/storage/methods/listOutputsKnex.js.map +1 -1
- package/out/src/storage/methods/managedChangePolicy.d.ts +44 -0
- package/out/src/storage/methods/managedChangePolicy.d.ts.map +1 -0
- package/out/src/storage/methods/managedChangePolicy.js +58 -0
- package/out/src/storage/methods/managedChangePolicy.js.map +1 -0
- package/out/src/storage/methods/maxPossibleSatoshis.d.ts +13 -0
- package/out/src/storage/methods/maxPossibleSatoshis.d.ts.map +1 -0
- package/out/src/storage/methods/maxPossibleSatoshis.js +16 -0
- package/out/src/storage/methods/maxPossibleSatoshis.js.map +1 -0
- package/out/src/storage/methods/noSendExpiry.d.ts +11 -0
- package/out/src/storage/methods/noSendExpiry.d.ts.map +1 -0
- package/out/src/storage/methods/noSendExpiry.js +359 -0
- package/out/src/storage/methods/noSendExpiry.js.map +1 -0
- package/out/src/storage/methods/noSendExpiryLifecycle.d.ts +14 -0
- package/out/src/storage/methods/noSendExpiryLifecycle.d.ts.map +1 -0
- package/out/src/storage/methods/noSendExpiryLifecycle.js +691 -0
- package/out/src/storage/methods/noSendExpiryLifecycle.js.map +1 -0
- package/out/src/storage/methods/preparedBeef.d.ts +104 -0
- package/out/src/storage/methods/preparedBeef.d.ts.map +1 -0
- package/out/src/storage/methods/preparedBeef.js +524 -0
- package/out/src/storage/methods/preparedBeef.js.map +1 -0
- package/out/src/storage/methods/processAction.d.ts.map +1 -1
- package/out/src/storage/methods/processAction.js +144 -32
- package/out/src/storage/methods/processAction.js.map +1 -1
- package/out/src/storage/methods/purgeData.d.ts.map +1 -1
- package/out/src/storage/methods/purgeData.js +21 -3
- package/out/src/storage/methods/purgeData.js.map +1 -1
- package/out/src/storage/methods/reconcileFailedTransactionInputs.d.ts +32 -0
- package/out/src/storage/methods/reconcileFailedTransactionInputs.d.ts.map +1 -0
- package/out/src/storage/methods/reconcileFailedTransactionInputs.js +142 -0
- package/out/src/storage/methods/reconcileFailedTransactionInputs.js.map +1 -0
- package/out/src/storage/methods/reviewStatus.d.ts.map +1 -1
- package/out/src/storage/methods/reviewStatus.js +7 -4
- package/out/src/storage/methods/reviewStatus.js.map +1 -1
- package/out/src/storage/methods/reviewStatusIdb.d.ts +1 -1
- package/out/src/storage/methods/reviewStatusIdb.d.ts.map +1 -1
- package/out/src/storage/methods/reviewStatusIdb.js.map +1 -1
- package/out/src/storage/methods/reviewUtxoOutputs.d.ts +38 -0
- package/out/src/storage/methods/reviewUtxoOutputs.d.ts.map +1 -0
- package/out/src/storage/methods/reviewUtxoOutputs.js +197 -0
- package/out/src/storage/methods/reviewUtxoOutputs.js.map +1 -0
- package/out/src/storage/methods/validateSyncProof.d.ts +32 -0
- package/out/src/storage/methods/validateSyncProof.d.ts.map +1 -0
- package/out/src/storage/methods/validateSyncProof.js +139 -0
- package/out/src/storage/methods/validateSyncProof.js.map +1 -0
- package/out/src/storage/portable/index.d.ts.map +1 -1
- package/out/src/storage/portable/index.js +25 -15
- package/out/src/storage/portable/index.js.map +1 -1
- package/out/src/storage/remoting/BinaryJson.d.ts +11 -0
- package/out/src/storage/remoting/BinaryJson.d.ts.map +1 -1
- package/out/src/storage/remoting/BinaryJson.js +94 -8
- package/out/src/storage/remoting/BinaryJson.js.map +1 -1
- package/out/src/storage/remoting/KnexPaymentReplayStore.d.ts.map +1 -1
- package/out/src/storage/remoting/KnexPaymentReplayStore.js +1 -0
- package/out/src/storage/remoting/KnexPaymentReplayStore.js.map +1 -1
- package/out/src/storage/remoting/KnexSessionManager.d.ts +26 -2
- package/out/src/storage/remoting/KnexSessionManager.d.ts.map +1 -1
- package/out/src/storage/remoting/KnexSessionManager.js +221 -40
- package/out/src/storage/remoting/KnexSessionManager.js.map +1 -1
- package/out/src/storage/remoting/KnexSyncTransferStore.d.ts +26 -0
- package/out/src/storage/remoting/KnexSyncTransferStore.d.ts.map +1 -0
- package/out/src/storage/remoting/KnexSyncTransferStore.js +222 -0
- package/out/src/storage/remoting/KnexSyncTransferStore.js.map +1 -0
- package/out/src/storage/remoting/StorageClient.d.ts +6 -1
- package/out/src/storage/remoting/StorageClient.d.ts.map +1 -1
- package/out/src/storage/remoting/StorageClient.js +65 -8
- package/out/src/storage/remoting/StorageClient.js.map +1 -1
- package/out/src/storage/remoting/StorageClientBase.d.ts +57 -10
- package/out/src/storage/remoting/StorageClientBase.d.ts.map +1 -1
- package/out/src/storage/remoting/StorageClientBase.js +372 -9
- package/out/src/storage/remoting/StorageClientBase.js.map +1 -1
- package/out/src/storage/remoting/StorageMobile.d.ts +5 -0
- package/out/src/storage/remoting/StorageMobile.d.ts.map +1 -1
- package/out/src/storage/remoting/StorageMobile.js +13 -11
- package/out/src/storage/remoting/StorageMobile.js.map +1 -1
- package/out/src/storage/remoting/StorageServer.d.ts +10 -1
- package/out/src/storage/remoting/StorageServer.d.ts.map +1 -1
- package/out/src/storage/remoting/StorageServer.js +221 -20
- package/out/src/storage/remoting/StorageServer.js.map +1 -1
- package/out/src/storage/remoting/SyncTransfer.d.ts +29 -0
- package/out/src/storage/remoting/SyncTransfer.d.ts.map +1 -0
- package/out/src/storage/remoting/SyncTransfer.js +153 -0
- package/out/src/storage/remoting/SyncTransfer.js.map +1 -0
- package/out/src/storage/remoting/entityValidationHelpers.d.ts.map +1 -1
- package/out/src/storage/remoting/entityValidationHelpers.js +35 -0
- package/out/src/storage/remoting/entityValidationHelpers.js.map +1 -1
- package/out/src/storage/remoting/syncChunkBinary.d.ts +4 -0
- package/out/src/storage/remoting/syncChunkBinary.d.ts.map +1 -0
- package/out/src/storage/remoting/syncChunkBinary.js +38 -0
- package/out/src/storage/remoting/syncChunkBinary.js.map +1 -0
- package/out/src/storage/remoting/validateRpcSyncProofs.d.ts +5 -0
- package/out/src/storage/remoting/validateRpcSyncProofs.d.ts.map +1 -0
- package/out/src/storage/remoting/validateRpcSyncProofs.js +82 -0
- package/out/src/storage/remoting/validateRpcSyncProofs.js.map +1 -0
- package/out/src/storage/schema/KnexMigrations.d.ts +6 -0
- package/out/src/storage/schema/KnexMigrations.d.ts.map +1 -1
- package/out/src/storage/schema/KnexMigrations.js +194 -5
- package/out/src/storage/schema/KnexMigrations.js.map +1 -1
- package/out/src/storage/schema/StorageIdbSchema.d.ts +3 -0
- package/out/src/storage/schema/StorageIdbSchema.d.ts.map +1 -1
- package/out/src/storage/schema/entities/EntityOutput.d.ts.map +1 -1
- package/out/src/storage/schema/entities/EntityOutput.js +24 -4
- package/out/src/storage/schema/entities/EntityOutput.js.map +1 -1
- package/out/src/storage/schema/entities/EntityOutputBasket.d.ts.map +1 -1
- package/out/src/storage/schema/entities/EntityOutputBasket.js +5 -2
- package/out/src/storage/schema/entities/EntityOutputBasket.js.map +1 -1
- package/out/src/storage/schema/entities/EntityProvenTx.d.ts +4 -1
- package/out/src/storage/schema/entities/EntityProvenTx.d.ts.map +1 -1
- package/out/src/storage/schema/entities/EntityProvenTx.js +125 -41
- package/out/src/storage/schema/entities/EntityProvenTx.js.map +1 -1
- package/out/src/storage/schema/entities/EntityProvenTxReq.js +1 -1
- package/out/src/storage/schema/entities/EntityProvenTxReq.js.map +1 -1
- package/out/src/storage/schema/entities/EntitySyncState.d.ts +4 -2
- package/out/src/storage/schema/entities/EntitySyncState.d.ts.map +1 -1
- package/out/src/storage/schema/entities/EntitySyncState.js +12 -6
- package/out/src/storage/schema/entities/EntitySyncState.js.map +1 -1
- package/out/src/storage/schema/entities/EntityTransaction.d.ts +26 -0
- package/out/src/storage/schema/entities/EntityTransaction.d.ts.map +1 -1
- package/out/src/storage/schema/entities/EntityTransaction.js +221 -21
- package/out/src/storage/schema/entities/EntityTransaction.js.map +1 -1
- package/out/src/storage/schema/tables/TableCertificate.d.ts +1 -1
- package/out/src/storage/schema/tables/TableCertificate.d.ts.map +1 -1
- package/out/src/storage/schema/tables/TableCertificateField.d.ts +1 -1
- package/out/src/storage/schema/tables/TableCertificateField.d.ts.map +1 -1
- package/out/src/storage/schema/tables/TableCommission.d.ts +1 -1
- package/out/src/storage/schema/tables/TableCommission.d.ts.map +1 -1
- package/out/src/storage/schema/tables/TableMonitorEvent.d.ts +1 -1
- package/out/src/storage/schema/tables/TableMonitorEvent.d.ts.map +1 -1
- package/out/src/storage/schema/tables/TableOutput.d.ts +1 -1
- package/out/src/storage/schema/tables/TableOutput.d.ts.map +1 -1
- package/out/src/storage/schema/tables/TableOutputBasket.d.ts +1 -1
- package/out/src/storage/schema/tables/TableOutputBasket.d.ts.map +1 -1
- package/out/src/storage/schema/tables/TableOutputTag.d.ts +1 -1
- package/out/src/storage/schema/tables/TableOutputTag.d.ts.map +1 -1
- package/out/src/storage/schema/tables/TableOutputTagMap.d.ts +1 -1
- package/out/src/storage/schema/tables/TableOutputTagMap.d.ts.map +1 -1
- package/out/src/storage/schema/tables/TablePreparedBeef.interfaces.d.ts +23 -0
- package/out/src/storage/schema/tables/TablePreparedBeef.interfaces.d.ts.map +1 -0
- package/out/src/storage/schema/tables/TablePreparedBeef.interfaces.js +3 -0
- package/out/src/storage/schema/tables/TablePreparedBeef.interfaces.js.map +1 -0
- package/out/src/storage/schema/tables/TableProvenTx.d.ts +1 -1
- package/out/src/storage/schema/tables/TableProvenTx.d.ts.map +1 -1
- package/out/src/storage/schema/tables/TableProvenTxReq.d.ts +1 -1
- package/out/src/storage/schema/tables/TableProvenTxReq.d.ts.map +1 -1
- package/out/src/storage/schema/tables/TableSettings.d.ts +2 -2
- package/out/src/storage/schema/tables/TableSettings.d.ts.map +1 -1
- package/out/src/storage/schema/tables/TableSyncState.d.ts +1 -1
- package/out/src/storage/schema/tables/TableSyncState.d.ts.map +1 -1
- package/out/src/storage/schema/tables/TableTransaction.d.ts +17 -1
- package/out/src/storage/schema/tables/TableTransaction.d.ts.map +1 -1
- package/out/src/storage/schema/tables/TableTransaction.js +14 -1
- package/out/src/storage/schema/tables/TableTransaction.js.map +1 -1
- package/out/src/storage/schema/tables/TableTxLabel.d.ts +1 -1
- package/out/src/storage/schema/tables/TableTxLabel.d.ts.map +1 -1
- package/out/src/storage/schema/tables/TableTxLabelMap.d.ts +1 -1
- package/out/src/storage/schema/tables/TableTxLabelMap.d.ts.map +1 -1
- package/out/src/storage/schema/tables/TableUser.d.ts +1 -1
- package/out/src/storage/schema/tables/TableUser.d.ts.map +1 -1
- package/out/src/storage/sync/StorageMySQLDojoReader.d.ts.map +1 -1
- package/out/src/storage/sync/StorageMySQLDojoReader.js +8 -7
- package/out/src/storage/sync/StorageMySQLDojoReader.js.map +1 -1
- package/out/src/storage/sync/SyncPageBudget.d.ts +8 -0
- package/out/src/storage/sync/SyncPageBudget.d.ts.map +1 -0
- package/out/src/storage/sync/SyncPageBudget.js +24 -0
- package/out/src/storage/sync/SyncPageBudget.js.map +1 -0
- package/out/src/storage/sync/syncCheckpoint.d.ts +4 -0
- package/out/src/storage/sync/syncCheckpoint.d.ts.map +1 -0
- package/out/src/storage/sync/syncCheckpoint.js +49 -0
- package/out/src/storage/sync/syncCheckpoint.js.map +1 -0
- package/out/src/utility/Argon2idBackend.d.ts +36 -0
- package/out/src/utility/Argon2idBackend.d.ts.map +1 -0
- package/out/src/utility/Argon2idBackend.js +60 -0
- package/out/src/utility/Argon2idBackend.js.map +1 -0
- package/out/src/utility/actionBatchDigest.d.ts.map +1 -1
- package/out/src/utility/actionBatchDigest.js +9 -7
- package/out/src/utility/actionBatchDigest.js.map +1 -1
- package/out/src/utility/actionBatchPack.d.ts.map +1 -1
- package/out/src/utility/actionBatchPack.js +7 -12
- package/out/src/utility/actionBatchPack.js.map +1 -1
- package/out/src/utility/beefForTxids.d.ts +12 -3
- package/out/src/utility/beefForTxids.d.ts.map +1 -1
- package/out/src/utility/beefForTxids.js +69 -21
- package/out/src/utility/beefForTxids.js.map +1 -1
- package/out/src/utility/brc153ReferenceLabels.d.ts +3 -5
- package/out/src/utility/brc153ReferenceLabels.d.ts.map +1 -1
- package/out/src/utility/brc153ReferenceLabels.js +8 -14
- package/out/src/utility/brc153ReferenceLabels.js.map +1 -1
- package/out/src/utility/brc177NoSendExpiry.d.ts +34 -0
- package/out/src/utility/brc177NoSendExpiry.d.ts.map +1 -0
- package/out/src/utility/brc177NoSendExpiry.js +81 -0
- package/out/src/utility/brc177NoSendExpiry.js.map +1 -0
- package/out/src/utility/canonicalizeAtomicBeef.d.ts +12 -0
- package/out/src/utility/canonicalizeAtomicBeef.d.ts.map +1 -0
- package/out/src/utility/canonicalizeAtomicBeef.js +23 -0
- package/out/src/utility/canonicalizeAtomicBeef.js.map +1 -0
- package/out/src/utility/exactActionSpend.d.ts +9 -0
- package/out/src/utility/exactActionSpend.d.ts.map +1 -0
- package/out/src/utility/exactActionSpend.js +26 -0
- package/out/src/utility/exactActionSpend.js.map +1 -0
- package/out/src/utility/hashWasm.d.ts +1 -1
- package/out/src/utility/hashWasm.d.ts.map +1 -1
- package/out/src/utility/hashWasm.js +83 -1
- package/out/src/utility/hashWasm.js.map +1 -1
- package/out/src/utility/identityUtils.d.ts +44 -4
- package/out/src/utility/identityUtils.d.ts.map +1 -1
- package/out/src/utility/identityUtils.js +523 -61
- package/out/src/utility/identityUtils.js.map +1 -1
- package/out/src/utility/index.all.d.ts +2 -0
- package/out/src/utility/index.all.d.ts.map +1 -1
- package/out/src/utility/index.all.js +2 -0
- package/out/src/utility/index.all.js.map +1 -1
- package/out/src/utility/index.client.d.ts +2 -0
- package/out/src/utility/index.client.d.ts.map +1 -1
- package/out/src/utility/index.client.js +2 -0
- package/out/src/utility/index.client.js.map +1 -1
- package/out/src/utility/parseTxScriptOffsets.d.ts.map +1 -1
- package/out/src/utility/parseTxScriptOffsets.js +1 -19
- package/out/src/utility/parseTxScriptOffsets.js.map +1 -1
- package/out/src/utility/tscProofToMerklePath.d.ts.map +1 -1
- package/out/src/utility/tscProofToMerklePath.js +35 -4
- package/out/src/utility/tscProofToMerklePath.js.map +1 -1
- package/out/src/utility/utilityHelpers.d.ts +1 -1
- package/out/src/utility/utilityHelpers.d.ts.map +1 -1
- package/out/src/utility/utilityHelpers.js +10 -7
- package/out/src/utility/utilityHelpers.js.map +1 -1
- package/out/src/utility/utilityHelpers.noBuffer.d.ts.map +1 -1
- package/out/src/utility/utilityHelpers.noBuffer.js +6 -6
- package/out/src/utility/utilityHelpers.noBuffer.js.map +1 -1
- package/out/src/utility/verifyOverlayOutput.d.ts +12 -0
- package/out/src/utility/verifyOverlayOutput.d.ts.map +1 -0
- package/out/src/utility/verifyOverlayOutput.js +22 -0
- package/out/src/utility/verifyOverlayOutput.js.map +1 -0
- package/out/src/utility/walletResultGuards.d.ts +14 -0
- package/out/src/utility/walletResultGuards.d.ts.map +1 -0
- package/out/src/utility/walletResultGuards.js +28 -0
- package/out/src/utility/walletResultGuards.js.map +1 -0
- package/out/src/wab-client/WABClient.d.ts +4 -17
- package/out/src/wab-client/WABClient.d.ts.map +1 -1
- package/out/src/wab-client/WABClient.js +35 -12
- package/out/src/wab-client/WABClient.js.map +1 -1
- package/out/src/wab-client/WABResponseValidation.d.ts +48 -0
- package/out/src/wab-client/WABResponseValidation.d.ts.map +1 -0
- package/out/src/wab-client/WABResponseValidation.js +321 -0
- package/out/src/wab-client/WABResponseValidation.js.map +1 -0
- package/out/src/wab-client/WABTransport.d.ts +17 -23
- package/out/src/wab-client/WABTransport.d.ts.map +1 -1
- package/out/src/wab-client/WABTransport.js +130 -142
- package/out/src/wab-client/WABTransport.js.map +1 -1
- package/out/src/wab-client/auth-method-interactors/AuthMethodInteractor.d.ts +8 -0
- package/out/src/wab-client/auth-method-interactors/AuthMethodInteractor.d.ts.map +1 -1
- package/out/src/wab-client/auth-method-interactors/AuthMethodInteractor.js +3 -2
- package/out/src/wab-client/auth-method-interactors/AuthMethodInteractor.js.map +1 -1
- package/package.json +40 -33
- package/docs/open-rpc/index.html +0 -46
|
@@ -1,8 +1,94 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.WalletPermissionsManager = void 0;
|
|
4
|
+
const validationHelpers_1 = require("@bsv/sdk/wallet/validationHelpers");
|
|
4
5
|
const sdk_1 = require("@bsv/sdk");
|
|
6
|
+
const utils_1 = require("@bsv/sdk/primitives/utils");
|
|
5
7
|
const brc114ActionTimeLabels_1 = require("./utility/brc114ActionTimeLabels");
|
|
8
|
+
const brc177NoSendExpiry_1 = require("./utility/brc177NoSendExpiry");
|
|
9
|
+
const exactActionSpend_1 = require("./utility/exactActionSpend");
|
|
10
|
+
const WERR_errors_1 = require("./sdk/WERR_errors");
|
|
11
|
+
// Imported from the leaf module directly (not generateChange.ts, which
|
|
12
|
+
// transitively imports StorageProvider.ts and the full signer/create-action
|
|
13
|
+
// module graph) to avoid an unrelated circular-import edge from this file.
|
|
14
|
+
const maxPossibleSatoshis_1 = require("./storage/methods/maxPossibleSatoshis");
|
|
15
|
+
const MAX_PERMISSION_TOKEN_FIELD_BYTES = 1024 * 1024;
|
|
16
|
+
const MAX_PERMISSION_TOKEN_PAYLOAD_BYTES = 4 * 1024 * 1024;
|
|
17
|
+
const MAX_PERMISSION_TOKEN_LIST_FIELDS = 256;
|
|
18
|
+
const MAX_MONEY_SATOSHIS = 21e14;
|
|
19
|
+
function parseCanonicalPermissionInteger(value, label, maximum = Number.MAX_SAFE_INTEGER) {
|
|
20
|
+
if (!/^(?:0|[1-9]\d*)$/.test(value))
|
|
21
|
+
throw new Error(`${label} is not a canonical non-negative integer.`);
|
|
22
|
+
const parsed = Number(value);
|
|
23
|
+
if (!Number.isSafeInteger(parsed) || parsed > maximum) {
|
|
24
|
+
throw new Error(`${label} is outside the supported range.`);
|
|
25
|
+
}
|
|
26
|
+
return parsed;
|
|
27
|
+
}
|
|
28
|
+
function parsePermissionBoolean(value, label) {
|
|
29
|
+
if (value !== 'true' && value !== 'false')
|
|
30
|
+
throw new Error(`${label} must be true or false.`);
|
|
31
|
+
return value === 'true';
|
|
32
|
+
}
|
|
33
|
+
function parsePermissionCertificateFields(value) {
|
|
34
|
+
const parsed = JSON.parse(value);
|
|
35
|
+
if (!Array.isArray(parsed) || parsed.length > MAX_PERMISSION_TOKEN_LIST_FIELDS) {
|
|
36
|
+
throw new Error('Permission certificate fields must be a bounded array.');
|
|
37
|
+
}
|
|
38
|
+
const fields = [];
|
|
39
|
+
const seen = new Set();
|
|
40
|
+
for (const field of parsed) {
|
|
41
|
+
if (typeof field !== 'string' ||
|
|
42
|
+
field.length === 0 ||
|
|
43
|
+
new TextEncoder().encode(field).length >= 50 ||
|
|
44
|
+
seen.has(field)) {
|
|
45
|
+
throw new Error('Permission certificate fields are invalid.');
|
|
46
|
+
}
|
|
47
|
+
seen.add(field);
|
|
48
|
+
fields.push(field);
|
|
49
|
+
}
|
|
50
|
+
return fields;
|
|
51
|
+
}
|
|
52
|
+
function brc177PreflightSatoshis(args) {
|
|
53
|
+
const outputs = args.outputs ?? [];
|
|
54
|
+
let total = 0;
|
|
55
|
+
for (const output of outputs) {
|
|
56
|
+
if (typeof output.satoshis !== 'number' || !Number.isSafeInteger(output.satoshis) || output.satoshis < 0) {
|
|
57
|
+
throw new Error('BRC-177 outputs must contain valid satoshi amounts');
|
|
58
|
+
}
|
|
59
|
+
// A sendMax output is requested with the `maxPossibleSatoshis` sentinel
|
|
60
|
+
// (see storage/methods/generateChange); its real cost is unknowable until
|
|
61
|
+
// storage funds the transaction, so it cannot contribute a meaningful
|
|
62
|
+
// amount to this pre-funding estimate. The real amount is still gated by
|
|
63
|
+
// the post-funding spend check in createAction (computeNetSpend) once it
|
|
64
|
+
// is known.
|
|
65
|
+
if (output.satoshis === maxPossibleSatoshis_1.maxPossibleSatoshis)
|
|
66
|
+
continue;
|
|
67
|
+
total += output.satoshis;
|
|
68
|
+
if (!Number.isSafeInteger(total))
|
|
69
|
+
throw new Error('BRC-177 output amount exceeds the safely supported range');
|
|
70
|
+
}
|
|
71
|
+
// Even an action funded entirely by caller-supplied inputs incurs a wallet
|
|
72
|
+
// prefunding fee. Require a spending grant before that fee can be broadcast.
|
|
73
|
+
return Math.max(1, total);
|
|
74
|
+
}
|
|
75
|
+
function validateBrc177CreateActionShape(args) {
|
|
76
|
+
const request = args;
|
|
77
|
+
if (!Array.isArray(request.outputs) || request.outputs.length === 0) {
|
|
78
|
+
throw new Error('BRC-177 protected actions require at least one output');
|
|
79
|
+
}
|
|
80
|
+
if (request.options?.noSend !== true)
|
|
81
|
+
throw new Error('BRC-177 protected actions require noSend');
|
|
82
|
+
if ((request.options.sendWith?.length ?? 0) > 0) {
|
|
83
|
+
throw new Error('BRC-177 protected actions cannot use sendWith');
|
|
84
|
+
}
|
|
85
|
+
if ((request.options.noSendChange?.length ?? 0) > 0) {
|
|
86
|
+
throw new Error('BRC-177 protected actions cannot supply noSendChange');
|
|
87
|
+
}
|
|
88
|
+
if (request.options.returnTXIDOnly === true) {
|
|
89
|
+
throw new Error('BRC-177 protected actions cannot use returnTXIDOnly');
|
|
90
|
+
}
|
|
91
|
+
}
|
|
6
92
|
// Security invariant: only the configured admin originator bypasses permission
|
|
7
93
|
// prompts. Admin-reserved protocols, baskets, and labels are rejected for all
|
|
8
94
|
// other originators; counterparty bypasses require an explicit configuration
|
|
@@ -61,6 +147,16 @@ const BASKET_MAP = {
|
|
|
61
147
|
* - Token revocation or renewal uses standard BRC-100 flows: we build a transaction that consumes
|
|
62
148
|
* the old token UTXO and outputs a new one (or none, if fully revoked).
|
|
63
149
|
*/
|
|
150
|
+
/**
|
|
151
|
+
* Signing changes the txid, so change outpoints the signable createAction
|
|
152
|
+
* result named (by the unsigned txid) are moved onto the signed transaction.
|
|
153
|
+
* Signing never reorders outputs, so each vout stays the same.
|
|
154
|
+
*/
|
|
155
|
+
function noSendChangeOnSignedTransaction(noSendChange, signedTxid) {
|
|
156
|
+
if (noSendChange === undefined || signedTxid === undefined)
|
|
157
|
+
return noSendChange;
|
|
158
|
+
return noSendChange.map(outpoint => `${signedTxid}.${outpoint.slice(outpoint.lastIndexOf('.') + 1)}`);
|
|
159
|
+
}
|
|
64
160
|
class WalletPermissionsManager {
|
|
65
161
|
/** A reference to the BRC-100 wallet instance. */
|
|
66
162
|
underlying;
|
|
@@ -92,6 +188,23 @@ class WalletPermissionsManager {
|
|
|
92
188
|
/** Cache recently confirmed permissions to avoid repeated lookups. */
|
|
93
189
|
permissionCache = new Map();
|
|
94
190
|
recentGrants = new Map();
|
|
191
|
+
/** Originator binding for partial actions issued through this manager. */
|
|
192
|
+
pendingActionOriginators = new Map();
|
|
193
|
+
/** Exact authorized transaction template for each pending action. */
|
|
194
|
+
pendingActionTemplates = new Map();
|
|
195
|
+
/** References that failed authorization and could not be conclusively aborted. */
|
|
196
|
+
blockedActionReferences = new Set();
|
|
197
|
+
/** Pending references whose action was created with `noSend`. */
|
|
198
|
+
pendingNoSendReferences = new Set();
|
|
199
|
+
/**
|
|
200
|
+
* Originator binding for signed no-send actions, keyed by lowercase txid.
|
|
201
|
+
* Signing drops the pending reference, so without this a non-admin caller
|
|
202
|
+
* could not release the action it created.
|
|
203
|
+
*/
|
|
204
|
+
noSendActions = new Map();
|
|
205
|
+
/** Reference a caller signed a no-send action under, to that action's txid key. */
|
|
206
|
+
noSendActionReferences = new Map();
|
|
207
|
+
permissionTokenLockingKeyPromise;
|
|
95
208
|
/**
|
|
96
209
|
* Token mints currently being written on-chain, keyed by permission cache
|
|
97
210
|
* key. A granted permission is only cached once its token finishes minting
|
|
@@ -100,9 +213,18 @@ class WalletPermissionsManager {
|
|
|
100
213
|
* Stored promises never reject.
|
|
101
214
|
*/
|
|
102
215
|
mintsInFlight = new Map();
|
|
216
|
+
/**
|
|
217
|
+
* Monotonic nonce used to keep spending prompts one-to-one with the wallet
|
|
218
|
+
* operations they authorize. Unlike capability permissions, spending
|
|
219
|
+
* requests must never share a pending approval merely because their amounts
|
|
220
|
+
* happen to match.
|
|
221
|
+
*/
|
|
222
|
+
spendingRequestSequence = 0;
|
|
103
223
|
manifestCache = new Map();
|
|
104
224
|
manifestFetchInProgress = new Map();
|
|
105
225
|
static MANIFEST_CACHE_TTL_MS = 5 * 60 * 1000;
|
|
226
|
+
static MANIFEST_MAX_BYTES = 256 * 1024;
|
|
227
|
+
static MANIFEST_TIMEOUT_MS = 10_000;
|
|
106
228
|
groupedPermissionFlowTail = new Map();
|
|
107
229
|
pactEstablishedCache = new Map();
|
|
108
230
|
/**
|
|
@@ -118,11 +240,6 @@ class WalletPermissionsManager {
|
|
|
118
240
|
static CACHE_TTL_MS = 5 * 60 * 1000;
|
|
119
241
|
/** Window during which freshly granted permissions are auto-allowed (except spending). */
|
|
120
242
|
static RECENT_GRANT_COVER_MS = 15 * 1000;
|
|
121
|
-
/** Default ports used when normalizing originator values. */
|
|
122
|
-
static DEFAULT_PORTS = {
|
|
123
|
-
'http:': '80',
|
|
124
|
-
'https:': '443'
|
|
125
|
-
};
|
|
126
243
|
/**
|
|
127
244
|
* Configuration that determines whether to skip or apply various checks and encryption.
|
|
128
245
|
*/
|
|
@@ -162,7 +279,41 @@ class WalletPermissionsManager {
|
|
|
162
279
|
seekGroupedPermission: true,
|
|
163
280
|
differentiatePrivilegedOperations: true,
|
|
164
281
|
whitelistedCounterparties: {},
|
|
165
|
-
...config
|
|
282
|
+
...config,
|
|
283
|
+
permissionModules: {
|
|
284
|
+
...config.permissionModules,
|
|
285
|
+
// BRC-177 is a built-in reserved BRC-111 module in every Toolbox wallet.
|
|
286
|
+
nosend: {
|
|
287
|
+
onRequest: async (req) => {
|
|
288
|
+
const labels = req.args.labels;
|
|
289
|
+
(0, brc177NoSendExpiry_1.parseBrc177NoSendExpiryLabels)(labels);
|
|
290
|
+
if (req.method !== 'createAction' && req.method !== 'listActions') {
|
|
291
|
+
throw new Error('BRC-177 noSend expiry labels are only valid for createAction and listActions');
|
|
292
|
+
}
|
|
293
|
+
if (req.method === 'createAction')
|
|
294
|
+
validateBrc177CreateActionShape(req.args);
|
|
295
|
+
// Prefunding has a real miner fee, so authorize use of this
|
|
296
|
+
// module before the underlying wallet can broadcast it. This is
|
|
297
|
+
// deliberately separate from the later amount-specific spend
|
|
298
|
+
// authorization for the protected transaction.
|
|
299
|
+
await this.ensureLabelAccess({
|
|
300
|
+
originator: req.originator,
|
|
301
|
+
label: 'BRC-177 noSend expiry',
|
|
302
|
+
reason: req.method,
|
|
303
|
+
usageType: req.method === 'createAction' ? 'apply' : 'list'
|
|
304
|
+
});
|
|
305
|
+
if (req.method === 'createAction') {
|
|
306
|
+
await this.ensureSpendingAuthorization({
|
|
307
|
+
originator: req.originator,
|
|
308
|
+
satoshis: brc177PreflightSatoshis(req.args),
|
|
309
|
+
reason: 'BRC-177 protected action prefunding'
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
return { args: req.args };
|
|
313
|
+
},
|
|
314
|
+
onResponse: async (res) => res
|
|
315
|
+
}
|
|
316
|
+
}
|
|
166
317
|
};
|
|
167
318
|
}
|
|
168
319
|
/* ---------------------------------------------------------------------
|
|
@@ -189,12 +340,19 @@ class WalletPermissionsManager {
|
|
|
189
340
|
if (module == null) {
|
|
190
341
|
throw new Error(`Unsupported P-module scheme: p ${schemeID}`);
|
|
191
342
|
}
|
|
343
|
+
const request = { method, args, originator };
|
|
344
|
+
if (module.handleRequest != null) {
|
|
345
|
+
let nextCalled = false;
|
|
346
|
+
return (await module.handleRequest(request, async (transformedArgs) => {
|
|
347
|
+
if (nextCalled) {
|
|
348
|
+
throw new Error(`P-module p ${schemeID} called its underlying wallet operation more than once`);
|
|
349
|
+
}
|
|
350
|
+
nextCalled = true;
|
|
351
|
+
return await underlyingCall(transformedArgs, originator);
|
|
352
|
+
}));
|
|
353
|
+
}
|
|
192
354
|
// Transform request with module
|
|
193
|
-
const transformedReq = await module.onRequest(
|
|
194
|
-
method,
|
|
195
|
-
args,
|
|
196
|
-
originator
|
|
197
|
-
});
|
|
355
|
+
const transformedReq = await module.onRequest(request);
|
|
198
356
|
// Call underlying method with transformed request
|
|
199
357
|
const results = await underlyingCall(transformedReq.args, originator);
|
|
200
358
|
// Transform response with module
|
|
@@ -393,6 +551,43 @@ class WalletPermissionsManager {
|
|
|
393
551
|
/* ---------------------------------------------------------------------
|
|
394
552
|
* 2) PERMISSION (GRANT / DENY) METHODS
|
|
395
553
|
* --------------------------------------------------------------------- */
|
|
554
|
+
async grantPersistentPermission(request, expiry, amount) {
|
|
555
|
+
const key = this.buildRequestKey(request);
|
|
556
|
+
// Several first-contact prompts for the same permission can stack up
|
|
557
|
+
// before any token exists (e.g. one per usage type). Granting them all
|
|
558
|
+
// should yield ONE token: if an identical non-renewal grant just minted
|
|
559
|
+
// (or is minting), don't mint a duplicate. Spending authorizations are
|
|
560
|
+
// excluded — their tokens carry amounts, so every grant is honored.
|
|
561
|
+
let skipDuplicateMint = !request.renewal &&
|
|
562
|
+
request.type !== 'spending' &&
|
|
563
|
+
(this.isPermissionCached(key) || this.isRecentlyGranted(key) || this.mintsInFlight.has(key));
|
|
564
|
+
if (skipDuplicateMint) {
|
|
565
|
+
const inFlight = this.mintsInFlight.get(key);
|
|
566
|
+
if (inFlight != null) {
|
|
567
|
+
await inFlight;
|
|
568
|
+
// The awaited mint may have failed; only skip if it landed.
|
|
569
|
+
skipDuplicateMint = this.isPermissionCached(key) || this.isRecentlyGranted(key);
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
if (!skipDuplicateMint) {
|
|
573
|
+
const mint = request.renewal
|
|
574
|
+
? this.renewPermissionOnChain(request.previousToken, request, expiry, amount)
|
|
575
|
+
: this.createPermissionOnChain(request, expiry, amount);
|
|
576
|
+
// Publish the in-flight mint so concurrent ensures for the same
|
|
577
|
+
// permission wait for it instead of re-prompting (stored promise
|
|
578
|
+
// never rejects; failures still propagate to this caller below).
|
|
579
|
+
this.mintsInFlight.set(key, mint.then(() => { }, () => { }));
|
|
580
|
+
try {
|
|
581
|
+
await mint;
|
|
582
|
+
}
|
|
583
|
+
finally {
|
|
584
|
+
this.mintsInFlight.delete(key);
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
if (request.type !== 'spending')
|
|
588
|
+
this.cachePermission(key, expiry);
|
|
589
|
+
this.markRecentGrant(request);
|
|
590
|
+
}
|
|
396
591
|
/**
|
|
397
592
|
* Grants a previously requested permission.
|
|
398
593
|
* This method:
|
|
@@ -413,47 +608,10 @@ class WalletPermissionsManager {
|
|
|
413
608
|
x.resolve(true);
|
|
414
609
|
}
|
|
415
610
|
this.activeRequests.delete(params.requestID);
|
|
416
|
-
// 3)
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
const request = matching.request;
|
|
421
|
-
const expiry = params.expiry || 0; // default: never expires
|
|
422
|
-
const key = this.buildRequestKey(request);
|
|
423
|
-
// Several first-contact prompts for the same permission can stack up
|
|
424
|
-
// before any token exists (e.g. one per usage type). Granting them all
|
|
425
|
-
// should yield ONE token: if an identical non-renewal grant just minted
|
|
426
|
-
// (or is minting), don't mint a duplicate. Spending authorizations are
|
|
427
|
-
// excluded — their tokens carry amounts, so every grant is honored.
|
|
428
|
-
let skipDuplicateMint = !request.renewal &&
|
|
429
|
-
request.type !== 'spending' &&
|
|
430
|
-
(this.isPermissionCached(key) || this.isRecentlyGranted(key) || this.mintsInFlight.has(key));
|
|
431
|
-
if (skipDuplicateMint) {
|
|
432
|
-
const inFlight = this.mintsInFlight.get(key);
|
|
433
|
-
if (inFlight != null) {
|
|
434
|
-
await inFlight;
|
|
435
|
-
// The awaited mint may have failed; only skip if it landed.
|
|
436
|
-
skipDuplicateMint = this.isPermissionCached(key) || this.isRecentlyGranted(key);
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
if (!skipDuplicateMint) {
|
|
440
|
-
const mint = request.renewal
|
|
441
|
-
? this.renewPermissionOnChain(request.previousToken, request, expiry, params.amount)
|
|
442
|
-
: this.createPermissionOnChain(request, expiry, params.amount);
|
|
443
|
-
// Publish the in-flight mint so concurrent ensures for the same
|
|
444
|
-
// permission wait for it instead of re-prompting (stored promise
|
|
445
|
-
// never rejects; failures still propagate to this caller below).
|
|
446
|
-
this.mintsInFlight.set(key, mint.then(() => { }, () => { }));
|
|
447
|
-
try {
|
|
448
|
-
await mint;
|
|
449
|
-
}
|
|
450
|
-
finally {
|
|
451
|
-
this.mintsInFlight.delete(key);
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
this.cachePermission(key, expiry);
|
|
455
|
-
this.markRecentGrant(request);
|
|
456
|
-
}
|
|
611
|
+
// 3) Ephemeral permissions are one-time authorizations and never persist.
|
|
612
|
+
if (params.ephemeral)
|
|
613
|
+
return;
|
|
614
|
+
await this.grantPersistentPermission(matching.request, params.expiry || 0, params.amount);
|
|
457
615
|
}
|
|
458
616
|
/**
|
|
459
617
|
* Denies a previously requested permission.
|
|
@@ -552,27 +710,18 @@ class WalletPermissionsManager {
|
|
|
552
710
|
expiry
|
|
553
711
|
});
|
|
554
712
|
}
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
p.resolve(true);
|
|
563
|
-
}
|
|
713
|
+
// A user-visible grouped grant is atomic from the caller's perspective:
|
|
714
|
+
// never resolve the waiting wallet call if one of the requested tokens
|
|
715
|
+
// failed to persist. The best-effort helpers intentionally suppress
|
|
716
|
+
// singleton failures and are therefore only suitable for maintenance
|
|
717
|
+
// operations where a partial result is explicitly returned.
|
|
718
|
+
await this.persistPermissionGrant(toCreate, toRenew);
|
|
719
|
+
this.settleActiveGrant(params.requestID, matching, 'resolve', true);
|
|
564
720
|
}
|
|
565
721
|
catch (error) {
|
|
566
|
-
|
|
567
|
-
for (const p of matching.pending) {
|
|
568
|
-
p.reject(error);
|
|
569
|
-
}
|
|
722
|
+
this.settleActiveGrant(params.requestID, matching, 'reject', error);
|
|
570
723
|
throw error;
|
|
571
724
|
}
|
|
572
|
-
finally {
|
|
573
|
-
// Always clean up the request entry
|
|
574
|
-
this.activeRequests.delete(params.requestID);
|
|
575
|
-
}
|
|
576
725
|
}
|
|
577
726
|
/**
|
|
578
727
|
* Denies a previously requested grouped permission.
|
|
@@ -608,6 +757,17 @@ class WalletPermissionsManager {
|
|
|
608
757
|
}
|
|
609
758
|
this.activeRequests.delete(requestID);
|
|
610
759
|
}
|
|
760
|
+
settleActiveGrant(requestID, matching, method, value) {
|
|
761
|
+
for (const pending of matching.pending)
|
|
762
|
+
pending[method](value);
|
|
763
|
+
this.activeRequests.delete(requestID);
|
|
764
|
+
}
|
|
765
|
+
async persistPermissionGrant(toCreate, toRenew) {
|
|
766
|
+
const created = await this.createPermissionTokensBestEffort(toCreate, true);
|
|
767
|
+
const renewed = await this.renewPermissionTokensBestEffort(toRenew, true);
|
|
768
|
+
for (const request of [...created, ...renewed])
|
|
769
|
+
this.markRecentGrant(request);
|
|
770
|
+
}
|
|
611
771
|
async denyGroupedPermission(requestID) {
|
|
612
772
|
this.denyActiveRequest(requestID);
|
|
613
773
|
}
|
|
@@ -675,15 +835,14 @@ class WalletPermissionsManager {
|
|
|
675
835
|
toRenew.push({ oldToken: token, request, expiry });
|
|
676
836
|
}
|
|
677
837
|
}
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
this.markRecentGrant(req);
|
|
838
|
+
try {
|
|
839
|
+
await this.persistPermissionGrant(toCreate, toRenew);
|
|
840
|
+
this.settleActiveGrant(params.requestID, matching, 'resolve', true);
|
|
682
841
|
}
|
|
683
|
-
|
|
684
|
-
|
|
842
|
+
catch (error) {
|
|
843
|
+
this.settleActiveGrant(params.requestID, matching, 'reject', error);
|
|
844
|
+
throw error;
|
|
685
845
|
}
|
|
686
|
-
this.activeRequests.delete(params.requestID);
|
|
687
846
|
}
|
|
688
847
|
async denyCounterpartyPermission(requestID) {
|
|
689
848
|
this.denyActiveRequest(requestID);
|
|
@@ -879,19 +1038,11 @@ class WalletPermissionsManager {
|
|
|
879
1038
|
// We skip spending permission entirely
|
|
880
1039
|
return true;
|
|
881
1040
|
}
|
|
882
|
-
const cacheKey = this.buildRequestKey({ type: 'spending', originator, spending: { satoshis } });
|
|
883
|
-
// Spending keys are amount-scoped. The recent-grant window this adds sits
|
|
884
|
-
// inside the pre-existing permissionCache window grantPermission already
|
|
885
|
-
// wrote for spending, so accounting exposure is unchanged.
|
|
886
|
-
if (await this.hasRecentOrPendingGrant(cacheKey)) {
|
|
887
|
-
return true;
|
|
888
|
-
}
|
|
889
1041
|
const token = await this.findSpendingToken(originator, lookupValues);
|
|
890
1042
|
if (token?.authorizedAmount) {
|
|
891
1043
|
// Check how much has been spent so far
|
|
892
1044
|
const spentSoFar = await this.querySpentSince(token);
|
|
893
1045
|
if (spentSoFar + satoshis <= token.authorizedAmount) {
|
|
894
|
-
this.cachePermission(cacheKey, token.expiry);
|
|
895
1046
|
return true;
|
|
896
1047
|
}
|
|
897
1048
|
else {
|
|
@@ -1046,11 +1197,22 @@ class WalletPermissionsManager {
|
|
|
1046
1197
|
return await inProgress;
|
|
1047
1198
|
}
|
|
1048
1199
|
const fetchPromise = (async () => {
|
|
1200
|
+
const controller = new AbortController();
|
|
1201
|
+
const timeout = setTimeout(() => controller.abort(), WalletPermissionsManager.MANIFEST_TIMEOUT_MS);
|
|
1049
1202
|
try {
|
|
1050
|
-
const
|
|
1051
|
-
const
|
|
1203
|
+
const localDevelopment = originator === 'localhost' || originator.startsWith('localhost:');
|
|
1204
|
+
const proto = localDevelopment ? 'http' : 'https';
|
|
1205
|
+
const expectedOrigin = `${proto}://${originator}`;
|
|
1206
|
+
// Localhost HTTP is an explicit development compatibility path. Every
|
|
1207
|
+
// public origin uses resolved-address validation and a DNS-pinned
|
|
1208
|
+
// connection so a manifest hostname cannot rebind to a private host.
|
|
1209
|
+
const manifestFetch = localDevelopment ? globalThis.fetch : (0, sdk_1.createPublicHTTPSFetch)(expectedOrigin);
|
|
1210
|
+
const response = await manifestFetch(`${expectedOrigin}/manifest.json`, {
|
|
1211
|
+
redirect: 'error',
|
|
1212
|
+
signal: controller.signal
|
|
1213
|
+
});
|
|
1052
1214
|
if (response.ok) {
|
|
1053
|
-
const manifest = await
|
|
1215
|
+
const manifest = await this.readBoundedManifest(response);
|
|
1054
1216
|
const namespace = manifest?.metanet || manifest?.babbage;
|
|
1055
1217
|
const groupPermissions = namespace?.groupPermissions || null;
|
|
1056
1218
|
const counterpartyPermissionsDeclared = this.validateCounterpartyPermissions(namespace?.counterpartyPermissions);
|
|
@@ -1065,6 +1227,9 @@ class WalletPermissionsManager {
|
|
|
1065
1227
|
catch {
|
|
1066
1228
|
// Manifest fetch or parse failed — fall through to return null/null defaults below
|
|
1067
1229
|
}
|
|
1230
|
+
finally {
|
|
1231
|
+
clearTimeout(timeout);
|
|
1232
|
+
}
|
|
1068
1233
|
const result = { groupPermissions: null, counterpartyPermissions: null };
|
|
1069
1234
|
this.manifestCache.set(originator, { ...result, fetchedAt: Date.now() });
|
|
1070
1235
|
return result;
|
|
@@ -1077,6 +1242,49 @@ class WalletPermissionsManager {
|
|
|
1077
1242
|
this.manifestFetchInProgress.delete(originator);
|
|
1078
1243
|
}
|
|
1079
1244
|
}
|
|
1245
|
+
async readBoundedManifest(response) {
|
|
1246
|
+
const declaredLength = response.headers?.get('content-length');
|
|
1247
|
+
if (declaredLength != null) {
|
|
1248
|
+
const parsedLength = Number(declaredLength);
|
|
1249
|
+
if (!Number.isSafeInteger(parsedLength) ||
|
|
1250
|
+
parsedLength < 0 ||
|
|
1251
|
+
parsedLength > WalletPermissionsManager.MANIFEST_MAX_BYTES) {
|
|
1252
|
+
throw new Error('Manifest response exceeds the configured size limit.');
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
if (response.body == null) {
|
|
1256
|
+
// Test and embedded fetch implementations may expose only json(). Bound
|
|
1257
|
+
// their parsed representation before accepting it.
|
|
1258
|
+
const parsed = await response.json();
|
|
1259
|
+
if (new TextEncoder().encode(JSON.stringify(parsed)).length > WalletPermissionsManager.MANIFEST_MAX_BYTES) {
|
|
1260
|
+
throw new Error('Manifest response exceeds the configured size limit.');
|
|
1261
|
+
}
|
|
1262
|
+
return parsed;
|
|
1263
|
+
}
|
|
1264
|
+
const reader = response.body.getReader();
|
|
1265
|
+
const chunks = [];
|
|
1266
|
+
let total = 0;
|
|
1267
|
+
for (;;) {
|
|
1268
|
+
const { done, value } = await reader.read();
|
|
1269
|
+
if (done)
|
|
1270
|
+
break;
|
|
1271
|
+
if (value == null)
|
|
1272
|
+
continue;
|
|
1273
|
+
total += value.byteLength;
|
|
1274
|
+
if (total > WalletPermissionsManager.MANIFEST_MAX_BYTES) {
|
|
1275
|
+
await reader.cancel();
|
|
1276
|
+
throw new Error('Manifest response exceeds the configured size limit.');
|
|
1277
|
+
}
|
|
1278
|
+
chunks.push(value);
|
|
1279
|
+
}
|
|
1280
|
+
const bytes = new Uint8Array(total);
|
|
1281
|
+
let offset = 0;
|
|
1282
|
+
for (const chunk of chunks) {
|
|
1283
|
+
bytes.set(chunk, offset);
|
|
1284
|
+
offset += chunk.byteLength;
|
|
1285
|
+
}
|
|
1286
|
+
return JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(bytes));
|
|
1287
|
+
}
|
|
1080
1288
|
async fetchManifestGroupPermissions(originator) {
|
|
1081
1289
|
const { groupPermissions } = await this.fetchManifestPermissions(originator);
|
|
1082
1290
|
return groupPermissions;
|
|
@@ -1669,7 +1877,7 @@ class WalletPermissionsManager {
|
|
|
1669
1877
|
];
|
|
1670
1878
|
/** We always use `keyID="1"` and `counterparty="self"` for these encryption ops. */
|
|
1671
1879
|
async encryptPermissionTokenField(plaintext) {
|
|
1672
|
-
const data = typeof plaintext === 'string' ?
|
|
1880
|
+
const data = typeof plaintext === 'string' ? (0, utils_1.toArray)(plaintext, 'utf8') : plaintext;
|
|
1673
1881
|
const { ciphertext } = await this.underlying.encrypt({
|
|
1674
1882
|
plaintext: data,
|
|
1675
1883
|
protocolID: WalletPermissionsManager.PERM_TOKEN_ENCRYPTION_PROTOCOL,
|
|
@@ -1691,7 +1899,7 @@ class WalletPermissionsManager {
|
|
|
1691
1899
|
let parsed = this.parsedBeefCache.get(beef);
|
|
1692
1900
|
if (parsed === undefined) {
|
|
1693
1901
|
try {
|
|
1694
|
-
parsed = sdk_1.Beef.
|
|
1902
|
+
parsed = sdk_1.Beef.fromBinaryStrict(beef);
|
|
1695
1903
|
}
|
|
1696
1904
|
catch {
|
|
1697
1905
|
parsed = null;
|
|
@@ -1709,6 +1917,60 @@ class WalletPermissionsManager {
|
|
|
1709
1917
|
// fast path can't serve.
|
|
1710
1918
|
return sdk_1.Transaction.fromBEEF(beef ?? [], txid);
|
|
1711
1919
|
}
|
|
1920
|
+
async permissionTokenLockingKey() {
|
|
1921
|
+
const pending = this.permissionTokenLockingKeyPromise ??
|
|
1922
|
+
this.underlying
|
|
1923
|
+
.getPublicKey({
|
|
1924
|
+
protocolID: WalletPermissionsManager.PERM_TOKEN_ENCRYPTION_PROTOCOL,
|
|
1925
|
+
keyID: '1',
|
|
1926
|
+
counterparty: 'self',
|
|
1927
|
+
forSelf: true
|
|
1928
|
+
}, this.adminOriginator)
|
|
1929
|
+
.then(({ publicKey }) => {
|
|
1930
|
+
if (typeof publicKey !== 'string' || !/^(?:02|03)[0-9a-f]{64}$/i.test(publicKey)) {
|
|
1931
|
+
throw new Error('Wallet returned an invalid permission-token locking key.');
|
|
1932
|
+
}
|
|
1933
|
+
return publicKey.toLowerCase();
|
|
1934
|
+
});
|
|
1935
|
+
this.permissionTokenLockingKeyPromise = pending;
|
|
1936
|
+
try {
|
|
1937
|
+
return await pending;
|
|
1938
|
+
}
|
|
1939
|
+
catch (error) {
|
|
1940
|
+
if (this.permissionTokenLockingKeyPromise === pending)
|
|
1941
|
+
this.permissionTokenLockingKeyPromise = undefined;
|
|
1942
|
+
throw error;
|
|
1943
|
+
}
|
|
1944
|
+
}
|
|
1945
|
+
async authenticatedPermissionTokenSource(result, output, dataFieldCount) {
|
|
1946
|
+
try {
|
|
1947
|
+
const [txid, outputIndex] = this.parseOutpoint(output.outpoint);
|
|
1948
|
+
const tx = this.transactionFromResultBeef(result, txid);
|
|
1949
|
+
if (tx.id('hex').toLowerCase() !== txid)
|
|
1950
|
+
throw new Error('Permission token transaction ID mismatch.');
|
|
1951
|
+
const txOutput = tx.outputs[outputIndex];
|
|
1952
|
+
if (txOutput == null || txOutput.satoshis !== 1 || output.satoshis !== 1) {
|
|
1953
|
+
throw new Error('Permission token source output is invalid.');
|
|
1954
|
+
}
|
|
1955
|
+
const decoded = (0, sdk_1.decodeCanonicalPushDrop)(txOutput.lockingScript, {
|
|
1956
|
+
fieldCount: dataFieldCount + 1,
|
|
1957
|
+
maximumFieldBytes: MAX_PERMISSION_TOKEN_FIELD_BYTES,
|
|
1958
|
+
maximumPayloadBytes: MAX_PERMISSION_TOKEN_PAYLOAD_BYTES
|
|
1959
|
+
});
|
|
1960
|
+
if (decoded.lockingPublicKey.toString().toLowerCase() !== (await this.permissionTokenLockingKey())) {
|
|
1961
|
+
throw new Error('Permission token is not controlled by this wallet.');
|
|
1962
|
+
}
|
|
1963
|
+
const fields = decoded.fields.slice(0, -1);
|
|
1964
|
+
const signature = sdk_1.Signature.fromDER(decoded.fields.at(-1));
|
|
1965
|
+
if (!signature.verify(fields.flat(), decoded.lockingPublicKey)) {
|
|
1966
|
+
throw new Error('Permission token field signature is invalid.');
|
|
1967
|
+
}
|
|
1968
|
+
return { tx, txid, outputIndex, fields };
|
|
1969
|
+
}
|
|
1970
|
+
catch {
|
|
1971
|
+
return undefined;
|
|
1972
|
+
}
|
|
1973
|
+
}
|
|
1712
1974
|
async decryptPermissionTokenField(ciphertext) {
|
|
1713
1975
|
// Field decrypts run in tight loops over every token in a basket; yield a
|
|
1714
1976
|
// macrotask periodically so large scans don't starve the caller's event
|
|
@@ -1729,6 +1991,9 @@ class WalletPermissionsManager {
|
|
|
1729
1991
|
return ciphertext;
|
|
1730
1992
|
}
|
|
1731
1993
|
}
|
|
1994
|
+
async decryptPermissionTokenText(ciphertext) {
|
|
1995
|
+
return (0, utils_1.toUTF8Strict)(await this.decryptPermissionTokenField(ciphertext));
|
|
1996
|
+
}
|
|
1732
1997
|
/**
|
|
1733
1998
|
* Encrypts wallet metadata if configured to do so, otherwise returns the original plaintext for storage.
|
|
1734
1999
|
* @param plaintext The metadata to encrypt if configured to do so
|
|
@@ -1739,11 +2004,11 @@ class WalletPermissionsManager {
|
|
|
1739
2004
|
return plaintext;
|
|
1740
2005
|
}
|
|
1741
2006
|
const { ciphertext } = await this.underlying.encrypt({
|
|
1742
|
-
plaintext:
|
|
2007
|
+
plaintext: (0, utils_1.toArray)(plaintext, 'utf8'),
|
|
1743
2008
|
protocolID: WalletPermissionsManager.METADATA_ENCRYPTION_PROTOCOL,
|
|
1744
2009
|
keyID: '1'
|
|
1745
2010
|
}, this.adminOriginator);
|
|
1746
|
-
return
|
|
2011
|
+
return (0, utils_1.toBase64)(ciphertext);
|
|
1747
2012
|
}
|
|
1748
2013
|
/**
|
|
1749
2014
|
* Attempts to decrypt metadata. if decryption fails, assumes the value is already plaintext and returns it.
|
|
@@ -1753,11 +2018,11 @@ class WalletPermissionsManager {
|
|
|
1753
2018
|
async maybeDecryptMetadata(ciphertext) {
|
|
1754
2019
|
try {
|
|
1755
2020
|
const { plaintext } = await this.underlying.decrypt({
|
|
1756
|
-
ciphertext:
|
|
2021
|
+
ciphertext: (0, utils_1.toArray)(ciphertext, 'base64'),
|
|
1757
2022
|
protocolID: WalletPermissionsManager.METADATA_ENCRYPTION_PROTOCOL,
|
|
1758
2023
|
keyID: '1'
|
|
1759
2024
|
}, this.adminOriginator);
|
|
1760
|
-
return
|
|
2025
|
+
return (0, utils_1.toUTF8)(plaintext);
|
|
1761
2026
|
}
|
|
1762
2027
|
catch {
|
|
1763
2028
|
// Decryption failed (e.g. wrong key, unencrypted legacy value) — return original string unchanged
|
|
@@ -1771,32 +2036,33 @@ class WalletPermissionsManager {
|
|
|
1771
2036
|
}
|
|
1772
2037
|
/** Decrypts the standard 6 fields from a protocol (DPACP) PushDrop script. */
|
|
1773
2038
|
async decryptProtocolTokenFields(fields) {
|
|
1774
|
-
const domainDecoded =
|
|
1775
|
-
const expiryDecoded =
|
|
1776
|
-
const privDecoded =
|
|
1777
|
-
const
|
|
1778
|
-
const
|
|
1779
|
-
const
|
|
2039
|
+
const domainDecoded = await this.decryptPermissionTokenText(fields[0]);
|
|
2040
|
+
const expiryDecoded = parseCanonicalPermissionInteger(await this.decryptPermissionTokenText(fields[1]), 'Permission expiry');
|
|
2041
|
+
const privDecoded = parsePermissionBoolean(await this.decryptPermissionTokenText(fields[2]), 'Permission privileged flag');
|
|
2042
|
+
const securityLevel = parseCanonicalPermissionInteger(await this.decryptPermissionTokenText(fields[3]), 'Permission security level', 2);
|
|
2043
|
+
const secLevelDecoded = securityLevel;
|
|
2044
|
+
const protoNameDecoded = await this.decryptPermissionTokenText(fields[4]);
|
|
2045
|
+
const cptyDecoded = await this.decryptPermissionTokenText(fields[5]);
|
|
1780
2046
|
return { domainDecoded, expiryDecoded, privDecoded, secLevelDecoded, protoNameDecoded, cptyDecoded };
|
|
1781
2047
|
}
|
|
1782
2048
|
protocolTokenTags(originator, privileged, securityLevel, protocolName, counterparty) {
|
|
1783
2049
|
const tags = [
|
|
1784
|
-
`originator ${originator}`,
|
|
1785
2050
|
`privileged ${!!privileged}`,
|
|
1786
2051
|
`protocolName ${protocolName}`,
|
|
1787
2052
|
`protocolSecurityLevel ${securityLevel}`
|
|
1788
2053
|
];
|
|
2054
|
+
if (originator !== undefined)
|
|
2055
|
+
tags.unshift(`originator ${originator}`);
|
|
1789
2056
|
if (securityLevel === 2)
|
|
1790
2057
|
tags.push(`counterparty ${counterparty}`);
|
|
1791
2058
|
return tags;
|
|
1792
2059
|
}
|
|
1793
2060
|
async parseProtocolTokenOutput(result, output, expected) {
|
|
1794
|
-
const
|
|
1795
|
-
|
|
1796
|
-
const decoded = sdk_1.PushDrop.decode(tx.outputs[outputIndex].lockingScript);
|
|
1797
|
-
if (decoded?.fields == null || decoded.fields.length < 6)
|
|
2061
|
+
const source = await this.authenticatedPermissionTokenSource(result, output, 6);
|
|
2062
|
+
if (source == null)
|
|
1798
2063
|
return undefined;
|
|
1799
|
-
const
|
|
2064
|
+
const { tx, txid, outputIndex } = source;
|
|
2065
|
+
const fields = await this.decryptProtocolTokenFields(source.fields);
|
|
1800
2066
|
if (this.normalizeOriginator(fields.domainDecoded) !== expected.originator)
|
|
1801
2067
|
return undefined;
|
|
1802
2068
|
const matches = fields.privDecoded === !!expected.privileged &&
|
|
@@ -1821,16 +2087,15 @@ class WalletPermissionsManager {
|
|
|
1821
2087
|
};
|
|
1822
2088
|
}
|
|
1823
2089
|
async parseBasketTokenOutput(result, output, originator, basket) {
|
|
1824
|
-
const
|
|
1825
|
-
|
|
1826
|
-
const decoded = sdk_1.PushDrop.decode(tx.outputs[outputIndex].lockingScript);
|
|
1827
|
-
if (decoded?.fields == null || decoded.fields.length < 3)
|
|
2090
|
+
const source = await this.authenticatedPermissionTokenSource(result, output, 3);
|
|
2091
|
+
if (source == null)
|
|
1828
2092
|
return undefined;
|
|
1829
|
-
const
|
|
2093
|
+
const { tx, txid, outputIndex, fields } = source;
|
|
2094
|
+
const domainDecoded = await this.decryptPermissionTokenText(fields[0]);
|
|
1830
2095
|
if (this.normalizeOriginator(domainDecoded) !== originator)
|
|
1831
2096
|
return undefined;
|
|
1832
|
-
const expiryDecoded =
|
|
1833
|
-
const basketDecoded =
|
|
2097
|
+
const expiryDecoded = parseCanonicalPermissionInteger(await this.decryptPermissionTokenText(fields[1]), 'Permission expiry');
|
|
2098
|
+
const basketDecoded = await this.decryptPermissionTokenText(fields[2]);
|
|
1834
2099
|
if (basketDecoded !== basket)
|
|
1835
2100
|
return undefined;
|
|
1836
2101
|
return {
|
|
@@ -1846,20 +2111,19 @@ class WalletPermissionsManager {
|
|
|
1846
2111
|
};
|
|
1847
2112
|
}
|
|
1848
2113
|
async parseCertificateTokenOutput(result, output, expected) {
|
|
1849
|
-
const
|
|
1850
|
-
|
|
1851
|
-
const decoded = sdk_1.PushDrop.decode(tx.outputs[outputIndex].lockingScript);
|
|
1852
|
-
if (decoded?.fields == null || decoded.fields.length < 6)
|
|
2114
|
+
const source = await this.authenticatedPermissionTokenSource(result, output, 6);
|
|
2115
|
+
if (source == null)
|
|
1853
2116
|
return undefined;
|
|
1854
|
-
const
|
|
1855
|
-
const
|
|
2117
|
+
const { tx, txid, outputIndex } = source;
|
|
2118
|
+
const [domainRaw, expiryRaw, privRaw, typeRaw, fieldsRaw, verifierRaw] = source.fields;
|
|
2119
|
+
const domainDecoded = await this.decryptPermissionTokenText(domainRaw);
|
|
1856
2120
|
if (this.normalizeOriginator(domainDecoded) !== expected.originator)
|
|
1857
2121
|
return undefined;
|
|
1858
|
-
const expiryDecoded =
|
|
1859
|
-
const privileged =
|
|
1860
|
-
const certType =
|
|
1861
|
-
const verifier =
|
|
1862
|
-
const allFields =
|
|
2122
|
+
const expiryDecoded = parseCanonicalPermissionInteger(await this.decryptPermissionTokenText(expiryRaw), 'Permission expiry');
|
|
2123
|
+
const privileged = parsePermissionBoolean(await this.decryptPermissionTokenText(privRaw), 'Permission privileged flag');
|
|
2124
|
+
const certType = await this.decryptPermissionTokenText(typeRaw);
|
|
2125
|
+
const verifier = await this.decryptPermissionTokenText(verifierRaw);
|
|
2126
|
+
const allFields = parsePermissionCertificateFields(await this.decryptPermissionTokenText(fieldsRaw));
|
|
1863
2127
|
const metadataMatches = privileged === !!expected.privileged && certType === expected.certType && verifier === expected.verifier;
|
|
1864
2128
|
if (!metadataMatches)
|
|
1865
2129
|
return undefined;
|
|
@@ -1883,61 +2147,14 @@ class WalletPermissionsManager {
|
|
|
1883
2147
|
}
|
|
1884
2148
|
/** Parses outpoint string "txid.vout" into [txid, outputIndex]. */
|
|
1885
2149
|
parseOutpoint(outpoint) {
|
|
1886
|
-
const
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
reverseHexTxid(txid) {
|
|
1895
|
-
const hex = this.normalizeTxid(txid);
|
|
1896
|
-
if (!/^[0-9a-f]{64}$/.test(hex))
|
|
1897
|
-
return hex;
|
|
1898
|
-
const bytes = hex.match(/../g);
|
|
1899
|
-
return bytes != null ? bytes.reverse().join('') : hex;
|
|
1900
|
-
}
|
|
1901
|
-
/**
|
|
1902
|
-
* Returns true when an outpoint string (e.g. "txid.vout" or "txid:vout") refers to `token`.
|
|
1903
|
-
*/
|
|
1904
|
-
tokenMatchesOutpointString(outpoint, token) {
|
|
1905
|
-
const dot = outpoint.lastIndexOf('.');
|
|
1906
|
-
const colon = outpoint.lastIndexOf(':');
|
|
1907
|
-
const sep = Math.max(dot, colon);
|
|
1908
|
-
if (sep === -1)
|
|
1909
|
-
return false;
|
|
1910
|
-
const txidPart = outpoint.slice(0, sep);
|
|
1911
|
-
const vout = Number(outpoint.slice(sep + 1));
|
|
1912
|
-
if (!Number.isFinite(vout))
|
|
1913
|
-
return false;
|
|
1914
|
-
return this.normalizeTxid(txidPart) === this.normalizeTxid(token.txid) && vout === token.outputIndex;
|
|
1915
|
-
}
|
|
1916
|
-
/**
|
|
1917
|
-
* Finds the index of the tx input that spends the given permission token.
|
|
1918
|
-
* Handles multiple potential field names for TXID and vout.
|
|
1919
|
-
*/
|
|
1920
|
-
findInputIndexForToken(tx, token) {
|
|
1921
|
-
return tx.inputs.findIndex((input) => {
|
|
1922
|
-
const txidCandidate = input?.sourceTXID ??
|
|
1923
|
-
input?.sourceTxid ??
|
|
1924
|
-
input?.sourceTxId ??
|
|
1925
|
-
input?.prevTxId ??
|
|
1926
|
-
input?.prevTxid ??
|
|
1927
|
-
input?.prevTXID ??
|
|
1928
|
-
input?.txid ??
|
|
1929
|
-
input?.txID;
|
|
1930
|
-
const voutCandidate = input?.sourceOutputIndex ?? input?.sourceOutput ?? input?.outputIndex ?? input?.vout ?? input?.prevOutIndex;
|
|
1931
|
-
if (typeof txidCandidate === 'string' && typeof voutCandidate === 'number') {
|
|
1932
|
-
const cand = this.normalizeTxid(txidCandidate);
|
|
1933
|
-
if (cand === this.normalizeTxid(token.txid) && voutCandidate === token.outputIndex)
|
|
1934
|
-
return true;
|
|
1935
|
-
if (cand === this.reverseHexTxid(token.txid) && voutCandidate === token.outputIndex)
|
|
1936
|
-
return true;
|
|
1937
|
-
}
|
|
1938
|
-
const outpointCandidate = input?.outpoint ?? input?.sourceOutpoint ?? input?.prevOutpoint;
|
|
1939
|
-
return typeof outpointCandidate === 'string' && this.tokenMatchesOutpointString(outpointCandidate, token);
|
|
1940
|
-
});
|
|
2150
|
+
const match = /^([0-9a-f]{64})\.(0|[1-9]\d*)$/i.exec(outpoint);
|
|
2151
|
+
if (match == null)
|
|
2152
|
+
throw new Error('Permission token outpoint is invalid.');
|
|
2153
|
+
const outputIndex = Number(match[2]);
|
|
2154
|
+
if (!Number.isSafeInteger(outputIndex) || outputIndex > 0xffffffff) {
|
|
2155
|
+
throw new Error('Permission token outpoint is invalid.');
|
|
2156
|
+
}
|
|
2157
|
+
return [match[1].toLowerCase(), outputIndex];
|
|
1941
2158
|
}
|
|
1942
2159
|
/** Looks for a DPACP permission token matching origin/domain, privileged, protocol, cpty. */
|
|
1943
2160
|
async findProtocolToken(originator, privileged, protocolID, counterparty, includeExpired, originatorLookupValues) {
|
|
@@ -1948,7 +2165,8 @@ class WalletPermissionsManager {
|
|
|
1948
2165
|
basket: BASKET_MAP.protocol,
|
|
1949
2166
|
tags: this.protocolTokenTags(originTag, privileged, secLevel, protoName, counterparty),
|
|
1950
2167
|
tagQueryMode: 'all',
|
|
1951
|
-
include: 'entire transactions'
|
|
2168
|
+
include: 'entire transactions',
|
|
2169
|
+
limit: 10000
|
|
1952
2170
|
}, this.adminOriginator);
|
|
1953
2171
|
for (const out of result.outputs) {
|
|
1954
2172
|
const token = await this.parseProtocolTokenOutput(result, out, {
|
|
@@ -1978,7 +2196,8 @@ class WalletPermissionsManager {
|
|
|
1978
2196
|
basket: BASKET_MAP.protocol,
|
|
1979
2197
|
tags: this.protocolTokenTags(originTag, privileged, secLevel, protoName, counterparty),
|
|
1980
2198
|
tagQueryMode: 'all',
|
|
1981
|
-
include: 'entire transactions'
|
|
2199
|
+
include: 'entire transactions',
|
|
2200
|
+
limit: 10000
|
|
1982
2201
|
}, this.adminOriginator);
|
|
1983
2202
|
for (const out of result.outputs) {
|
|
1984
2203
|
if (seen.has(out.outpoint))
|
|
@@ -2004,9 +2223,10 @@ class WalletPermissionsManager {
|
|
|
2004
2223
|
for (const originTag of originsToTry) {
|
|
2005
2224
|
const result = await this.underlying.listOutputs({
|
|
2006
2225
|
basket: BASKET_MAP.basket,
|
|
2007
|
-
tags: [`originator ${originTag}`, `basket ${basket}`],
|
|
2226
|
+
tags: [originTag === undefined ? undefined : `originator ${originTag}`, `basket ${basket}`].filter((tag) => tag !== undefined),
|
|
2008
2227
|
tagQueryMode: 'all',
|
|
2009
|
-
include: 'entire transactions'
|
|
2228
|
+
include: 'entire transactions',
|
|
2229
|
+
limit: 10000
|
|
2010
2230
|
}, this.adminOriginator);
|
|
2011
2231
|
for (const out of result.outputs) {
|
|
2012
2232
|
const token = await this.parseBasketTokenOutput(result, out, originator, basket);
|
|
@@ -2025,9 +2245,15 @@ class WalletPermissionsManager {
|
|
|
2025
2245
|
for (const originTag of originsToTry) {
|
|
2026
2246
|
const result = await this.underlying.listOutputs({
|
|
2027
2247
|
basket: BASKET_MAP.certificate,
|
|
2028
|
-
tags: [
|
|
2248
|
+
tags: [
|
|
2249
|
+
originTag === undefined ? undefined : `originator ${originTag}`,
|
|
2250
|
+
`privileged ${!!privileged}`,
|
|
2251
|
+
`type ${certType}`,
|
|
2252
|
+
`verifier ${verifier}`
|
|
2253
|
+
].filter((tag) => tag !== undefined),
|
|
2029
2254
|
tagQueryMode: 'all',
|
|
2030
|
-
include: 'entire transactions'
|
|
2255
|
+
include: 'entire transactions',
|
|
2256
|
+
limit: 10000
|
|
2031
2257
|
}, this.adminOriginator);
|
|
2032
2258
|
for (const out of result.outputs) {
|
|
2033
2259
|
const token = await this.parseCertificateTokenOutput(result, out, {
|
|
@@ -2052,29 +2278,28 @@ class WalletPermissionsManager {
|
|
|
2052
2278
|
for (const originTag of originsToTry) {
|
|
2053
2279
|
const result = await this.underlying.listOutputs({
|
|
2054
2280
|
basket: BASKET_MAP.spending,
|
|
2055
|
-
tags: [`originator ${originTag}`],
|
|
2281
|
+
tags: originTag === undefined ? [] : [`originator ${originTag}`],
|
|
2056
2282
|
tagQueryMode: 'all',
|
|
2057
|
-
include: 'entire transactions'
|
|
2283
|
+
include: 'entire transactions',
|
|
2284
|
+
limit: 10000
|
|
2058
2285
|
}, this.adminOriginator);
|
|
2059
2286
|
for (const out of result.outputs) {
|
|
2060
|
-
const
|
|
2061
|
-
|
|
2062
|
-
const dec = sdk_1.PushDrop.decode(tx.outputs[Number(outputIndexStr)].lockingScript);
|
|
2063
|
-
if (!dec?.fields || dec.fields.length < 2)
|
|
2287
|
+
const source = await this.authenticatedPermissionTokenSource(result, out, 2);
|
|
2288
|
+
if (source == null)
|
|
2064
2289
|
continue;
|
|
2065
|
-
const
|
|
2066
|
-
const
|
|
2067
|
-
const
|
|
2290
|
+
const { tx, txid, outputIndex, fields } = source;
|
|
2291
|
+
const domainRaw = fields[0];
|
|
2292
|
+
const amtRaw = fields[1];
|
|
2293
|
+
const domainDecoded = await this.decryptPermissionTokenText(domainRaw);
|
|
2068
2294
|
const normalizedDomain = this.normalizeOriginator(domainDecoded);
|
|
2069
2295
|
if (normalizedDomain !== originator)
|
|
2070
2296
|
continue;
|
|
2071
|
-
const
|
|
2072
|
-
const authorizedAmount = Number.parseInt(amtDecodedStr, 10);
|
|
2297
|
+
const authorizedAmount = parseCanonicalPermissionInteger(await this.decryptPermissionTokenText(amtRaw), 'Permission spending amount', MAX_MONEY_SATOSHIS);
|
|
2073
2298
|
return {
|
|
2074
2299
|
tx: tx.toBEEF(),
|
|
2075
|
-
txid
|
|
2076
|
-
outputIndex
|
|
2077
|
-
outputScript: tx.outputs[
|
|
2300
|
+
txid,
|
|
2301
|
+
outputIndex,
|
|
2302
|
+
outputScript: tx.outputs[outputIndex].lockingScript.toHex(),
|
|
2078
2303
|
satoshis: out.satoshis,
|
|
2079
2304
|
originator,
|
|
2080
2305
|
rawOriginator: domainDecoded,
|
|
@@ -2103,11 +2328,23 @@ class WalletPermissionsManager {
|
|
|
2103
2328
|
const labelOrigins = this.buildOriginatorLookupValues(token.rawOriginator, token.originator);
|
|
2104
2329
|
let total = 0;
|
|
2105
2330
|
for (const labelOrigin of labelOrigins) {
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2331
|
+
let offset = 0;
|
|
2332
|
+
let totalActions = 0;
|
|
2333
|
+
do {
|
|
2334
|
+
const result = await this.underlying.listActions({
|
|
2335
|
+
labels: [`admin originator ${labelOrigin}`, `admin month ${this.getCurrentMonthYearUTC()}`],
|
|
2336
|
+
labelQueryMode: 'all',
|
|
2337
|
+
limit: 10000,
|
|
2338
|
+
offset
|
|
2339
|
+
}, this.adminOriginator);
|
|
2340
|
+
total += result.actions.reduce((a, e) => a - e.satoshis, 0);
|
|
2341
|
+
offset += result.actions.length;
|
|
2342
|
+
totalActions = result.totalActions;
|
|
2343
|
+
// A provider that reports more results but returns an empty page must
|
|
2344
|
+
// not trap the wallet in an infinite accounting loop.
|
|
2345
|
+
if (result.actions.length === 0)
|
|
2346
|
+
break;
|
|
2347
|
+
} while (offset < totalActions);
|
|
2111
2348
|
}
|
|
2112
2349
|
return total;
|
|
2113
2350
|
}
|
|
@@ -2138,7 +2375,7 @@ class WalletPermissionsManager {
|
|
|
2138
2375
|
const tags = this.buildTagsForRequest(r);
|
|
2139
2376
|
// Build a transaction with exactly one output, no explicit inputs since the wallet
|
|
2140
2377
|
// can internally fund it from its balance.
|
|
2141
|
-
await this.
|
|
2378
|
+
await this.completePermissionTokenAction({
|
|
2142
2379
|
description: `Grant ${r.type} permission`,
|
|
2143
2380
|
outputs: [
|
|
2144
2381
|
{
|
|
@@ -2150,9 +2387,12 @@ class WalletPermissionsManager {
|
|
|
2150
2387
|
}
|
|
2151
2388
|
],
|
|
2152
2389
|
options: {
|
|
2390
|
+
// Permission persistence must not inherit network-broadcast latency.
|
|
2391
|
+
// The managed-change planner keeps the queued output available as a
|
|
2392
|
+
// last-resort funding source for the resumed request.
|
|
2153
2393
|
acceptDelayedBroadcast: true
|
|
2154
2394
|
}
|
|
2155
|
-
}
|
|
2395
|
+
});
|
|
2156
2396
|
}
|
|
2157
2397
|
async mapWithConcurrency(items, concurrency, fn) {
|
|
2158
2398
|
if (items.length === 0)
|
|
@@ -2170,13 +2410,13 @@ class WalletPermissionsManager {
|
|
|
2170
2410
|
await Promise.all(Array.from({ length: Math.min(concurrency, items.length) }, async () => await worker()));
|
|
2171
2411
|
return results;
|
|
2172
2412
|
}
|
|
2173
|
-
async runBestEffortBatches(items, chunkSize, runChunk) {
|
|
2413
|
+
async runBestEffortBatches(items, chunkSize, runChunk, strict = false) {
|
|
2174
2414
|
if (items.length === 0)
|
|
2175
2415
|
return [];
|
|
2176
2416
|
const out = [];
|
|
2177
2417
|
for (let i = 0; i < items.length; i += chunkSize) {
|
|
2178
2418
|
const chunk = items.slice(i, i + chunkSize);
|
|
2179
|
-
out.push(...(await this.runBestEffortChunk(chunk, runChunk)));
|
|
2419
|
+
out.push(...(strict ? await runChunk(chunk) : await this.runBestEffortChunk(chunk, runChunk)));
|
|
2180
2420
|
}
|
|
2181
2421
|
return out;
|
|
2182
2422
|
}
|
|
@@ -2184,9 +2424,8 @@ class WalletPermissionsManager {
|
|
|
2184
2424
|
try {
|
|
2185
2425
|
return await runChunk(chunk);
|
|
2186
2426
|
}
|
|
2187
|
-
catch
|
|
2427
|
+
catch {
|
|
2188
2428
|
if (chunk.length <= 1) {
|
|
2189
|
-
console.error('Permission batch failed:', e);
|
|
2190
2429
|
return [];
|
|
2191
2430
|
}
|
|
2192
2431
|
const mid = Math.ceil(chunk.length / 2);
|
|
@@ -2216,27 +2455,27 @@ class WalletPermissionsManager {
|
|
|
2216
2455
|
}
|
|
2217
2456
|
};
|
|
2218
2457
|
}
|
|
2219
|
-
async createPermissionTokensBestEffort(items) {
|
|
2458
|
+
async createPermissionTokensBestEffort(items, strict = false) {
|
|
2220
2459
|
const CHUNK = 25;
|
|
2221
2460
|
return await this.runBestEffortBatches(items, CHUNK, async (chunk) => {
|
|
2222
2461
|
const built = await this.mapWithConcurrency(chunk, 8, async (c) => await this.buildPermissionOutput(c.request, c.expiry, c.amount));
|
|
2223
|
-
await this.
|
|
2462
|
+
await this.completePermissionTokenAction({
|
|
2224
2463
|
description: `Grant ${built.length} permissions`,
|
|
2225
2464
|
outputs: built.map(b => b.output),
|
|
2226
2465
|
options: { acceptDelayedBroadcast: true }
|
|
2227
|
-
}
|
|
2466
|
+
});
|
|
2228
2467
|
return built.map(b => b.request);
|
|
2229
|
-
});
|
|
2468
|
+
}, strict);
|
|
2230
2469
|
}
|
|
2231
|
-
async renewPermissionTokensBestEffort(items) {
|
|
2470
|
+
async renewPermissionTokensBestEffort(items, strict = false) {
|
|
2232
2471
|
const CHUNK = 15;
|
|
2233
2472
|
return await this.runBestEffortBatches(items, CHUNK, async (chunk) => {
|
|
2234
2473
|
const built = await this.mapWithConcurrency(chunk, 8, async (c) => await this.buildPermissionOutput(c.request, c.expiry, c.amount));
|
|
2235
2474
|
const inputBeef = new sdk_1.Beef();
|
|
2236
2475
|
for (const c of chunk) {
|
|
2237
|
-
inputBeef.mergeBeef(sdk_1.Beef.
|
|
2476
|
+
inputBeef.mergeBeef(sdk_1.Beef.fromBinaryStrict(c.oldToken.tx));
|
|
2238
2477
|
}
|
|
2239
|
-
|
|
2478
|
+
await this.completePermissionTokenAction({
|
|
2240
2479
|
description: `Renew ${chunk.length} permissions`,
|
|
2241
2480
|
inputBEEF: inputBeef.toBinary(),
|
|
2242
2481
|
inputs: chunk.map((c, i) => ({
|
|
@@ -2250,27 +2489,22 @@ class WalletPermissionsManager {
|
|
|
2250
2489
|
randomizeOutputs: false,
|
|
2251
2490
|
signAndProcess: false
|
|
2252
2491
|
}
|
|
2253
|
-
},
|
|
2254
|
-
if (!signableTransaction?.reference || !signableTransaction.tx) {
|
|
2255
|
-
throw new Error('Failed to create signable transaction');
|
|
2256
|
-
}
|
|
2257
|
-
const partialTx = sdk_1.Transaction.fromAtomicBEEF(signableTransaction.tx);
|
|
2258
|
-
const pushdrop = new sdk_1.PushDrop(this.underlying);
|
|
2259
|
-
const spends = {};
|
|
2260
|
-
for (let i = 0; i < chunk.length; i++) {
|
|
2261
|
-
const token = chunk[i].oldToken;
|
|
2262
|
-
const unlocker = pushdrop.unlock(WalletPermissionsManager.PERM_TOKEN_ENCRYPTION_PROTOCOL, '1', 'self', 'all', false, 1, sdk_1.LockingScript.fromHex(token.outputScript));
|
|
2263
|
-
const unlockingScript = await unlocker.sign(partialTx, i);
|
|
2264
|
-
spends[i] = { unlockingScript: unlockingScript.toHex() };
|
|
2265
|
-
}
|
|
2266
|
-
const { txid } = await this.underlying.signAction({
|
|
2267
|
-
reference: signableTransaction.reference,
|
|
2268
|
-
spends
|
|
2269
|
-
});
|
|
2270
|
-
if (!txid)
|
|
2271
|
-
throw new Error('Failed to finalize renewal transaction');
|
|
2492
|
+
}, chunk.map(item => item.oldToken));
|
|
2272
2493
|
return built.map(b => b.request);
|
|
2273
|
-
});
|
|
2494
|
+
}, strict);
|
|
2495
|
+
}
|
|
2496
|
+
permissionTokenInputSigners(tokens) {
|
|
2497
|
+
const inputSigners = Object.create(null);
|
|
2498
|
+
const pushdrop = new sdk_1.PushDrop(this.underlying);
|
|
2499
|
+
for (const token of tokens) {
|
|
2500
|
+
const outpoint = `${token.txid}.${token.outputIndex}`;
|
|
2501
|
+
const unlocker = pushdrop.unlock(WalletPermissionsManager.PERM_TOKEN_ENCRYPTION_PROTOCOL, '1', 'self', 'all', false, 1, sdk_1.LockingScript.fromHex(token.outputScript));
|
|
2502
|
+
inputSigners[outpoint] = async (transaction, inputIndex) => await unlocker.sign(transaction, inputIndex);
|
|
2503
|
+
}
|
|
2504
|
+
return inputSigners;
|
|
2505
|
+
}
|
|
2506
|
+
async completePermissionTokenAction(args, tokens = []) {
|
|
2507
|
+
return await (0, sdk_1.completeBoundAction)(this, args, { inputSigners: this.permissionTokenInputSigners(tokens) }, this.adminOriginator);
|
|
2274
2508
|
}
|
|
2275
2509
|
async coalescePermissionTokens(oldTokens, newScript, opts) {
|
|
2276
2510
|
if (!oldTokens?.length)
|
|
@@ -2281,9 +2515,9 @@ class WalletPermissionsManager {
|
|
|
2281
2515
|
// Merge all input token BEEFs into a single BEEF structure
|
|
2282
2516
|
const inputBeef = new sdk_1.Beef();
|
|
2283
2517
|
for (const token of oldTokens) {
|
|
2284
|
-
inputBeef.mergeBeef(sdk_1.Beef.
|
|
2518
|
+
inputBeef.mergeBeef(sdk_1.Beef.fromBinaryStrict(token.tx));
|
|
2285
2519
|
}
|
|
2286
|
-
const
|
|
2520
|
+
const transaction = await this.completePermissionTokenAction({
|
|
2287
2521
|
description: opts?.description ?? `Coalesce ${oldTokens.length} permission tokens`,
|
|
2288
2522
|
inputBEEF: inputBeef.toBinary(),
|
|
2289
2523
|
inputs: oldTokens.map((t, i) => ({
|
|
@@ -2305,29 +2539,8 @@ class WalletPermissionsManager {
|
|
|
2305
2539
|
randomizeOutputs: false,
|
|
2306
2540
|
signAndProcess: false
|
|
2307
2541
|
}
|
|
2308
|
-
},
|
|
2309
|
-
|
|
2310
|
-
throw new Error('Failed to create signable transaction');
|
|
2311
|
-
}
|
|
2312
|
-
// 2) Sign each input - each token needs its own unlocker with the correct locking script
|
|
2313
|
-
const partialTx = sdk_1.Transaction.fromAtomicBEEF(signableTransaction.tx);
|
|
2314
|
-
const pushdrop = new sdk_1.PushDrop(this.underlying);
|
|
2315
|
-
const spends = {};
|
|
2316
|
-
for (let i = 0; i < oldTokens.length; i++) {
|
|
2317
|
-
const token = oldTokens[i];
|
|
2318
|
-
// Each token requires its own unlocker with the specific locking script
|
|
2319
|
-
const unlocker = pushdrop.unlock(WalletPermissionsManager.PERM_TOKEN_ENCRYPTION_PROTOCOL, '1', 'self', 'all', false, 1, sdk_1.LockingScript.fromHex(token.outputScript));
|
|
2320
|
-
const unlockingScript = await unlocker.sign(partialTx, i);
|
|
2321
|
-
spends[i] = { unlockingScript: unlockingScript.toHex() };
|
|
2322
|
-
}
|
|
2323
|
-
// 3) Finalize the action
|
|
2324
|
-
const { txid } = await this.underlying.signAction({
|
|
2325
|
-
reference: signableTransaction.reference,
|
|
2326
|
-
spends
|
|
2327
|
-
});
|
|
2328
|
-
if (!txid)
|
|
2329
|
-
throw new Error('Failed to finalize coalescing transaction');
|
|
2330
|
-
return txid;
|
|
2542
|
+
}, oldTokens);
|
|
2543
|
+
return transaction.id('hex');
|
|
2331
2544
|
}
|
|
2332
2545
|
/**
|
|
2333
2546
|
* Renews a permission token by spending the old token as input and creating a new token output.
|
|
@@ -2360,7 +2573,7 @@ class WalletPermissionsManager {
|
|
|
2360
2573
|
// 3) For BRC-100, we do a "createAction" with a partial input referencing oldToken
|
|
2361
2574
|
// plus a single new output. We'll hydrate the template, then signAction for the wallet to finalize.
|
|
2362
2575
|
const oldOutpoint = `${oldToken.txid}.${oldToken.outputIndex}`;
|
|
2363
|
-
|
|
2576
|
+
await this.completePermissionTokenAction({
|
|
2364
2577
|
description: `Renew ${r.type} permission`,
|
|
2365
2578
|
inputBEEF: oldToken.tx,
|
|
2366
2579
|
inputs: [
|
|
@@ -2382,18 +2595,7 @@ class WalletPermissionsManager {
|
|
|
2382
2595
|
options: {
|
|
2383
2596
|
acceptDelayedBroadcast: true
|
|
2384
2597
|
}
|
|
2385
|
-
},
|
|
2386
|
-
const tx = sdk_1.Transaction.fromBEEF(signableTransaction.tx);
|
|
2387
|
-
const unlocker = new sdk_1.PushDrop(this.underlying).unlock(WalletPermissionsManager.PERM_TOKEN_ENCRYPTION_PROTOCOL, '1', 'self', 'all', false, 1, sdk_1.LockingScript.fromHex(oldToken.outputScript));
|
|
2388
|
-
const unlockingScript = await unlocker.sign(tx, 0);
|
|
2389
|
-
await this.underlying.signAction({
|
|
2390
|
-
reference: signableTransaction.reference,
|
|
2391
|
-
spends: {
|
|
2392
|
-
0: {
|
|
2393
|
-
unlockingScript: unlockingScript.toHex()
|
|
2394
|
-
}
|
|
2395
|
-
}
|
|
2396
|
-
});
|
|
2598
|
+
}, [oldToken]);
|
|
2397
2599
|
}
|
|
2398
2600
|
}
|
|
2399
2601
|
/**
|
|
@@ -2494,7 +2696,10 @@ class WalletPermissionsManager {
|
|
|
2494
2696
|
const result = await this.underlying.listOutputs({ basket: BASKET_MAP.protocol, tags, tagQueryMode: 'all', include: 'entire transactions', limit: 10000 }, this.adminOriginator);
|
|
2495
2697
|
await this.collectProtocolTokens(result, originFilter, seen, tokens);
|
|
2496
2698
|
}
|
|
2497
|
-
return tokens
|
|
2699
|
+
return tokens.filter(token => (privileged === undefined || token.privileged === privileged) &&
|
|
2700
|
+
(protocolName === undefined || token.protocol === protocolName) &&
|
|
2701
|
+
(protocolSecurityLevel === undefined || token.securityLevel === protocolSecurityLevel) &&
|
|
2702
|
+
(counterparty === undefined || token.counterparty === counterparty));
|
|
2498
2703
|
}
|
|
2499
2704
|
/** Builds the base tag array for protocol permission listing. */
|
|
2500
2705
|
buildProtocolFilterTags({ privileged, protocolName, protocolSecurityLevel, counterparty }) {
|
|
@@ -2514,12 +2719,11 @@ class WalletPermissionsManager {
|
|
|
2514
2719
|
for (const out of result.outputs) {
|
|
2515
2720
|
if (seen.has(out.outpoint))
|
|
2516
2721
|
continue;
|
|
2517
|
-
const
|
|
2518
|
-
|
|
2519
|
-
const dec = sdk_1.PushDrop.decode(tx.outputs[outputIndex].lockingScript);
|
|
2520
|
-
if (!dec?.fields || dec.fields.length < 6)
|
|
2722
|
+
const source = await this.authenticatedPermissionTokenSource(result, out, 6);
|
|
2723
|
+
if (source == null)
|
|
2521
2724
|
continue;
|
|
2522
|
-
const
|
|
2725
|
+
const { tx, txid, outputIndex } = source;
|
|
2726
|
+
const f = await this.decryptProtocolTokenFields(source.fields);
|
|
2523
2727
|
const normalizedDomain = this.normalizeOriginator(f.domainDecoded);
|
|
2524
2728
|
if (originFilter != null && normalizedDomain !== originFilter.normalized)
|
|
2525
2729
|
continue;
|
|
@@ -2588,25 +2792,24 @@ class WalletPermissionsManager {
|
|
|
2588
2792
|
}, this.adminOriginator);
|
|
2589
2793
|
await this.collectBasketTokens(result, originFilter, seen, tokens);
|
|
2590
2794
|
}
|
|
2591
|
-
return tokens;
|
|
2795
|
+
return params.basket == null ? tokens : tokens.filter(token => token.basketName === params.basket);
|
|
2592
2796
|
}
|
|
2593
2797
|
/** Decodes and appends basket permission tokens from a listOutputs result. */
|
|
2594
2798
|
async collectBasketTokens(result, originFilter, seen, tokens) {
|
|
2595
2799
|
for (const out of result.outputs) {
|
|
2596
2800
|
if (seen.has(out.outpoint))
|
|
2597
2801
|
continue;
|
|
2598
|
-
const
|
|
2599
|
-
|
|
2600
|
-
const dec = sdk_1.PushDrop.decode(tx.outputs[outputIndex].lockingScript);
|
|
2601
|
-
if (!dec?.fields || dec.fields.length < 3)
|
|
2802
|
+
const source = await this.authenticatedPermissionTokenSource(result, out, 3);
|
|
2803
|
+
if (source == null)
|
|
2602
2804
|
continue;
|
|
2603
|
-
const
|
|
2604
|
-
const
|
|
2805
|
+
const { tx, txid, outputIndex } = source;
|
|
2806
|
+
const [domainRaw, expiryRaw, basketRaw] = source.fields;
|
|
2807
|
+
const domainDecoded = await this.decryptPermissionTokenText(domainRaw);
|
|
2605
2808
|
const normalizedDomain = this.normalizeOriginator(domainDecoded);
|
|
2606
2809
|
if (originFilter != null && normalizedDomain !== originFilter.normalized)
|
|
2607
2810
|
continue;
|
|
2608
|
-
const expiryDecoded =
|
|
2609
|
-
const basketDecoded =
|
|
2811
|
+
const expiryDecoded = parseCanonicalPermissionInteger(await this.decryptPermissionTokenText(expiryRaw), 'Permission expiry');
|
|
2812
|
+
const basketDecoded = await this.decryptPermissionTokenText(basketRaw);
|
|
2610
2813
|
seen.add(out.outpoint);
|
|
2611
2814
|
tokens.push({
|
|
2612
2815
|
tx: tx.toBEEF(),
|
|
@@ -2656,27 +2859,28 @@ class WalletPermissionsManager {
|
|
|
2656
2859
|
}, this.adminOriginator);
|
|
2657
2860
|
const tokens = [];
|
|
2658
2861
|
for (const out of result.outputs) {
|
|
2659
|
-
const
|
|
2660
|
-
|
|
2661
|
-
const dec = sdk_1.PushDrop.decode(tx.outputs[Number(outputIndexStr)].lockingScript);
|
|
2662
|
-
if (!dec?.fields || dec.fields.length < 2)
|
|
2862
|
+
const source = await this.authenticatedPermissionTokenSource(result, out, 2);
|
|
2863
|
+
if (source == null)
|
|
2663
2864
|
continue;
|
|
2664
|
-
const
|
|
2665
|
-
const
|
|
2666
|
-
const
|
|
2667
|
-
const authorizedAmount =
|
|
2865
|
+
const { tx, txid, outputIndex, fields } = source;
|
|
2866
|
+
const [domainRaw, amtRaw] = fields;
|
|
2867
|
+
const domainDecoded = await this.decryptPermissionTokenText(domainRaw);
|
|
2868
|
+
const authorizedAmount = parseCanonicalPermissionInteger(await this.decryptPermissionTokenText(amtRaw), 'Permission spending amount', MAX_MONEY_SATOSHIS);
|
|
2668
2869
|
tokens.push({
|
|
2669
2870
|
tx: tx.toBEEF(),
|
|
2670
|
-
txid
|
|
2671
|
-
outputIndex
|
|
2871
|
+
txid,
|
|
2872
|
+
outputIndex,
|
|
2672
2873
|
satoshis: out.satoshis,
|
|
2673
|
-
outputScript: tx.outputs[
|
|
2874
|
+
outputScript: tx.outputs[outputIndex].lockingScript.toHex(),
|
|
2674
2875
|
originator: domainDecoded,
|
|
2675
2876
|
authorizedAmount,
|
|
2676
2877
|
expiry: 0
|
|
2677
2878
|
});
|
|
2678
2879
|
}
|
|
2679
|
-
|
|
2880
|
+
if (params.originator == null)
|
|
2881
|
+
return tokens;
|
|
2882
|
+
const normalizedOriginator = this.prepareOriginator(params.originator).normalized;
|
|
2883
|
+
return tokens.filter(token => this.normalizeOriginator(token.originator) === normalizedOriginator);
|
|
2680
2884
|
}
|
|
2681
2885
|
/**
|
|
2682
2886
|
* Returns `true` if the originator already holds a valid spending authorization token
|
|
@@ -2720,28 +2924,29 @@ class WalletPermissionsManager {
|
|
|
2720
2924
|
const result = await this.underlying.listOutputs({ basket: BASKET_MAP.certificate, tags, tagQueryMode: 'all', include: 'entire transactions', limit: 10000 }, this.adminOriginator);
|
|
2721
2925
|
await this.collectCertificateTokens(result, originFilter, seen, tokens);
|
|
2722
2926
|
}
|
|
2723
|
-
return tokens
|
|
2927
|
+
return tokens.filter(token => (params.privileged === undefined || token.privileged === params.privileged) &&
|
|
2928
|
+
(params.certType === undefined || token.certType === params.certType) &&
|
|
2929
|
+
(params.verifier === undefined || token.verifier === params.verifier));
|
|
2724
2930
|
}
|
|
2725
2931
|
/** Decodes and appends certificate permission tokens from a listOutputs result. */
|
|
2726
2932
|
async collectCertificateTokens(result, originFilter, seen, tokens) {
|
|
2727
2933
|
for (const out of result.outputs) {
|
|
2728
2934
|
if (seen.has(out.outpoint))
|
|
2729
2935
|
continue;
|
|
2730
|
-
const
|
|
2731
|
-
|
|
2732
|
-
const dec = sdk_1.PushDrop.decode(tx.outputs[outputIndex].lockingScript);
|
|
2733
|
-
if (!dec?.fields || dec.fields.length < 6)
|
|
2936
|
+
const source = await this.authenticatedPermissionTokenSource(result, out, 6);
|
|
2937
|
+
if (source == null)
|
|
2734
2938
|
continue;
|
|
2735
|
-
const
|
|
2736
|
-
const
|
|
2939
|
+
const { tx, txid, outputIndex } = source;
|
|
2940
|
+
const [domainRaw, expiryRaw, privRaw, typeRaw, fieldsRaw, verifierRaw] = source.fields;
|
|
2941
|
+
const domainDecoded = await this.decryptPermissionTokenText(domainRaw);
|
|
2737
2942
|
const normalizedDomain = this.normalizeOriginator(domainDecoded);
|
|
2738
2943
|
if (originFilter != null && normalizedDomain !== originFilter.normalized)
|
|
2739
2944
|
continue;
|
|
2740
|
-
const expiryDecoded =
|
|
2741
|
-
const privDecoded =
|
|
2742
|
-
const typeDecoded =
|
|
2743
|
-
const verifierDec =
|
|
2744
|
-
const allFields =
|
|
2945
|
+
const expiryDecoded = parseCanonicalPermissionInteger(await this.decryptPermissionTokenText(expiryRaw), 'Permission expiry');
|
|
2946
|
+
const privDecoded = parsePermissionBoolean(await this.decryptPermissionTokenText(privRaw), 'Permission privileged flag');
|
|
2947
|
+
const typeDecoded = await this.decryptPermissionTokenText(typeRaw);
|
|
2948
|
+
const verifierDec = await this.decryptPermissionTokenText(verifierRaw);
|
|
2949
|
+
const allFields = parsePermissionCertificateFields(await this.decryptPermissionTokenText(fieldsRaw));
|
|
2745
2950
|
seen.add(out.outpoint);
|
|
2746
2951
|
tokens.push({
|
|
2747
2952
|
tx: tx.toBEEF(),
|
|
@@ -2824,9 +3029,9 @@ class WalletPermissionsManager {
|
|
|
2824
3029
|
return;
|
|
2825
3030
|
const inputBeef = new sdk_1.Beef();
|
|
2826
3031
|
for (const token of oldTokens) {
|
|
2827
|
-
inputBeef.mergeBeef(sdk_1.Beef.
|
|
3032
|
+
inputBeef.mergeBeef(sdk_1.Beef.fromBinaryStrict(token.tx));
|
|
2828
3033
|
}
|
|
2829
|
-
|
|
3034
|
+
await this.completePermissionTokenAction({
|
|
2830
3035
|
description: `Revoke ${oldTokens.length} permissions`,
|
|
2831
3036
|
inputBEEF: inputBeef.toBinary(),
|
|
2832
3037
|
inputs: oldTokens.map((t, i) => ({
|
|
@@ -2839,37 +3044,7 @@ class WalletPermissionsManager {
|
|
|
2839
3044
|
randomizeOutputs: false,
|
|
2840
3045
|
signAndProcess: false
|
|
2841
3046
|
}
|
|
2842
|
-
},
|
|
2843
|
-
if (!signableTransaction?.reference || !signableTransaction.tx) {
|
|
2844
|
-
throw new Error('Failed to create signable transaction');
|
|
2845
|
-
}
|
|
2846
|
-
const tx = sdk_1.Transaction.fromAtomicBEEF(signableTransaction.tx);
|
|
2847
|
-
const inputsToSign = oldTokens.map(token => {
|
|
2848
|
-
let permInputIndex = this.findInputIndexForToken(tx, token);
|
|
2849
|
-
if (permInputIndex === -1 && tx.inputs.length === 1) {
|
|
2850
|
-
permInputIndex = 0;
|
|
2851
|
-
}
|
|
2852
|
-
if (permInputIndex === -1) {
|
|
2853
|
-
throw new Error('Unable to locate permission token input for revocation.');
|
|
2854
|
-
}
|
|
2855
|
-
return { token, permInputIndex };
|
|
2856
|
-
});
|
|
2857
|
-
const pushdrop = new sdk_1.PushDrop(this.underlying);
|
|
2858
|
-
const spends = {};
|
|
2859
|
-
const signed = await this.mapWithConcurrency(inputsToSign, 8, async ({ token, permInputIndex }) => {
|
|
2860
|
-
const unlocker = pushdrop.unlock(WalletPermissionsManager.PERM_TOKEN_ENCRYPTION_PROTOCOL, '1', 'self', 'all', false, 1, sdk_1.LockingScript.fromHex(token.outputScript));
|
|
2861
|
-
const unlockingScript = await unlocker.sign(tx, permInputIndex);
|
|
2862
|
-
return { permInputIndex, unlockingScriptHex: unlockingScript.toHex() };
|
|
2863
|
-
});
|
|
2864
|
-
for (const s of signed) {
|
|
2865
|
-
spends[s.permInputIndex] = { unlockingScript: s.unlockingScriptHex };
|
|
2866
|
-
}
|
|
2867
|
-
const { txid } = await this.underlying.signAction({
|
|
2868
|
-
reference: signableTransaction.reference,
|
|
2869
|
-
spends
|
|
2870
|
-
});
|
|
2871
|
-
if (!txid)
|
|
2872
|
-
throw new Error('Failed to finalize revoke transaction');
|
|
3047
|
+
}, oldTokens);
|
|
2873
3048
|
}
|
|
2874
3049
|
/**
|
|
2875
3050
|
* Revokes a permission token by spending it with no replacement output.
|
|
@@ -2877,7 +3052,7 @@ class WalletPermissionsManager {
|
|
|
2877
3052
|
*/
|
|
2878
3053
|
async revokePermission(oldToken) {
|
|
2879
3054
|
const oldOutpoint = `${oldToken.txid}.${oldToken.outputIndex}`;
|
|
2880
|
-
|
|
3055
|
+
await this.completePermissionTokenAction({
|
|
2881
3056
|
description: 'Revoke permission',
|
|
2882
3057
|
inputBEEF: oldToken.tx,
|
|
2883
3058
|
inputs: [
|
|
@@ -2890,30 +3065,13 @@ class WalletPermissionsManager {
|
|
|
2890
3065
|
options: {
|
|
2891
3066
|
acceptDelayedBroadcast: true
|
|
2892
3067
|
}
|
|
2893
|
-
},
|
|
2894
|
-
const tx = sdk_1.Transaction.fromBEEF(signableTransaction.tx);
|
|
2895
|
-
let permInputIndex = this.findInputIndexForToken(tx, oldToken);
|
|
2896
|
-
if (permInputIndex === -1 && tx.inputs.length === 1) {
|
|
2897
|
-
permInputIndex = 0;
|
|
2898
|
-
}
|
|
2899
|
-
if (permInputIndex === -1) {
|
|
2900
|
-
throw new Error('Unable to locate permission token input for revocation.');
|
|
2901
|
-
}
|
|
2902
|
-
const unlocker = new sdk_1.PushDrop(this.underlying).unlock(WalletPermissionsManager.PERM_TOKEN_ENCRYPTION_PROTOCOL, '1', 'self', 'all', false, 1, sdk_1.LockingScript.fromHex(oldToken.outputScript));
|
|
2903
|
-
const unlockingScript = await unlocker.sign(tx, permInputIndex);
|
|
2904
|
-
await this.underlying.signAction({
|
|
2905
|
-
reference: signableTransaction.reference,
|
|
2906
|
-
spends: {
|
|
2907
|
-
[permInputIndex]: {
|
|
2908
|
-
unlockingScript: unlockingScript.toHex()
|
|
2909
|
-
}
|
|
2910
|
-
}
|
|
2911
|
-
});
|
|
3068
|
+
}, [oldToken]);
|
|
2912
3069
|
}
|
|
2913
3070
|
/* ---------------------------------------------------------------------
|
|
2914
3071
|
* 7) BRC-100 WALLET INTERFACE FORWARDING WITH PERMISSION CHECKS
|
|
2915
3072
|
* --------------------------------------------------------------------- */
|
|
2916
3073
|
async createAction(args, originator) {
|
|
3074
|
+
const vargs = (0, validationHelpers_1.validateCreateActionArgs)(args);
|
|
2917
3075
|
// 1) Identify unique P-modules involved (one per schemeID) from both baskets and labels
|
|
2918
3076
|
const pModulesByScheme = new Map();
|
|
2919
3077
|
const nonPBaskets = this.collectNonPBaskets(args.outputs, pModulesByScheme);
|
|
@@ -2947,13 +3105,24 @@ class WalletPermissionsManager {
|
|
|
2947
3105
|
options: modifiedOptions,
|
|
2948
3106
|
labels: [...(args.labels || []), `admin originator ${originator}`, `admin month ${this.getCurrentMonthYearUTC()}`]
|
|
2949
3107
|
};
|
|
2950
|
-
let createResult
|
|
3108
|
+
let createResult;
|
|
3109
|
+
try {
|
|
3110
|
+
createResult = await this.callCreateActionWithPModules(finalArgs, pModulesByScheme, originator);
|
|
3111
|
+
}
|
|
3112
|
+
catch (error) {
|
|
3113
|
+
this.forgetSentNoSendActionsInError(error);
|
|
3114
|
+
throw error;
|
|
3115
|
+
}
|
|
3116
|
+
this.forgetSentNoSendActions(createResult.sendWithResults);
|
|
2951
3117
|
if (createResult.signableTransaction == null)
|
|
2952
3118
|
return createResult;
|
|
2953
|
-
// 7)
|
|
2954
|
-
|
|
3119
|
+
// 7) Bind the action reference before parsing any storage-provided transaction
|
|
3120
|
+
// data. This ensures malformed BEEF is still aborted and cannot leave an
|
|
3121
|
+
// untracked action that may later be signed under another originator.
|
|
2955
3122
|
const reference = createResult.signableTransaction.reference;
|
|
2956
|
-
|
|
3123
|
+
this.bindPendingAction(reference, originator, vargs.isNoSend);
|
|
3124
|
+
// 7a) Parse the signable tx to determine net spend, then gate on spending
|
|
3125
|
+
// authorization. SECURITY (GHSA-36f9-7rg5-cpf8) defense-in-depth: confirm every
|
|
2957
3126
|
// caller-requested output actually appears in the transaction we are about to
|
|
2958
3127
|
// authorize and sign. The locking scripts in the signable transaction
|
|
2959
3128
|
// originate from storage; a malicious or compromised remote storage provider
|
|
@@ -2962,34 +3131,66 @@ class WalletPermissionsManager {
|
|
|
2962
3131
|
// recipient. The signer (buildSignableTransaction) rejects this at the
|
|
2963
3132
|
// source; this is an independent check at the permissions layer.
|
|
2964
3133
|
try {
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
3134
|
+
const tx = sdk_1.Transaction.fromAtomicBEEF(createResult.signableTransaction.tx);
|
|
3135
|
+
const resolvedOutputSatoshis = this.verifyRequestedOutputsPresent(tx, args);
|
|
3136
|
+
let { netSpent, lineItems } = this.computeNetSpend(tx, args, originalInputDescriptions, originalOutputDescriptions, resolvedOutputSatoshis);
|
|
3137
|
+
const exactWalletSpend = (0, exactActionSpend_1.getExactActionSpend)(createResult);
|
|
3138
|
+
if (exactWalletSpend !== undefined) {
|
|
3139
|
+
if (!Number.isSafeInteger(exactWalletSpend) ||
|
|
3140
|
+
exactWalletSpend < -MAX_MONEY_SATOSHIS ||
|
|
3141
|
+
exactWalletSpend > MAX_MONEY_SATOSHIS ||
|
|
3142
|
+
exactWalletSpend < netSpent) {
|
|
3143
|
+
throw new Error('Wallet signer returned an invalid exact action-spend amount.');
|
|
3144
|
+
}
|
|
3145
|
+
const serviceCharge = exactWalletSpend - netSpent;
|
|
3146
|
+
if (serviceCharge > 0) {
|
|
3147
|
+
lineItems = [...lineItems, { type: 'output', satoshis: serviceCharge, description: 'Storage service charge' }];
|
|
3148
|
+
}
|
|
3149
|
+
netSpent = exactWalletSpend;
|
|
3150
|
+
}
|
|
3151
|
+
// 8) If netSpent > 0, require spending authorization. Abort if denied.
|
|
3152
|
+
if (netSpent > 0) {
|
|
2975
3153
|
await this.ensureSpendingAuthorization({
|
|
2976
3154
|
originator: originator,
|
|
2977
3155
|
satoshis: netSpent,
|
|
2978
3156
|
lineItems,
|
|
2979
|
-
reason: originalDescription
|
|
3157
|
+
reason: originalDescription,
|
|
3158
|
+
allowRecentGrant: (0, brc177NoSendExpiry_1.parseBrc177NoSendExpiryLabels)(args.labels) == null
|
|
2980
3159
|
});
|
|
2981
3160
|
}
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
3161
|
+
this.pendingActionTemplates.set(reference, tx);
|
|
3162
|
+
}
|
|
3163
|
+
catch (err) {
|
|
3164
|
+
await this.blockAndAbortAction(reference);
|
|
3165
|
+
throw err;
|
|
2986
3166
|
}
|
|
2987
3167
|
// 9) Finalize or return the signable transaction based on whether more signatures are needed.
|
|
2988
|
-
const vargs = sdk_1.Validation.validateCreateActionArgs(args);
|
|
2989
3168
|
if (vargs.isSignAction)
|
|
2990
3169
|
return createResult;
|
|
2991
|
-
|
|
2992
|
-
|
|
3170
|
+
try {
|
|
3171
|
+
const signResult = await this.underlying.signAction({
|
|
3172
|
+
reference,
|
|
3173
|
+
spends: {},
|
|
3174
|
+
options: { ...args.options, returnTXIDOnly: false }
|
|
3175
|
+
}, originator);
|
|
3176
|
+
this.assertAuthorizedSignResult(reference, {}, signResult);
|
|
3177
|
+
this.clearPendingAction(reference);
|
|
3178
|
+
if (vargs.isNoSend && signResult.txid != null) {
|
|
3179
|
+
this.recordNoSendAction(signResult.txid, originator);
|
|
3180
|
+
}
|
|
3181
|
+
this.forgetSentNoSendActions(signResult.sendWithResults);
|
|
3182
|
+
return {
|
|
3183
|
+
...createResult,
|
|
3184
|
+
...signResult,
|
|
3185
|
+
noSendChange: noSendChangeOnSignedTransaction(createResult.noSendChange, signResult.txid),
|
|
3186
|
+
signableTransaction: undefined
|
|
3187
|
+
};
|
|
3188
|
+
}
|
|
3189
|
+
catch (error) {
|
|
3190
|
+
this.forgetSentNoSendActionsInError(error);
|
|
3191
|
+
await this.blockAndAbortAction(reference);
|
|
3192
|
+
throw error;
|
|
3193
|
+
}
|
|
2993
3194
|
}
|
|
2994
3195
|
/** Scans outputs to split P-scheme baskets from regular baskets; registers P-modules as a side effect. */
|
|
2995
3196
|
collectNonPBaskets(outputs, pModulesByScheme) {
|
|
@@ -3049,8 +3250,6 @@ class WalletPermissionsManager {
|
|
|
3049
3250
|
}
|
|
3050
3251
|
/** Calls underlying createAction, chaining P-module request/response transforms when needed. */
|
|
3051
3252
|
async callCreateActionWithPModules(finalArgs, pModulesByScheme, originator) {
|
|
3052
|
-
if (pModulesByScheme.size === 0)
|
|
3053
|
-
return await this.underlying.createAction(finalArgs, originator);
|
|
3054
3253
|
const pModules = Array.from(pModulesByScheme.values());
|
|
3055
3254
|
let transformedArgs = finalArgs;
|
|
3056
3255
|
for (const module of pModules) {
|
|
@@ -3062,10 +3261,17 @@ class WalletPermissionsManager {
|
|
|
3062
3261
|
transformedArgs = transformed.args;
|
|
3063
3262
|
}
|
|
3064
3263
|
let createResult = await this.underlying.createAction(transformedArgs, originator);
|
|
3264
|
+
const exactWalletSpend = (0, exactActionSpend_1.getExactActionSpend)(createResult);
|
|
3065
3265
|
for (let i = pModules.length - 1; i >= 0; i--) {
|
|
3066
3266
|
createResult = await pModules[i].onResponse(createResult, { method: 'createAction', originator: originator });
|
|
3067
3267
|
}
|
|
3068
|
-
|
|
3268
|
+
// Older local wallets may still attach the legacy symbol. Consume it for
|
|
3269
|
+
// authorization, but never return it across a public BRC-100 boundary.
|
|
3270
|
+
const { [exactActionSpend_1.exactActionSpendSymbol]: _legacySpend, ...publicResult } = createResult;
|
|
3271
|
+
if (exactWalletSpend !== undefined) {
|
|
3272
|
+
(0, exactActionSpend_1.setExactActionSpend)(publicResult, exactWalletSpend);
|
|
3273
|
+
}
|
|
3274
|
+
return publicResult;
|
|
3069
3275
|
}
|
|
3070
3276
|
/**
|
|
3071
3277
|
* Computes the net satoshis the originator is spending in a createAction call,
|
|
@@ -3088,12 +3294,30 @@ class WalletPermissionsManager {
|
|
|
3088
3294
|
* randomized by default, and a caller may legitimately request the same
|
|
3089
3295
|
* script+amount more than once.
|
|
3090
3296
|
*
|
|
3297
|
+
* A sendMax output is requested with the `maxPossibleSatoshis` sentinel
|
|
3298
|
+
* (see storage/methods/generateChange); storage's funding step rewrites it
|
|
3299
|
+
* to the actual funded amount before returning the signable transaction, so
|
|
3300
|
+
* it can never be matched by amount. Fixed-amount outputs are matched first,
|
|
3301
|
+
* as an exact (script, satoshis) multiset exactly as before; any
|
|
3302
|
+
* sentinel-valued requested output is then matched by locking script alone
|
|
3303
|
+
* against whatever the fixed-amount pass left unused. Matching the sentinel
|
|
3304
|
+
* only after fixed-amount outputs are claimed keeps a fixed output that
|
|
3305
|
+
* happens to share the sentinel's locking script from being mis-paired with
|
|
3306
|
+
* it. `generateChange` permits at most one `maxPossibleSatoshis` output per
|
|
3307
|
+
* call; more than one sentinel-valued request is simply matched
|
|
3308
|
+
* independently, first-fit, in requested order.
|
|
3309
|
+
*
|
|
3310
|
+
* @returns the resolved actual satoshis for each requested output index
|
|
3311
|
+
* (identical to the request for a fixed-amount output; the real funded
|
|
3312
|
+
* amount for a sendMax sentinel), so callers can bill the real amount
|
|
3313
|
+
* instead of the sentinel.
|
|
3091
3314
|
* @throws Error if any caller-requested output is absent from the transaction.
|
|
3092
3315
|
*/
|
|
3093
3316
|
verifyRequestedOutputsPresent(tx, args) {
|
|
3094
3317
|
const requested = args.outputs || [];
|
|
3318
|
+
const resolved = new Map();
|
|
3095
3319
|
if (requested.length === 0)
|
|
3096
|
-
return;
|
|
3320
|
+
return resolved;
|
|
3097
3321
|
// All transaction outputs as (script hex, satoshis); each may satisfy at
|
|
3098
3322
|
// most one requested output.
|
|
3099
3323
|
const available = tx.outputs.map(o => ({
|
|
@@ -3101,27 +3325,53 @@ class WalletPermissionsManager {
|
|
|
3101
3325
|
satoshis: o.satoshis,
|
|
3102
3326
|
used: false
|
|
3103
3327
|
}));
|
|
3328
|
+
const sentinelIndexes = [];
|
|
3329
|
+
// Pass 1: every fixed-amount request must match an exact (script, satoshis) pair.
|
|
3104
3330
|
for (let i = 0; i < requested.length; i++) {
|
|
3105
|
-
const wantScript = (requested[i].lockingScript ?? '').toLowerCase();
|
|
3106
3331
|
const wantSats = requested[i].satoshis;
|
|
3332
|
+
if (wantSats === maxPossibleSatoshis_1.maxPossibleSatoshis) {
|
|
3333
|
+
sentinelIndexes.push(i);
|
|
3334
|
+
continue;
|
|
3335
|
+
}
|
|
3336
|
+
const wantScript = (requested[i].lockingScript ?? '').toLowerCase();
|
|
3107
3337
|
const match = available.find(a => !a.used && a.script === wantScript && a.satoshis === wantSats);
|
|
3108
3338
|
if (match == null) {
|
|
3109
3339
|
throw new Error(`The transaction returned for signing does not contain caller-requested output ${i} ` +
|
|
3110
3340
|
`(locking script and amount). The recipient may have been substituted by storage.`);
|
|
3111
3341
|
}
|
|
3112
3342
|
match.used = true;
|
|
3343
|
+
resolved.set(i, (0, validationHelpers_1.validateSatoshis)(match.satoshis, `signable transaction output ${i} satoshis`));
|
|
3113
3344
|
}
|
|
3345
|
+
// Pass 2: match each sendMax sentinel request by locking script only,
|
|
3346
|
+
// against whatever pass 1 left unused.
|
|
3347
|
+
for (const i of sentinelIndexes) {
|
|
3348
|
+
const wantScript = (requested[i].lockingScript ?? '').toLowerCase();
|
|
3349
|
+
const match = available.find(a => !a.used && a.script === wantScript);
|
|
3350
|
+
if (match == null) {
|
|
3351
|
+
throw new Error(`The transaction returned for signing does not contain caller-requested output ${i} ` +
|
|
3352
|
+
`(locking script and amount). The recipient may have been substituted by storage.`);
|
|
3353
|
+
}
|
|
3354
|
+
match.used = true;
|
|
3355
|
+
resolved.set(i, (0, validationHelpers_1.validateSatoshis)(match.satoshis, `signable transaction output ${i} satoshis`));
|
|
3356
|
+
}
|
|
3357
|
+
return resolved;
|
|
3114
3358
|
}
|
|
3115
|
-
computeNetSpend(tx, args, originalInputDescriptions, originalOutputDescriptions) {
|
|
3359
|
+
computeNetSpend(tx, args, originalInputDescriptions, originalOutputDescriptions, resolvedOutputSatoshis) {
|
|
3116
3360
|
const lineItems = [];
|
|
3117
3361
|
// Sum originator-provided inputs:
|
|
3118
3362
|
let totalInputSatoshis = 0;
|
|
3119
3363
|
for (const input of tx.inputs) {
|
|
3120
|
-
const outpoint =
|
|
3364
|
+
const outpoint = this.inputOutpointForBinding(input);
|
|
3121
3365
|
const matchingIndex = (args.inputs || []).findIndex(i => i.outpoint === outpoint);
|
|
3122
3366
|
if (matchingIndex !== -1) {
|
|
3123
|
-
|
|
3124
|
-
|
|
3367
|
+
if (input.sourceTransaction == null) {
|
|
3368
|
+
throw new Error('Caller-provided action input is missing its authenticated source transaction.');
|
|
3369
|
+
}
|
|
3370
|
+
const sourceOutput = input.sourceTransaction.outputs[input.sourceOutputIndex];
|
|
3371
|
+
if (sourceOutput == null)
|
|
3372
|
+
throw new Error('Caller-provided action input source output is missing.');
|
|
3373
|
+
const satoshis = (0, validationHelpers_1.validateSatoshis)(sourceOutput.satoshis, 'caller input satoshis');
|
|
3374
|
+
totalInputSatoshis = this.checkedSatoshiTotal(totalInputSatoshis, satoshis, 'caller input total');
|
|
3125
3375
|
lineItems.push({
|
|
3126
3376
|
type: 'input',
|
|
3127
3377
|
description: originalInputDescriptions[matchingIndex] || 'No input description provided',
|
|
@@ -3129,31 +3379,228 @@ class WalletPermissionsManager {
|
|
|
3129
3379
|
});
|
|
3130
3380
|
}
|
|
3131
3381
|
}
|
|
3132
|
-
// Sum originator-requested outputs
|
|
3133
|
-
|
|
3382
|
+
// Sum originator-requested outputs. A sendMax output's requested satoshis
|
|
3383
|
+
// is the `maxPossibleSatoshis` sentinel, not its real cost; bill the
|
|
3384
|
+
// actual funded amount that verifyRequestedOutputsPresent already resolved
|
|
3385
|
+
// against the signable transaction instead of re-deriving it here (an
|
|
3386
|
+
// independent re-lookup by script could mis-pair a fixed output that
|
|
3387
|
+
// shares the sentinel's locking script).
|
|
3388
|
+
let totalOutputSatoshis = 0;
|
|
3134
3389
|
for (const outIndex in args.outputs || []) {
|
|
3135
|
-
const
|
|
3390
|
+
const index = Number(outIndex);
|
|
3391
|
+
const resolvedSatoshis = resolvedOutputSatoshis.get(index);
|
|
3392
|
+
if (resolvedSatoshis == null) {
|
|
3393
|
+
throw new Error(`Internal error: requested output ${index} was not resolved against the signable transaction.`);
|
|
3394
|
+
}
|
|
3395
|
+
const satoshis = (0, validationHelpers_1.validateSatoshis)(resolvedSatoshis, 'requested output satoshis');
|
|
3396
|
+
totalOutputSatoshis = this.checkedSatoshiTotal(totalOutputSatoshis, satoshis, 'requested output total');
|
|
3136
3397
|
lineItems.push({
|
|
3137
3398
|
type: 'output',
|
|
3138
|
-
satoshis
|
|
3139
|
-
description: originalOutputDescriptions[
|
|
3399
|
+
satoshis,
|
|
3400
|
+
description: originalOutputDescriptions[index] || 'No output description provided'
|
|
3140
3401
|
});
|
|
3141
3402
|
}
|
|
3142
3403
|
// Add an entry for the transaction fee:
|
|
3143
|
-
const fee = tx.getFee();
|
|
3404
|
+
const fee = (0, validationHelpers_1.validateSatoshis)(tx.getFee(), 'network fee');
|
|
3144
3405
|
lineItems.push({ type: 'fee', satoshis: fee, description: 'Network fee' });
|
|
3145
3406
|
/**
|
|
3146
3407
|
* Net spend = total foreign outflows minus total foreign inflows plus fee.
|
|
3147
3408
|
* Domestic wallet inputs/change outputs are not counted — they are internal.
|
|
3148
3409
|
*/
|
|
3149
|
-
const
|
|
3410
|
+
const grossSpent = this.checkedSatoshiTotal(totalOutputSatoshis, fee, 'gross action spend');
|
|
3411
|
+
const netSpent = grossSpent - totalInputSatoshis;
|
|
3412
|
+
if (!Number.isSafeInteger(netSpent) || netSpent < -MAX_MONEY_SATOSHIS || netSpent > MAX_MONEY_SATOSHIS) {
|
|
3413
|
+
throw new Error('Net action spend is outside the supported monetary range.');
|
|
3414
|
+
}
|
|
3150
3415
|
return { netSpent, lineItems };
|
|
3151
3416
|
}
|
|
3417
|
+
checkedSatoshiTotal(left, right, label) {
|
|
3418
|
+
const total = left + right;
|
|
3419
|
+
if (!Number.isSafeInteger(total) || total < 0 || total > MAX_MONEY_SATOSHIS) {
|
|
3420
|
+
throw new Error(`${label} is outside the supported monetary range.`);
|
|
3421
|
+
}
|
|
3422
|
+
return total;
|
|
3423
|
+
}
|
|
3424
|
+
inputOutpointForBinding(input) {
|
|
3425
|
+
const embeddedTxid = input.sourceTransaction?.id('hex');
|
|
3426
|
+
const explicitTxid = input.sourceTXID?.toLowerCase();
|
|
3427
|
+
if (explicitTxid != null && embeddedTxid != null && explicitTxid !== embeddedTxid) {
|
|
3428
|
+
throw new Error('Wallet action input source transaction is inconsistent.');
|
|
3429
|
+
}
|
|
3430
|
+
const txid = explicitTxid ?? embeddedTxid;
|
|
3431
|
+
if (txid == null || !/^[0-9a-f]{64}$/.test(txid)) {
|
|
3432
|
+
throw new Error('Wallet action input transaction ID is invalid.');
|
|
3433
|
+
}
|
|
3434
|
+
if (!Number.isSafeInteger(input.sourceOutputIndex) ||
|
|
3435
|
+
input.sourceOutputIndex < 0 ||
|
|
3436
|
+
input.sourceOutputIndex > 0xffffffff) {
|
|
3437
|
+
throw new Error('Wallet action input output index is invalid.');
|
|
3438
|
+
}
|
|
3439
|
+
return `${txid}.${input.sourceOutputIndex}`;
|
|
3440
|
+
}
|
|
3441
|
+
/** Binds a wallet's final result to the exact template that passed authorization. */
|
|
3442
|
+
assertAuthorizedSignResult(reference, spends, result) {
|
|
3443
|
+
const authorized = this.pendingActionTemplates.get(reference);
|
|
3444
|
+
if (authorized == null)
|
|
3445
|
+
throw new Error('The authorized action template is unavailable.');
|
|
3446
|
+
if (result.tx == null)
|
|
3447
|
+
throw new Error('Wallet finalization omitted transaction data required for binding.');
|
|
3448
|
+
const finalized = sdk_1.Transaction.fromAtomicBEEF(result.tx);
|
|
3449
|
+
if (finalized.version !== authorized.version ||
|
|
3450
|
+
finalized.lockTime !== authorized.lockTime ||
|
|
3451
|
+
finalized.inputs.length !== authorized.inputs.length ||
|
|
3452
|
+
finalized.outputs.length !== authorized.outputs.length) {
|
|
3453
|
+
throw new Error('Wallet finalization substituted the authorized transaction template.');
|
|
3454
|
+
}
|
|
3455
|
+
for (let index = 0; index < authorized.inputs.length; index++) {
|
|
3456
|
+
if (this.inputOutpointForBinding(finalized.inputs[index]) !==
|
|
3457
|
+
this.inputOutpointForBinding(authorized.inputs[index]) ||
|
|
3458
|
+
(finalized.inputs[index].sequence ?? 0xffffffff) !== (authorized.inputs[index].sequence ?? 0xffffffff)) {
|
|
3459
|
+
throw new Error('Wallet finalization substituted an authorized transaction input.');
|
|
3460
|
+
}
|
|
3461
|
+
const authorizedScript = authorized.inputs[index].unlockingScript?.toHex() ?? '';
|
|
3462
|
+
if (authorizedScript !== '' && finalized.inputs[index].unlockingScript?.toHex() !== authorizedScript) {
|
|
3463
|
+
throw new Error('Wallet finalization substituted an existing unlocking script.');
|
|
3464
|
+
}
|
|
3465
|
+
}
|
|
3466
|
+
for (let index = 0; index < authorized.outputs.length; index++) {
|
|
3467
|
+
if (finalized.outputs[index].satoshis !== authorized.outputs[index].satoshis ||
|
|
3468
|
+
finalized.outputs[index].lockingScript.toHex() !== authorized.outputs[index].lockingScript.toHex()) {
|
|
3469
|
+
throw new Error('Wallet finalization substituted an authorized transaction output.');
|
|
3470
|
+
}
|
|
3471
|
+
}
|
|
3472
|
+
for (const [indexText, spend] of Object.entries(spends ?? {})) {
|
|
3473
|
+
if (!/^(0|[1-9]\d*)$/.test(indexText))
|
|
3474
|
+
throw new Error('Signed input index is invalid.');
|
|
3475
|
+
const index = Number(indexText);
|
|
3476
|
+
if (!Number.isSafeInteger(index) || finalized.inputs[index] == null) {
|
|
3477
|
+
throw new Error('Signed input index is invalid.');
|
|
3478
|
+
}
|
|
3479
|
+
if (typeof spend?.unlockingScript !== 'string' ||
|
|
3480
|
+
!/^(?:[0-9a-f]{2})*$/i.test(spend.unlockingScript) ||
|
|
3481
|
+
finalized.inputs[index].unlockingScript?.toHex().toLowerCase() !== spend.unlockingScript.toLowerCase()) {
|
|
3482
|
+
throw new Error('Wallet finalization substituted an authorized unlocking script.');
|
|
3483
|
+
}
|
|
3484
|
+
}
|
|
3485
|
+
const finalizedTxid = finalized.id('hex');
|
|
3486
|
+
if (result.txid != null && result.txid.toLowerCase() !== finalizedTxid) {
|
|
3487
|
+
throw new Error('Wallet finalization transaction ID does not match its transaction data.');
|
|
3488
|
+
}
|
|
3489
|
+
}
|
|
3490
|
+
async blockAndAbortAction(reference) {
|
|
3491
|
+
this.blockedActionReferences.add(reference);
|
|
3492
|
+
const result = await this.underlying.abortAction({ reference });
|
|
3493
|
+
if (result.aborted === true)
|
|
3494
|
+
this.clearPendingAction(reference);
|
|
3495
|
+
}
|
|
3496
|
+
assertPendingActionOriginator(reference, originator, allowBlocked) {
|
|
3497
|
+
if (!allowBlocked && this.blockedActionReferences.has(reference)) {
|
|
3498
|
+
throw new WERR_errors_1.WERR_UNAUTHORIZED('This action was blocked after a failed authorization check.');
|
|
3499
|
+
}
|
|
3500
|
+
const expected = this.pendingActionOriginators.get(reference);
|
|
3501
|
+
if (expected == null) {
|
|
3502
|
+
throw new WERR_errors_1.WERR_UNAUTHORIZED('The action reference was not issued by this permissions manager.');
|
|
3503
|
+
}
|
|
3504
|
+
if (expected !== (originator ?? '')) {
|
|
3505
|
+
throw new WERR_errors_1.WERR_UNAUTHORIZED('The action reference belongs to a different originator.');
|
|
3506
|
+
}
|
|
3507
|
+
}
|
|
3508
|
+
bindPendingAction(reference, originator, noSend) {
|
|
3509
|
+
if (this.pendingActionOriginators.has(reference)) {
|
|
3510
|
+
throw new WERR_errors_1.WERR_UNAUTHORIZED('The action reference is already pending.');
|
|
3511
|
+
}
|
|
3512
|
+
this.pendingActionOriginators.set(reference, originator ?? '');
|
|
3513
|
+
if (noSend)
|
|
3514
|
+
this.pendingNoSendReferences.add(reference);
|
|
3515
|
+
}
|
|
3516
|
+
clearPendingAction(reference) {
|
|
3517
|
+
this.pendingActionOriginators.delete(reference);
|
|
3518
|
+
this.pendingActionTemplates.delete(reference);
|
|
3519
|
+
this.blockedActionReferences.delete(reference);
|
|
3520
|
+
this.pendingNoSendReferences.delete(reference);
|
|
3521
|
+
}
|
|
3522
|
+
/** Lets the originator that created a signed no-send action, and only it, abort it. */
|
|
3523
|
+
recordNoSendAction(txid, originator, reference) {
|
|
3524
|
+
const key = txid.toLowerCase();
|
|
3525
|
+
const references = this.noSendActions.get(key)?.references ?? new Set();
|
|
3526
|
+
this.noSendActions.set(key, { originator: originator ?? '', references });
|
|
3527
|
+
if (reference !== undefined) {
|
|
3528
|
+
references.add(reference);
|
|
3529
|
+
this.noSendActionReferences.set(reference, key);
|
|
3530
|
+
}
|
|
3531
|
+
}
|
|
3532
|
+
forgetNoSendAction(key) {
|
|
3533
|
+
const action = this.noSendActions.get(key);
|
|
3534
|
+
if (action == null)
|
|
3535
|
+
return;
|
|
3536
|
+
for (const reference of action.references) {
|
|
3537
|
+
if (this.noSendActionReferences.get(reference) === key)
|
|
3538
|
+
this.noSendActionReferences.delete(reference);
|
|
3539
|
+
}
|
|
3540
|
+
this.noSendActions.delete(key);
|
|
3541
|
+
}
|
|
3542
|
+
/** Positive broadcast/queue results retire ownership; failures remain retryable. */
|
|
3543
|
+
forgetSentNoSendActions(results) {
|
|
3544
|
+
for (const result of results ?? []) {
|
|
3545
|
+
if (result.status === 'sending' || result.status === 'unproven') {
|
|
3546
|
+
this.forgetNoSendAction(result.txid.toLowerCase());
|
|
3547
|
+
}
|
|
3548
|
+
}
|
|
3549
|
+
}
|
|
3550
|
+
forgetSentNoSendActionsInError(error) {
|
|
3551
|
+
// Undelayed mixed batches report successful members alongside failures in
|
|
3552
|
+
// this error. Preserve the error and every member without positive evidence.
|
|
3553
|
+
if (error instanceof WERR_errors_1.WERR_REVIEW_ACTIONS || error instanceof sdk_1.WERR_REVIEW_ACTIONS) {
|
|
3554
|
+
this.forgetSentNoSendActions(error.sendWithResults);
|
|
3555
|
+
}
|
|
3556
|
+
}
|
|
3152
3557
|
async signAction(...args) {
|
|
3153
|
-
|
|
3558
|
+
const [requestArgs, originator] = args;
|
|
3559
|
+
this.assertPendingActionOriginator(requestArgs.reference, originator, false);
|
|
3560
|
+
// The wallet takes noSend from signAction's options, else from createAction's.
|
|
3561
|
+
const noSend = (requestArgs.options?.noSend ?? this.pendingNoSendReferences.has(requestArgs.reference)) === true;
|
|
3562
|
+
try {
|
|
3563
|
+
const result = await this.underlying.signAction({
|
|
3564
|
+
...requestArgs,
|
|
3565
|
+
options: { ...requestArgs.options, returnTXIDOnly: false }
|
|
3566
|
+
}, originator);
|
|
3567
|
+
this.assertAuthorizedSignResult(requestArgs.reference, requestArgs.spends, result);
|
|
3568
|
+
this.clearPendingAction(requestArgs.reference);
|
|
3569
|
+
if (noSend && result.txid != null) {
|
|
3570
|
+
this.recordNoSendAction(result.txid, originator, requestArgs.reference);
|
|
3571
|
+
}
|
|
3572
|
+
this.forgetSentNoSendActions(result.sendWithResults);
|
|
3573
|
+
return result;
|
|
3574
|
+
}
|
|
3575
|
+
catch (error) {
|
|
3576
|
+
this.forgetSentNoSendActionsInError(error);
|
|
3577
|
+
await this.blockAndAbortAction(requestArgs.reference);
|
|
3578
|
+
throw error;
|
|
3579
|
+
}
|
|
3154
3580
|
}
|
|
3155
3581
|
async abortAction(...args) {
|
|
3156
|
-
|
|
3582
|
+
const [requestArgs, originator] = args;
|
|
3583
|
+
// Pending references live in memory only. The admin may abort any of the
|
|
3584
|
+
// wallet's actions, including signed noSend actions and earlier sessions'.
|
|
3585
|
+
// A signed no-send action is found by the reference it was signed under or by its txid.
|
|
3586
|
+
const noSendKey = typeof requestArgs.reference === 'string'
|
|
3587
|
+
? (this.noSendActionReferences.get(requestArgs.reference) ?? requestArgs.reference.toLowerCase())
|
|
3588
|
+
: '';
|
|
3589
|
+
const noSendOriginator = this.noSendActions.get(noSendKey)?.originator;
|
|
3590
|
+
if (originator === undefined || !this.isAdminOriginator(originator)) {
|
|
3591
|
+
if (noSendOriginator === undefined) {
|
|
3592
|
+
this.assertPendingActionOriginator(requestArgs.reference, originator, true);
|
|
3593
|
+
}
|
|
3594
|
+
else if (noSendOriginator !== (originator ?? '')) {
|
|
3595
|
+
throw new WERR_errors_1.WERR_UNAUTHORIZED('The action reference belongs to a different originator.');
|
|
3596
|
+
}
|
|
3597
|
+
}
|
|
3598
|
+
const result = await this.underlying.abortAction(...args);
|
|
3599
|
+
if (result.aborted === true) {
|
|
3600
|
+
this.clearPendingAction(requestArgs.reference);
|
|
3601
|
+
this.forgetNoSendAction(noSendKey);
|
|
3602
|
+
}
|
|
3603
|
+
return result;
|
|
3157
3604
|
}
|
|
3158
3605
|
async listActions(...args) {
|
|
3159
3606
|
const [requestArgs, originator] = args;
|
|
@@ -3568,6 +4015,8 @@ class WalletPermissionsManager {
|
|
|
3568
4015
|
usageType: 'generic'
|
|
3569
4016
|
});
|
|
3570
4017
|
}
|
|
4018
|
+
// The underlying wallet may satisfy this with a caller-installed local trust anchor or the
|
|
4019
|
+
// certificate overlay. This permission gate authorizes resolution, not external certification.
|
|
3571
4020
|
return await this.underlying.discoverByIdentityKey(...args);
|
|
3572
4021
|
}
|
|
3573
4022
|
async discoverByAttributes(...args) {
|
|
@@ -3582,6 +4031,8 @@ class WalletPermissionsManager {
|
|
|
3582
4031
|
usageType: 'generic'
|
|
3583
4032
|
});
|
|
3584
4033
|
}
|
|
4034
|
+
// The underlying wallet may satisfy this with a caller-installed local trust anchor or the
|
|
4035
|
+
// certificate overlay. This permission gate authorizes resolution, not external certification.
|
|
3585
4036
|
return await this.underlying.discoverByAttributes(...args);
|
|
3586
4037
|
}
|
|
3587
4038
|
async isAuthenticated(...args) {
|
|
@@ -3768,7 +4219,11 @@ class WalletPermissionsManager {
|
|
|
3768
4219
|
}
|
|
3769
4220
|
return true;
|
|
3770
4221
|
}
|
|
3771
|
-
/**
|
|
4222
|
+
/**
|
|
4223
|
+
* Normalizes originator domains to their lowercase hostname. BRC-100
|
|
4224
|
+
* permission authority is hostname-scoped, so every port shares the same
|
|
4225
|
+
* grants and admin status.
|
|
4226
|
+
*/
|
|
3772
4227
|
normalizeOriginator(originator) {
|
|
3773
4228
|
if (!originator)
|
|
3774
4229
|
return '';
|
|
@@ -3786,12 +4241,7 @@ class WalletPermissionsManager {
|
|
|
3786
4241
|
const hostname = url.hostname.toLowerCase();
|
|
3787
4242
|
const needsBrackets = hostname.includes(':');
|
|
3788
4243
|
const baseHost = needsBrackets ? `[${hostname}]` : hostname;
|
|
3789
|
-
|
|
3790
|
-
const defaultPort = WalletPermissionsManager.DEFAULT_PORTS[url.protocol];
|
|
3791
|
-
if (port && defaultPort && port === defaultPort) {
|
|
3792
|
-
return baseHost;
|
|
3793
|
-
}
|
|
3794
|
-
return port ? `${baseHost}:${port}` : baseHost;
|
|
4244
|
+
return baseHost;
|
|
3795
4245
|
}
|
|
3796
4246
|
catch {
|
|
3797
4247
|
// Fall back to a conservative lowercase trim if URL parsing fails.
|
|
@@ -3822,8 +4272,37 @@ class WalletPermissionsManager {
|
|
|
3822
4272
|
if (!trimmed) {
|
|
3823
4273
|
throw new Error('Originator is required for permission checks.');
|
|
3824
4274
|
}
|
|
4275
|
+
if (/^[a-zA-Z][a-zA-Z\d+\-.]*:\/\//.test(trimmed)) {
|
|
4276
|
+
throw new Error('Originator must be a domain name with an optional port, without a URL scheme.');
|
|
4277
|
+
}
|
|
4278
|
+
let parsed;
|
|
4279
|
+
try {
|
|
4280
|
+
parsed = new URL(`https://${trimmed}`);
|
|
4281
|
+
}
|
|
4282
|
+
catch {
|
|
4283
|
+
throw new Error('Originator must be a valid domain name with an optional port.');
|
|
4284
|
+
}
|
|
4285
|
+
if (parsed.username !== '' ||
|
|
4286
|
+
parsed.password !== '' ||
|
|
4287
|
+
parsed.pathname !== '/' ||
|
|
4288
|
+
parsed.search !== '' ||
|
|
4289
|
+
parsed.hash !== '') {
|
|
4290
|
+
throw new Error('Originator must not contain credentials, a path, query parameters, or a fragment.');
|
|
4291
|
+
}
|
|
4292
|
+
const hostname = parsed.hostname.toLowerCase();
|
|
4293
|
+
if (hostname.includes(':') || /^\d+(?:\.\d+){3}$/u.test(hostname)) {
|
|
4294
|
+
throw new Error('IP address originators are not permitted.');
|
|
4295
|
+
}
|
|
4296
|
+
if (hostname !== 'localhost' &&
|
|
4297
|
+
!hostname.split('.').every(label => /^[a-z\d](?:[a-z\d-]{0,61}[a-z\d])?$/u.test(label))) {
|
|
4298
|
+
throw new Error('Originator must be a valid DNS hostname.');
|
|
4299
|
+
}
|
|
3825
4300
|
const normalized = this.normalizeOriginator(trimmed) || trimmed.toLowerCase();
|
|
3826
|
-
|
|
4301
|
+
// Search both current canonical tags and exact legacy tags first. The
|
|
4302
|
+
// untagged bounded fallback lets a grant minted for another port on this
|
|
4303
|
+
// hostname remain usable; decoded token fields are still authenticated and
|
|
4304
|
+
// compared to `normalized` before acceptance.
|
|
4305
|
+
const lookupValues = Array.from(new Set([trimmed, normalized, undefined]));
|
|
3827
4306
|
return { normalized, lookupValues };
|
|
3828
4307
|
}
|
|
3829
4308
|
/**
|
|
@@ -3859,6 +4338,10 @@ class WalletPermissionsManager {
|
|
|
3859
4338
|
}
|
|
3860
4339
|
buildActiveRequestKey(r) {
|
|
3861
4340
|
const base = this.buildRequestKey(r);
|
|
4341
|
+
if (r.type === 'spending') {
|
|
4342
|
+
this.spendingRequestSequence += 1;
|
|
4343
|
+
return `${base}:request:${this.spendingRequestSequence}`;
|
|
4344
|
+
}
|
|
3862
4345
|
if (r.type === 'protocol' || r.type === 'basket' || r.type === 'certificate') {
|
|
3863
4346
|
return `${base}:${r.usageType ?? ''}`;
|
|
3864
4347
|
}
|