UNPKG

@bsv/wallet-toolbox-mobile

Version:

React Native and mobile-safe BRC-100 wallet, signer, and remote storage components

1 lines 2.44 MB
{"version":3,"file":"index.mobile.mjs","names":["SdkUtils","sp","wsm","BsvTransaction","sdk.WERR_INVALID_PARAMETER","sdk.WERR_INVALID_OPERATION","sdk.WERR_NOT_ACTIVE","sdk.WERR_UNAUTHORIZED","sdk.WERR_INTERNAL","sdk.WERR_NOT_IMPLEMENTED","makeKnownTxidLookup","processAction","BsvTransaction","sdk.WERR_INTERNAL","createAction","createActionCore","internalizeAction","trimInputBeef","createAction","internalizeAction","writeUInt32BE","readUInt32BE","BsvTransaction","sdk.WERR_INVALID_OPERATION","sdk.WERR_INTERNAL","beginBatch","extendBatch","renewBatch","prepareBatchCommit","putBatchBlob","putBatchPack","commitBatch","commitBatchByDigest","abortBatch","processAction","sdk.WERR_UNAUTHORIZED","TAG","isObject","vbhfs","stripTrailingSlash","defaultDeploymentId","BsvTransaction","createInsertHeaderResult"],"sources":["../../src/sdk/WalletError.ts","../../src/sdk/WERR_errors.ts","../../src/sdk/WalletErrorFromJson.ts","../../src/sdk/types.ts","../../src/sdk/PrivilegedKeyManager.ts","../../src/sdk/index.ts","../../src/utility/stampLog.ts","../../src/utility/utilityHelpers.noBuffer.ts","../../src/utility/utilityHelpers.ts","../../src/utility/ScriptTemplateBRC29.ts","../../src/utility/parseTxScriptOffsets.ts","../../src/utility/tscProofToMerklePath.ts","../../src/utility/brc114ActionTimeLabels.ts","../../src/storage/schema/entities/EntityBase.ts","../../src/storage/schema/entities/EntityCertificate.ts","../../src/storage/schema/entities/EntityCertificateField.ts","../../src/storage/schema/entities/EntityCommission.ts","../../src/storage/schema/entities/EntityOutput.ts","../../src/storage/schema/entities/EntityOutputBasket.ts","../../src/storage/schema/entities/EntityOutputTag.ts","../../src/storage/schema/entities/EntityOutputTagMap.ts","../../src/storage/schema/entities/EntityProvenTx.ts","../../src/storage/schema/entities/EntityProvenTxReq.ts","../../src/storage/schema/entities/EntityTransaction.ts","../../src/storage/schema/entities/EntityTxLabel.ts","../../src/storage/schema/entities/EntityTxLabelMap.ts","../../src/storage/schema/entities/EntityUser.ts","../../src/storage/schema/entities/MergeEntity.ts","../../src/storage/schema/entities/EntitySyncState.ts","../../src/storage/WalletStorageManager.ts","../../src/storage/storageProviderHelpers.ts","../../src/storage/methods/getBeefForTransaction.ts","../../src/utility/aggregateResults.ts","../../src/storage/methods/processAction.ts","../../src/storage/methods/attemptToPostReqsToNetwork.ts","../../src/storage/methods/listCertificates.ts","../../src/storage/methods/utils.ts","../../src/storage/methods/generateChange.ts","../../src/signer/methods/acquireDirectCertificate.ts","../../src/signer/methods/proveCertificate.ts","../../src/signer/methods/buildSignableTransaction.ts","../../src/signer/methods/verifyUnlockScripts.ts","../../src/signer/methods/completeSignedTransaction.ts","../../src/signer/methods/resultBeef.ts","../../src/signer/methods/createAction.ts","../../src/signer/methods/signAction.ts","../../src/signer/methods/internalizeAction.ts","../../src/WalletSettingsManager.ts","../../src/utility/identityUtils.ts","../../src/signer/actionBatch/actionBatchBootstrap.ts","../../src/utility/actionBatchDigest.ts","../../src/utility/beefForTxids.ts","../../src/storage/methods/offsetKey.ts","../../src/storage/methods/actionPlanning.ts","../../src/signer/actionBatch/ActionBatchPlanner.ts","../../src/utility/actionBatchPack.ts","../../src/signer/actionBatch/ActionBatchWorkspace.ts","../../src/Wallet.ts","../../src/storage/methods/managedChange.ts","../../src/storage/methods/createAction.ts","../../src/services/chaintracker/chaintracks/util/dirtyHashes.ts","../../src/services/chaintracker/chaintracks/util/validBulkHeaderFilesByFileHash.ts","../../src/services/chaintracker/chaintracks/util/blockHeaderUtilities.ts","../../src/storage/methods/internalizeAction.ts","../../src/storage/methods/getSyncChunk.ts","../../src/storage/StorageReader.ts","../../src/storage/StorageReaderWriter.ts","../../src/storage/methods/actionBatchBlobs.ts","../../src/storage/methods/actionBatchValidation.ts","../../src/storage/methods/actionBatch.ts","../../src/storage/methods/availableManagedChange.ts","../../src/storage/StorageProvider.ts","../../src/storage/StorageSyncReader.ts","../../src/storage/schema/tables/TableTransaction.ts","../../src/storage/schema/tables/TableOutput.ts","../../src/storage/schema/tables/TableAuthSession.ts","../../src/storage/remoting/entityValidationHelpers.ts","../../src/storage/remoting/StorageClientBase.ts","../../src/storage/remoting/BinaryJson.ts","../../src/storage/remoting/StorageMobile.ts","../../src/utility/hashWasm.ts","../../src/storage/portable/index.ts","../../src/storage/methods/ListActionsSpecOp.ts","../../src/storage/methods/ListOutputsSpecOp.ts","../../src/services/chaintracker/chaintracks/Api/BlockHeaderApi.ts","../../src/services/chaintracker/chaintracks/util/HeightRange.ts","../../src/services/chaintracker/chaintracks/util/SingleWriterMultiReaderLock.ts","../../src/services/chaintracker/chaintracks/Chaintracks.ts","../../src/services/chaintracker/chaintracks/ChaintracksServiceClient.ts","../../src/services/chaintracker/chaintracks/GoChaintracksServiceClient.ts","../../src/services/chaintracker/chaintracks/Ingest/BulkIngestorBase.ts","../../src/services/chaintracker/chaintracks/Ingest/LiveIngestorBase.ts","../../src/services/chaintracker/chaintracks/util/BulkFileDataReader.ts","../../src/services/chaintracker/chaintracks/util/ChaintracksFetch.ts","../../src/services/chaintracker/chaintracks/util/BulkFileDataManager.ts","../../src/services/chaintracker/chaintracks/Ingest/BulkIngestorCDN.ts","../../src/services/chaintracker/chaintracks/Ingest/BulkIngestorCDNBabbage.ts","../../src/services/providers/SdkWhatsOnChain.ts","../../src/services/ServiceCollection.ts","../../src/services/networkConfig.ts","../../src/services/createDefaultWalletServicesOptions.ts","../../src/services/providers/exchangeRates.ts","../../src/services/providers/ARC.ts","../../src/services/providers/Arcade.ts","../../src/services/providers/Bitails.ts","../../src/services/providers/getBeefForTxid.ts","../../src/services/chaintracker/ChaintracksChainTracker.ts","../../src/services/Services.ts","../../src/services/providers/whatsOnChainHelpers.ts","../../src/services/providers/WhatsOnChain.ts","../../src/services/chaintracker/chaintracks/Ingest/WhatsOnChainServices.ts","../../src/services/chaintracker/chaintracks/Ingest/BulkIngestorWhatsOnChainCdn.ts","../../src/services/chaintracker/chaintracks/Ingest/BulkIngestorChaintracks.ts","../../src/services/chaintracker/chaintracks/Ingest/LiveIngestorWhatsOnChainPoll.ts","../../src/services/chaintracker/chaintracks/Ingest/LiveIngestorChaintracksSSE.ts","../../src/services/chaintracker/chaintracks/Storage/BulkStorageBase.ts","../../src/services/chaintracker/chaintracks/util/BulkHeaderFile.ts","../../src/services/chaintracker/chaintracks/util/BulkFilesReader.ts","../../src/services/chaintracker/chaintracks/Storage/ChaintracksStorageBase.ts","../../src/services/chaintracker/chaintracks/Storage/ChaintracksStorageNoDb.ts","../../src/services/chaintracker/chaintracks/Storage/ChaintracksStorageIdb.ts","../../src/services/chaintracker/chaintracks/configureChaintracksIngestors.ts","../../src/services/chaintracker/chaintracks/createDefaultNoDbChaintracksOptions.ts","../../src/services/chaintracker/chaintracks/createNoDbChaintracks.ts","../../src/CWIStyleWalletManager.ts","../../src/monitor/tasks/WalletMonitorTask.ts","../../src/monitor/tasks/TaskPurge.ts","../../src/monitor/tasks/TaskReviewStatus.ts","../../src/monitor/tasks/TaskFailAbandoned.ts","../../src/monitor/tasks/TaskCheckForProofs.ts","../../src/monitor/tasks/TaskClock.ts","../../src/monitor/tasks/TaskNewHeader.ts","../../src/monitor/tasks/TaskMonitorCallHistory.ts","../../src/monitor/tasks/TaskReorg.ts","../../src/services/providers/ArcSSEClient.ts","../../src/monitor/tasks/TaskUnFail.ts","../../src/monitor/tasks/TaskArcSSE.ts","../../src/monitor/tasks/TaskMineBlock.ts","../../src/monitor/tasks/TaskSendWaiting.ts","../../src/monitor/tasks/TaskCheckNoSends.ts","../../src/monitor/tasks/TaskReviewUtxos.ts","../../src/monitor/tasks/TaskReviewDoubleSpends.ts","../../src/monitor/tasks/TaskReviewProvenTxs.ts","../../src/monitor/tasks/TaskCleanupActionBatches.ts","../../src/monitor/Monitor.ts","../../src/signer/WalletSigner.ts","../../src/SimpleWalletManager.ts","../../src/wab-client/WABTransport.ts","../../src/wab-client/auth-method-interactors/AuthMethodInteractor.ts","../../src/wab-client/auth-method-interactors/PersonaIDInteractor.ts","../../src/wab-client/auth-method-interactors/TwilioPhoneInteractor.ts","../../src/wab-client/auth-method-interactors/DevConsoleInteractor.ts","../../src/wab-client/WABClient.ts","../../src/WalletLogger.ts","../../src/WalletAuthenticationManager.ts","../../src/WalletPermissionsManager.ts"],"sourcesContent":["import { ErrorCodeString10To40Bytes, ErrorDescriptionString20To200Bytes, WalletErrorObject } from '@bsv/sdk'\n\n/**\n * Derived class constructors should use the derived class name as the value for `name`,\n * and an internationalizable constant string for `message`.\n *\n * If a derived class intends to wrap another WalletError, the public property should\n * be named `walletError` and will be recovered by `fromUnknown`.\n *\n * Optionaly, the derived class `message` can include template parameters passed in\n * to the constructor. See WERR_MISSING_PARAMETER for an example.\n *\n * To avoid derived class name colisions, packages should include a package specific\n * identifier after the 'WERR_' prefix. e.g. 'WERR_FOO_' as the prefix for Foo package error\n * classes.\n */\nexport class WalletError extends Error implements WalletErrorObject {\n // Facilitates detection of Error objects from non-error return values.\n isError = true as const\n\n constructor(\n name: string,\n message: string,\n stack?: string,\n public details?: Record<string, string>\n ) {\n super(message)\n this.name = name\n if (stack != null && stack !== '') this.stack = stack\n }\n\n /**\n * Error class compatible accessor for `code`.\n */\n get code(): ErrorCodeString10To40Bytes {\n return this.name\n }\n\n set code(v: ErrorCodeString10To40Bytes) {\n this.name = v\n }\n\n /**\n * Error class compatible accessor for `description`.\n */\n get description(): ErrorDescriptionString20To200Bytes {\n return this.message\n }\n\n set description(v: ErrorDescriptionString20To200Bytes) {\n this.message = v\n }\n\n /**\n * Recovers all public fields from WalletError derived error classes and relevant Error derived errors.\n *\n */\n private static nonEmptyString(value: unknown): string | undefined {\n return typeof value === 'string' && value !== '' ? value : undefined\n }\n\n private static objectErrorFields(error: Record<string, unknown>): {\n name: string\n message: string\n stack: string | undefined\n details: Record<string, string> | undefined\n } {\n const stringValue = WalletError.nonEmptyString\n const genericName = error.name === 'Error' || error.name === 'FetchError'\n const name = genericName\n ? (stringValue(error.code) ?? stringValue(error.status) ?? 'WERR_UNKNOWN')\n : (stringValue(error.name) ?? stringValue(error.code) ?? stringValue(error.status) ?? 'WERR_UNKNOWN')\n const message = stringValue(error.message) ?? stringValue(error.description) ?? ''\n const stack = typeof error.stack === 'string' ? error.stack : undefined\n const details: Record<string, string> = {}\n if (typeof error.sql === 'string') details.sql = error.sql\n if (typeof error.sqlMessage === 'string') details.sqlMessage = error.sqlMessage\n return {\n name,\n message,\n stack,\n details: Object.keys(details).length > 0 ? details : undefined\n }\n }\n\n private static copyPublicErrorFields(target: WalletError, source: Record<string, unknown>): void {\n const extensibleTarget = target as WalletError & Record<string, unknown>\n const baseFields = new Set(['status', 'name', 'code', 'message', 'description', 'stack', 'sql', 'sqlMessage'])\n for (const [key, value] of Object.entries(source)) {\n const supportedValue = typeof value === 'string' || typeof value === 'number' || Array.isArray(value)\n if (key === 'walletError') {\n extensibleTarget[key] = WalletError.fromUnknown(value)\n } else if (!baseFields.has(key) && supportedValue) {\n extensibleTarget[key] = value\n }\n }\n }\n\n static fromUnknown(err: unknown): WalletError {\n if (err instanceof WalletError) return err\n let message = ''\n if (typeof err === 'string') {\n message = err\n } else if (typeof err === 'number') {\n message = err.toString()\n }\n let fields = {\n name: 'WERR_UNKNOWN',\n message,\n stack: undefined as string | undefined,\n details: undefined as Record<string, string> | undefined\n }\n if (err !== null && typeof err === 'object') {\n fields = WalletError.objectErrorFields(err as Record<string, unknown>)\n }\n const e = new WalletError(fields.name, fields.message, fields.stack, fields.details)\n if (err !== null && typeof err === 'object') {\n WalletError.copyPublicErrorFields(e, err as Record<string, unknown>)\n }\n return e\n }\n\n /**\n * @returns standard HTTP error status object with status property set to 'error'.\n */\n asStatus(): { status: string; code: string; description: string } {\n return {\n status: 'error',\n code: this.name,\n description: this.message\n }\n }\n\n /**\n * Base class default JSON serialization.\n * Captures just the name and message properties.\n *\n * Override this method to safely (avoid deep, large, circular issues) serialize\n * derived class properties.\n *\n * @returns stringified JSON representation of the WalletError.\n */\n protected toJson(): string {\n const e = new WalletError(this.name, this.message)\n const json = JSON.stringify({\n isError: true,\n name: e.name,\n message: e.message\n })\n return json\n }\n\n /**\n * Safely serializes a WalletError derived, WERR_REVIEW_ACTIONS (special case), Error or unknown error to JSON.\n *\n * Safely means avoiding deep, large, circular issues.\n *\n * @param error\n * @returns stringified JSON representation of the error such that it can be desirialized to a WalletError.\n */\n static unknownToJson(error: unknown): string {\n let json: string | undefined\n let e: WalletError | undefined\n const t = typeof error\n const ctorName: unknown =\n t === 'object' && error !== null ? (error as Record<string, unknown>).constructor : undefined\n const ctor: string | undefined =\n ctorName != null && typeof (ctorName as Record<string, unknown>).name === 'string'\n ? ((ctorName as Record<string, unknown>).name as string)\n : undefined\n const name = t === 'object' && error !== null && typeof (error as any).name === 'string' ? (error as any).name : ''\n const message =\n t === 'object' && error !== null && typeof (error as any).message === 'string' ? (error as any).message : ''\n const hasToJson: boolean = t === 'object' && typeof (error as any)?.toJson === 'function'\n if (ctor != null && ctor !== '' && ctor.startsWith('WERR_') && hasToJson) {\n json = (error as WalletError).toJson()\n } else if (name !== '' && message !== '') {\n e = new WalletError(name, message)\n json = e.toJson()\n } else {\n e = new WalletError('WERR_UNKNOWN', String(error))\n json = e.toJson()\n }\n return json\n }\n}\n","import { AtomicBEEF, OutpointString, SendWithResult, TXIDHexString, WalletNetwork } from '@bsv/sdk'\nimport { WalletError } from './WalletError'\nimport { ReviewActionResult } from './WalletStorage.interfaces'\n\n/**\n * Not implemented.\n */\nexport class WERR_NOT_IMPLEMENTED extends WalletError {\n constructor(message?: string) {\n super('WERR_NOT_IMPLEMENTED', message ?? 'Not implemented.')\n }\n}\n\n/**\n * An internal error has occurred.\n *\n * This is an example of an error with an optional custom `message`.\n */\nexport class WERR_INTERNAL extends WalletError {\n constructor(message?: string) {\n super('WERR_INTERNAL', message ?? 'An internal error has occurred.')\n }\n}\n\n/**\n * The ${parameter} parameter is invalid.\n *\n * This is an example of an error object with a custom property `parameter` and templated `message`.\n */\nexport class WERR_INVALID_OPERATION extends WalletError {\n constructor(message?: string) {\n super('WERR_INVALID_OPERATION', message ?? 'An invalid operation was requested.')\n }\n}\n\n/**\n * Unable to broadcast transaction at this time.\n */\nexport class WERR_BROADCAST_UNAVAILABLE extends WalletError {\n constructor(_message?: string) {\n super('WERR_BROADCAST_UNAVAILABLE', 'Unable to broadcast transaction at this time.')\n }\n}\n\n/**\n * The ${parameter} parameter is invalid.\n *\n * This is an example of an error object with a custom property `parameter` and templated `message`.\n */\nexport class WERR_INVALID_PARAMETER extends WalletError {\n constructor(\n public parameter: string,\n mustBe?: string\n ) {\n super('WERR_INVALID_PARAMETER', `The ${parameter} parameter must be ${mustBe ?? 'valid.'}`)\n }\n\n override toJson(): string {\n const obj = JSON.parse(super.toJson())\n obj.code = 6 // Must match HTTPWalletJSON.ts code\n obj.parameter = this.parameter\n return JSON.stringify(obj)\n }\n}\n\n/**\n * Invalid merkleRoot ${merkleRoot} for block ${blockHash} at height ${blockHeight}${txid ? ` for txid ${txid}` : ''}.\n *\n * Typically thrown when a chain tracker fails to validate a merkle root.\n */\nexport class WERR_INVALID_MERKLE_ROOT extends WalletError {\n constructor(\n public blockHash: string,\n public blockHeight: number,\n public merkleRoot: string,\n public txid?: string\n ) {\n super(\n 'WERR_INVALID_MERKLE_ROOT',\n `Invalid merkleRoot ${merkleRoot} for block ${blockHash} at height ${blockHeight}${txid != null ? ' for txid ' + txid : ''}.`\n )\n }\n\n override toJson(): string {\n const obj = JSON.parse(super.toJson())\n obj.code = 8 // Must match HTTPWalletJSON.ts code\n obj.blockHash = this.blockHash\n obj.blockHeight = this.blockHeight\n obj.merkleRoot = this.merkleRoot\n obj.txid = this.txid\n return JSON.stringify(obj)\n }\n}\n\n/**\n * The required ${parameter} parameter is missing.\n *\n * This is an example of an error object with a custom property `parameter`\n */\nexport class WERR_MISSING_PARAMETER extends WalletError {\n constructor(public parameter: string) {\n super('WERR_MISSING_PARAMETER', `The required ${parameter} parameter is missing.`)\n }\n\n override toJson(): string {\n const obj = JSON.parse(super.toJson())\n obj.parameter = this.parameter\n return JSON.stringify(obj)\n }\n}\n\n/**\n * The request is invalid.\n */\nexport class WERR_BAD_REQUEST extends WalletError {\n constructor(message?: string) {\n super('WERR_BAD_REQUEST', message ?? 'The request is invalid.')\n }\n}\n\n/**\n * Configured network chain is invalid or does not match across services.\n */\nexport class WERR_NETWORK_CHAIN extends WalletError {\n constructor(message?: string) {\n super('WERR_NETWORK_CHAIN', message ?? 'Configured network chain is invalid or does not match across services.')\n }\n}\n\n/**\n * Access is denied due to an authorization error.\n */\nexport class WERR_UNAUTHORIZED extends WalletError {\n constructor(message?: string) {\n super('WERR_UNAUTHORIZED', message ?? 'Access is denied due to an authorization error.')\n }\n}\n\n/**\n * WalletStorageManager is not accessing user's active storage or there are conflicting active stores configured.\n */\nexport class WERR_NOT_ACTIVE extends WalletError {\n constructor(message?: string) {\n super(\n 'WERR_NOT_ACTIVE',\n message ??\n \"WalletStorageManager is not accessing user's active storage or there are conflicting active stores configured.\"\n )\n }\n}\n\n/**\n * Insufficient funds in the available inputs to cover the cost of the required outputs\n * and the transaction fee (${moreSatoshisNeeded} more satoshis are needed,\n * for a total of ${totalSatoshisNeeded}), plus whatever would be required in order\n * to pay the fee to unlock and spend the outputs used to provide the additional satoshis.\n */\nexport class WERR_INSUFFICIENT_FUNDS extends WalletError {\n /**\n * @param totalSatoshisNeeded Total satoshis required to fund transactions after net of required inputs and outputs.\n * @param moreSatoshisNeeded Shortfall on total satoshis required to fund transactions after net of required inputs and outputs.\n */\n constructor(\n public totalSatoshisNeeded: number,\n public moreSatoshisNeeded: number\n ) {\n super(\n 'WERR_INSUFFICIENT_FUNDS',\n `Insufficient funds in the available inputs to cover the cost of the required outputs and the transaction fee (${moreSatoshisNeeded} more satoshis are needed, for a total of ${totalSatoshisNeeded}), plus whatever would be required in order to pay the fee to unlock and spend the outputs used to provide the additional satoshis.`\n )\n }\n\n override toJson(): string {\n const obj = JSON.parse(super.toJson())\n obj.code = 7 // Must match HTTPWalletJSON.ts code\n obj.totalSatoshisNeeded = this.totalSatoshisNeeded\n obj.moreSatoshisNeeded = this.moreSatoshisNeeded\n return JSON.stringify(obj)\n }\n}\n\nexport class WERR_INVALID_PUBLIC_KEY extends WalletError {\n /**\n * @param key The invalid public key that caused the error.\n * @param environment Optional environment flag to control whether the key is included in the message.\n */\n constructor(\n public key: string,\n network: WalletNetwork = 'mainnet'\n ) {\n const message =\n network === 'mainnet'\n ? `The provided public key \"${key}\" is invalid or malformed.`\n : 'The provided public key is invalid or malformed.'\n super('WERR_INVALID_PUBLIC_KEY', message)\n }\n\n protected override toJson(): string {\n const obj = JSON.parse(super.toJson())\n obj.key = this.key\n return JSON.stringify(obj)\n }\n}\n\n/**\n * When a `createAction` or `signAction` is completed in undelayed mode (`acceptDelayedBroadcast`: false),\n * any unsuccessful result will return the results by way of this exception to ensure attention is\n * paid to processing errors.\n */\nexport class WERR_REVIEW_ACTIONS extends WalletError {\n /**\n * All parameters correspond to their comparable `createAction` or `signAction` results\n * with the exception of `reviewActionResults`;\n * which contains more details, particularly for double spend results.\n */\n constructor(\n public reviewActionResults: ReviewActionResult[],\n public sendWithResults: SendWithResult[],\n public txid?: TXIDHexString,\n public tx?: AtomicBEEF,\n public noSendChange?: OutpointString[]\n ) {\n super('WERR_REVIEW_ACTIONS', 'Undelayed createAction or signAction results require review.')\n }\n\n override toJson(): string {\n const obj = JSON.parse(super.toJson())\n obj.code = 5 // Must match HTTPWalletJSON.ts code\n obj.reviewActionResults = this.reviewActionResults\n obj.sendWithResults = this.sendWithResults\n obj.txid = this.txid\n obj.tx = this.tx\n obj.noSendChange = this.noSendChange\n return JSON.stringify(obj)\n }\n}\n\n/**\n * IF YOU ADD NEW ERRORS, ALSO UPDATE THE WalletError.fromJson METHOD IN src/sdk/WalletError.ts\n */\n","import { WalletError } from './WalletError'\nimport {\n WERR_BAD_REQUEST,\n WERR_BROADCAST_UNAVAILABLE,\n WERR_INSUFFICIENT_FUNDS,\n WERR_INTERNAL,\n WERR_INVALID_OPERATION,\n WERR_INVALID_PARAMETER,\n WERR_INVALID_PUBLIC_KEY,\n WERR_MISSING_PARAMETER,\n WERR_NETWORK_CHAIN,\n WERR_NOT_ACTIVE,\n WERR_NOT_IMPLEMENTED,\n WERR_REVIEW_ACTIONS,\n WERR_UNAUTHORIZED\n} from './WERR_errors'\n\n/**\n * Reconstruct the correct derived WalletError from a JSON object created by `WalletError.unknownToJson`.\n *\n * This function is implemented as a separate function instead of a WalletError class static\n * to avoid circular dependencies.\n *\n * @param json\n * @returns a WalletError derived error object, typically for re-throw.\n */\nexport function WalletErrorFromJson (json: object): WalletError {\n let e: WalletError\n const obj = json as any\n switch (obj.name) {\n case 'WERR_NOT_IMPLEMENTED':\n e = new WERR_NOT_IMPLEMENTED(obj.message)\n break\n case 'WERR_INTERNAL':\n e = new WERR_INTERNAL(obj.message)\n break\n case 'WERR_INVALID_OPERATION':\n e = new WERR_INVALID_OPERATION(obj.message)\n break\n case 'WERR_BROADCAST_UNAVAILABLE':\n e = new WERR_BROADCAST_UNAVAILABLE(obj.message)\n break\n case 'WERR_INVALID_PARAMETER':\n e = new WERR_INVALID_PARAMETER(obj.parameter)\n e.message = obj.message\n break\n case 'WERR_MISSING_PARAMETER':\n e = new WERR_MISSING_PARAMETER(obj.parameter)\n e.message = obj.message\n break\n case 'WERR_BAD_REQUEST':\n e = new WERR_BAD_REQUEST(obj.message)\n break\n case 'WERR_NETWORK_CHAIN':\n e = new WERR_NETWORK_CHAIN(obj.message)\n break\n case 'WERR_UNAUTHORIZED':\n e = new WERR_UNAUTHORIZED(obj.message)\n break\n case 'WERR_NOT_ACTIVE':\n e = new WERR_NOT_ACTIVE(obj.message)\n break\n case 'WERR_INSUFFICIENT_FUNDS':\n e = new WERR_INSUFFICIENT_FUNDS(obj.totalSatoshisNeeded, obj.moreSatoshisNeeded)\n break\n case 'WERR_INVALID_PUBLIC_KEY':\n e = new WERR_INVALID_PUBLIC_KEY(obj.key, 'mainnet')\n e.message = obj.message\n break\n case 'WERR_REVIEW_ACTIONS':\n e = new WERR_REVIEW_ACTIONS(obj.reviewActionResults, obj.sendWithResults, obj.txid, obj.tx, obj.noSendChange)\n break\n default:\n e = new WalletError((typeof obj.name === 'string' && obj.name !== '' ? obj.name : 'WERR_UNKNOWN'), (typeof obj.message === 'string' ? obj.message : ''))\n break\n }\n return e\n}\n","import { Transaction, UnlockingScript } from '@bsv/sdk'\n\n/**\n * Identifies a unique transaction output by its `txid` and index `vout`\n */\nexport interface OutPoint {\n /**\n * Transaction double sha256 hash as big endian hex string\n */\n txid: string\n /**\n * zero based output index within the transaction\n */\n vout: number\n}\n\nexport type Chain = 'main' | 'test' | 'stn' | 'ttn' | 'tstn' | 'mock'\n\n/**\n * Initial status (attempts === 0):\n *\n * nosend: transaction was marked 'noSend'. It is complete and signed. It may be sent by an external party. Proof should be sought as if 'unmined'. No error if it remains unknown by network.\n *\n * unprocessed: indicates req is about to be posted to network by non-acceptDelayedBroadcast application code, after posting status is normally advanced to 'sending'\n *\n * unsent: rawTx has not yet been sent to the network for processing. req is queued for delayed processing.\n *\n * sending: At least one attempt to send rawTx to transaction processors has occured without confirmation of acceptance.\n *\n * unknown: rawTx status is unknown but is believed to have been previously sent to the network.\n *\n * Attempts > 0 status, processing:\n *\n * unknown: Last status update received did not recognize txid or wasn't understood.\n *\n * nonfinal: rawTx has an un-expired nLockTime and is eligible for continuous updating by new transactions with additional outputs and incrementing sequence numbers.\n *\n * unmined: Last attempt has txid waiting to be mined, possibly just sent without callback\n *\n * callback: Waiting for proof confirmation callback from transaction processor.\n *\n * unconfirmed: Potential proof has not been confirmed by chaintracks\n *\n * Terminal status:\n *\n * doubleSpend: Transaction spends same input as another transaction.\n *\n * invalid: rawTx is structuraly invalid or was rejected by the network. Will never be re-attempted or completed.\n *\n * completed: proven_txs record added, and notifications are complete.\n *\n * unfail: asigned to force review of a currently invalid ProvenTxReq.\n */\nexport type ProvenTxReqStatus =\n | 'sending'\n | 'unsent'\n | 'nosend'\n | 'unknown'\n | 'nonfinal'\n | 'unprocessed'\n | 'unmined'\n | 'callback'\n | 'unconfirmed'\n | 'completed'\n | 'invalid'\n | 'doubleSpend'\n | 'unfail'\n\nexport const ProvenTxReqTerminalStatus: ProvenTxReqStatus[] = ['completed', 'invalid', 'doubleSpend']\n\nexport const ProvenTxReqNonTerminalStatus: ProvenTxReqStatus[] = [\n 'sending',\n 'unsent',\n 'nosend',\n 'unknown',\n 'nonfinal',\n 'unprocessed',\n 'unmined',\n 'callback',\n 'unconfirmed'\n]\n\nexport type TransactionStatus =\n 'completed' | 'failed' | 'unprocessed' | 'sending' | 'unproven' | 'unsigned' | 'nosend' | 'nonfinal' | 'unfail'\n\nexport interface Paged {\n limit: number\n offset?: number\n}\n\nexport interface KeyPair {\n privateKey: string\n publicKey: string\n}\n\nexport interface StorageIdentity {\n /**\n * The identity key (public key) assigned to this storage\n */\n storageIdentityKey: string\n /**\n * The human readable name assigned to this storage.\n */\n storageName: string\n}\n\nexport interface EntityTimeStamp {\n created_at: Date\n updated_at: Date\n}\n\nexport interface ScriptTemplateUnlock {\n sign: (tx: Transaction, inputIndex: number) => Promise<UnlockingScript>\n estimateLength: (tx: Transaction, inputIndex: number) => Promise<number>\n}\n\nexport interface WalletBalance {\n total: number\n utxos: Array<{ satoshis: number; outpoint: string }>\n}\n\nexport interface ReqHistoryNote {\n when?: string\n what: string\n [key: string]: boolean | string | number | undefined\n}\n\n/**\n * The transaction status that a client will receive when subscribing to transaction updates in the Monitor.\n */\nexport interface ProvenTransactionStatus {\n txid: string\n txIndex: number\n blockHeight: number\n blockHash: string\n merklePath: number[]\n merkleRoot: string\n}\n\n/**\n * `listOutputs` special operation basket name value.\n *\n * Returns wallet's current change balance in the `totalOutputs` result property.\n * The `outputs` result property will always be an empty array.\n */\nexport const specOpWalletBalance = '893b7646de0e1c9f741bd6e9169b76a8847ae34adef7bef1e6a285371206d2e8'\n\n/**\n * `listOutputs` special operation basket name value.\n *\n * Lists only spendable wallet-managed BRC-29 change from the `default`\n * basket. Raw administrative `listOutputs({ basket: 'default' })` remains\n * intentionally unfiltered so legacy incompatible rows stay discoverable\n * for recovery instead of being hidden or silently mutated.\n */\nexport const specOpWalletManagedUtxos = '284570a6213a74ba861c38b1cf790e1e400d9cf9324454b76ea98860b6031c1a'\n\n/**\n * `listOutputs` special operation basket name value.\n *\n * Returns currently spendable wallet change outputs that fail to validate as unspent transaction outputs.\n *\n * Optional tag value 'release'. If present, updates invalid change outputs to not spendable.\n *\n * Optional tag value 'all'. If present, processes all spendable true outputs, independent of baskets, but basket must be defined.\n */\nexport const specOpInvalidChange = '5a76fd430a311f8bc0553859061710a4475c19fed46e2ff95969aa918e612e57'\n\n/**\n * `listOutputs` special operation basket name value.\n *\n * Updates the wallet's automatic change management parameters.\n *\n * Tag at index 0 is the new desired number of spendable change outputs to maintain.\n *\n * Tag at index 1 is the new target for minimum satoshis when creating new change outputs.\n */\nexport const specOpSetWalletChangeParams = 'a4979d28ced8581e9c1c92f1001cc7cb3aabf8ea32e10888ad898f0a509a3929'\n\n/**\n * @param basket Output basket name value.\n * @returns true iff the `basket` name is a reserved `listOutputs` special operation identifier.\n */\nexport function isListOutputsSpecOp(basket: string): boolean {\n return [specOpWalletBalance, specOpWalletManagedUtxos, specOpInvalidChange, specOpSetWalletChangeParams].includes(\n basket\n )\n}\n\n/**\n * `listActions` special operation label name value.\n *\n * Processes only actions currently with status 'nosend'\n *\n * Optional label value 'abort'. If present, runs abortAction on all the actions returned.\n */\nexport const specOpNoSendActions = 'ac6b20a3bb320adafecd637b25c84b792ad828d3aa510d05dc841481f664277d'\n\n/**\n * `listActions` special operation label name value.\n *\n * Processes only actions currently with status 'failed'\n *\n * Optional label value 'unfail'. If present, sets status to 'unfail', which queues them for attempted recovery by the Monitor.\n */\nexport const specOpFailedActions = '97d4eb1e49215e3374cc2c1939a7c43a55e95c7427bf2d45ed63e3b4e0c88153'\n\n/**\n * @param label Action / Transaction label name value.\n * @returns true iff the `label` name is a reserved `listActions` special operation identifier.\n */\nexport function isListActionsSpecOp(label: string): boolean {\n return [specOpNoSendActions, specOpFailedActions].includes(label)\n}\n\n/**\n * `createAction` special operation label name value.\n *\n * Causes WERR_REVIEW_ACTIONS throw with dummy properties.\n *\n */\nexport const specOpThrowReviewActions = 'a496e747fc3ad5fabdd4ae8f91184e71f87539bd3d962aa2548942faaaf0047a'\n\n/**\n * @param label Action / Transaction label name value.\n * @returns true iff the `label` name is a reserved `createAction` special operation identifier.\n */\nexport function isCreateActionSpecOp(label: string): boolean {\n return [specOpThrowReviewActions].includes(label)\n}\n","import {\n Random,\n Utils,\n PrivateKey,\n CreateHmacArgs,\n CreateHmacResult,\n CreateSignatureArgs,\n CreateSignatureResult,\n GetPublicKeyArgs,\n ProtoWallet,\n PubKeyHex,\n RevealCounterpartyKeyLinkageArgs,\n RevealCounterpartyKeyLinkageResult,\n RevealSpecificKeyLinkageArgs,\n RevealSpecificKeyLinkageResult,\n VerifyHmacArgs,\n VerifyHmacResult,\n VerifySignatureArgs,\n VerifySignatureResult,\n WalletDecryptArgs,\n WalletDecryptResult,\n WalletEncryptArgs,\n WalletEncryptResult\n} from '@bsv/sdk'\n\n/**\n * PrivilegedKeyManager\n *\n * This class manages a privileged (i.e., very sensitive) private key, obtained from\n * an external function (`keyGetter`), which might be backed by HSMs, secure enclaves,\n * or other secure storage. The manager retains the key in memory only for a limited\n * duration (`retentionPeriod`), uses XOR-based chunk-splitting obfuscation, and\n * includes decoy data to raise the difficulty of discovering the real key in memory.\n *\n * IMPORTANT: While these measures raise the bar for attackers, JavaScript environments\n * do not provide perfect in-memory secrecy.\n */\nexport class PrivilegedKeyManager implements ProtoWallet {\n /**\n * Function that will retrieve the PrivateKey from a secure environment,\n * e.g., an HSM or secure enclave. The reason for key usage is passed in\n * to help with user consent, auditing, and access policy checks.\n */\n private readonly keyGetter: (reason: string) => Promise<PrivateKey>\n\n /**\n * Time (in ms) for which the obfuscated key remains in memory\n * before being automatically destroyed.\n */\n private readonly retentionPeriod: number\n\n /**\n * A list of dynamically generated property names used to store\n * real key chunks (XORed with random pads).\n */\n private chunkPropNames: string[] = []\n\n /**\n * A list of dynamically generated property names used to store\n * the random pads that correspond to the real key chunks.\n */\n private chunkPadPropNames: string[] = []\n\n /**\n * A list of decoy property names that will be removed\n * when the real key is destroyed.\n */\n private decoyPropNamesDestroy: string[] = []\n\n /**\n * A list of decoy property names that remain in memory\n * even after the real key is destroyed (just to cause confusion).\n */\n private readonly decoyPropNamesRemain: string[] = []\n\n /**\n * Handle to the timer that will remove the key from memory\n * after the retention period. If the key is refreshed again\n * within that period, the timer is cleared and re-set.\n */\n private destroyTimer: any\n\n /**\n * Number of chunks to split the 32-byte key into.\n * Adjust to increase or decrease obfuscation complexity.\n */\n private readonly CHUNK_COUNT = 4\n\n /**\n * @param keyGetter - Asynchronous function that retrieves the PrivateKey from a secure environment.\n * @param retentionPeriod - Time in milliseconds to retain the obfuscated key in memory before zeroizing.\n */\n constructor(keyGetter: (reason: string) => Promise<PrivateKey>, retentionPeriod = 120_000) {\n this.keyGetter = keyGetter\n this.retentionPeriod = retentionPeriod\n\n // Initialize some random decoy properties that always remain:\n for (let i = 0; i < 2; i++) {\n const propName = this.generateRandomPropName()\n // Store random garbage to cause confusion\n ;(this as any)[propName] = Uint8Array.from(Random(16))\n this.decoyPropNamesRemain.push(propName)\n }\n }\n\n /**\n * Safely destroys the in-memory obfuscated key material by zeroizing\n * and deleting related fields. Also destroys some (but not all) decoy\n * properties to further confuse an attacker.\n */\n destroyKey(): void {\n try {\n // Zero out real chunk data\n for (const name of this.chunkPropNames) {\n const data: Uint8Array | undefined = (this as any)[name]\n if (data != null) {\n data.fill(0)\n }\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete (this as any)[name]\n }\n for (const name of this.chunkPadPropNames) {\n const data: Uint8Array | undefined = (this as any)[name]\n if (data != null) {\n data.fill(0)\n }\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete (this as any)[name]\n }\n\n // Destroy some decoys\n for (const name of this.decoyPropNamesDestroy) {\n const data: Uint8Array | undefined = (this as any)[name]\n if (data != null) {\n data.fill(0)\n }\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete (this as any)[name]\n }\n\n // Clear arrays of property names\n this.chunkPropNames = []\n this.chunkPadPropNames = []\n this.decoyPropNamesDestroy = []\n } catch {\n // Best-effort memory zeroing: if an individual property is already gone or the\n // fill/delete throws (e.g. frozen object in a test harness), we must still reach\n // the finally block to clear the destruction timer. Propagating here would leave\n // the timer running and risk a second (no-op) destruction attempt.\n } finally {\n if (this.destroyTimer != null) {\n clearTimeout(this.destroyTimer)\n this.destroyTimer = undefined\n }\n }\n }\n\n /**\n * Re/sets the destruction timer that removes the key from memory\n * after `retentionPeriod` ms. If a timer is already running, it\n * is cleared and re-set. This ensures the key remains in memory\n * for exactly the desired window after its most recent acquisition.\n */\n private scheduleKeyDestruction(): void {\n if (this.destroyTimer != null) {\n clearTimeout(this.destroyTimer)\n }\n this.destroyTimer = setTimeout(() => {\n this.destroyKey()\n }, this.retentionPeriod)\n }\n\n /**\n * XOR-based obfuscation on a per-chunk basis.\n * This function takes two equal-length byte arrays\n * and returns the XOR combination.\n */\n private xorBytes(a: Uint8Array, b: Uint8Array): Uint8Array {\n const out = new Uint8Array(a.length)\n for (let i = 0; i < a.length; i++) {\n out[i] = a[i] ^ b[i]\n }\n return out\n }\n\n /**\n * Splits the 32-byte key into `this.CHUNK_COUNT` smaller chunks\n * (mostly equal length; the last chunk picks up leftover bytes\n * if 32 is not evenly divisible).\n */\n private splitKeyIntoChunks(keyBytes: Uint8Array): Uint8Array[] {\n const chunkSize = Math.floor(keyBytes.length / this.CHUNK_COUNT)\n const chunks: Uint8Array[] = []\n let offset = 0\n\n for (let i = 0; i < this.CHUNK_COUNT; i++) {\n const size = i === this.CHUNK_COUNT - 1 ? keyBytes.length - offset : chunkSize\n chunks.push(keyBytes.slice(offset, offset + size))\n offset += size\n }\n return chunks\n }\n\n /**\n * Reassembles the chunks from the dynamic properties, XORs them\n * with their corresponding pads, and returns a single 32-byte\n * Uint8Array representing the raw key.\n */\n private reassembleKeyFromChunks(): Uint8Array | null {\n try {\n const chunkArrays: Uint8Array[] = []\n for (let i = 0; i < this.chunkPropNames.length; i++) {\n const chunkEnc = (this as any)[this.chunkPropNames[i]] as Uint8Array\n const chunkPad = (this as any)[this.chunkPadPropNames[i]] as Uint8Array\n if (chunkEnc?.length == null || chunkEnc.length !== chunkPad?.length) {\n return null\n }\n const rawChunk = this.xorBytes(chunkEnc, chunkPad)\n chunkArrays.push(rawChunk)\n }\n // Concat them back to a single 32-byte array:\n const totalLength = chunkArrays.reduce((sum, c) => sum + c.length, 0)\n if (totalLength !== 32) {\n // We only handle 32-byte keys\n return null\n }\n const rawKey = new Uint8Array(totalLength)\n let offset = 0\n for (const chunk of chunkArrays) {\n rawKey.set(chunk, offset)\n offset += chunk.length\n // Attempt to zero the ephemeral chunk\n chunk.fill(0)\n }\n return rawKey\n } catch {\n // Reassembly failed due to a missing property or type mismatch (e.g. the key was\n // already destroyed or was never stored). Returning null signals \"no key available\"\n // to the caller, which will prompt re-authentication — propagating the raw error\n // would leak internal obfuscation details and bypass that recovery path.\n return null\n }\n }\n\n /**\n * Generates a random property name to store key chunks or decoy data.\n */\n private generateRandomPropName(): string {\n // E.g., 8 random hex characters for the property name\n const randomHex = Utils.toHex(Random(4))\n const extraBytes = Random(3)\n const extraNum = ((extraBytes[0] << 16) | (extraBytes[1] << 8) | extraBytes[2]) % 1000000\n return `_${randomHex}_${extraNum}`\n }\n\n /**\n * Forces a PrivateKey to be represented as exactly 32 bytes, left-padding\n * with zeros if its numeric value has fewer than 32 bytes.\n */\n private get32ByteRepresentation(privKey: PrivateKey): Uint8Array {\n // The internal \"toArray()\" can be up to 32 bytes, but sometimes fewer\n // if the numeric value has leading zeros.\n const buf = privKey.toArray()\n if (buf.length > 32) {\n throw new Error('PrivilegedKeyManager: Expected a 32-byte key, but got more.')\n }\n // Left-pad with zeros if needed\n const keyBytes = new Uint8Array(32)\n keyBytes.set(buf, 32 - buf.length)\n return keyBytes\n }\n\n /**\n * Returns the privileged key needed to perform cryptographic operations.\n * Uses in-memory chunk-based obfuscation if the key was already fetched.\n * Otherwise, it calls out to `keyGetter`, splits the 32-byte representation\n * of the key, XORs each chunk with a random pad, and stores them under\n * dynamic property names. Also populates new decoy properties.\n *\n * @param reason - The reason for why the key is needed, passed to keyGetter.\n * @returns The PrivateKey object needed for cryptographic operations.\n */\n private async getPrivilegedKey(reason: string): Promise<PrivateKey> {\n // If we already have chunk properties, try reassemble\n if (this.chunkPropNames.length > 0 && this.chunkPadPropNames.length > 0) {\n const rawKeyBytes = this.reassembleKeyFromChunks()\n if (rawKeyBytes?.length === 32) {\n // Convert 32 raw bytes back to a PrivateKey\n // (Leading zeros are preserved, but PrivateKey() will parse it as a big integer.)\n const hexKey = Utils.toHex([...rawKeyBytes]) // 64 hex chars\n rawKeyBytes.fill(0) // Zero ephemeral copy\n this.scheduleKeyDestruction()\n return new PrivateKey(hexKey, 'hex')\n }\n }\n\n // Otherwise, fetch a fresh key from the secure environment\n const fetchedKey = await this.keyGetter(reason)\n\n // Force 32‑byte representation (left-pad if necessary)\n const keyBytes = this.get32ByteRepresentation(fetchedKey)\n\n // Clean up any old data first (in case we had something stale)\n this.destroyKey()\n\n // Split the key\n const chunks = this.splitKeyIntoChunks(keyBytes)\n\n // Store new chunk data under random property names\n for (const chunk of chunks) {\n const chunkProp = this.generateRandomPropName()\n const padProp = this.generateRandomPropName()\n this.chunkPropNames.push(chunkProp)\n this.chunkPadPropNames.push(padProp)\n\n // Generate random pad of the same length as the chunk\n const pad = Uint8Array.from(Random(chunk.length))\n // XOR the chunk to obfuscate\n const obf = this.xorBytes(chunk, pad)\n\n // Store them in dynamic properties\n ;(this as any)[chunkProp] = obf\n ;(this as any)[padProp] = pad\n }\n\n // Generate some decoy properties that will be destroyed with the key\n for (let i = 0; i < 2; i++) {\n const decoyProp = this.generateRandomPropName()\n ;(this as any)[decoyProp] = Uint8Array.from(Random(32))\n this.decoyPropNamesDestroy.push(decoyProp)\n }\n\n // Zero out ephemeral original\n keyBytes.fill(0)\n\n // Schedule destruction\n this.scheduleKeyDestruction()\n\n // Return the newly fetched key as a normal PrivateKey\n return fetchedKey\n }\n\n async getPublicKey(args: GetPublicKeyArgs): Promise<{ publicKey: PubKeyHex }> {\n return await new ProtoWallet(await this.getPrivilegedKey(args.privilegedReason as string)).getPublicKey(args)\n }\n\n async revealCounterpartyKeyLinkage(\n args: RevealCounterpartyKeyLinkageArgs\n ): Promise<RevealCounterpartyKeyLinkageResult> {\n return await new ProtoWallet(\n await this.getPrivilegedKey(args.privilegedReason as string)\n ).revealCounterpartyKeyLinkage(args)\n }\n\n async revealSpecificKeyLinkage(args: RevealSpecificKeyLinkageArgs): Promise<RevealSpecificKeyLinkageResult> {\n return await new ProtoWallet(await this.getPrivilegedKey(args.privilegedReason as string)).revealSpecificKeyLinkage(\n args\n )\n }\n\n async encrypt(args: WalletEncryptArgs): Promise<WalletEncryptResult> {\n return await new ProtoWallet(await this.getPrivilegedKey(args.privilegedReason as string)).encrypt(args)\n }\n\n async decrypt(args: WalletDecryptArgs): Promise<WalletDecryptResult> {\n return await new ProtoWallet(await this.getPrivilegedKey(args.privilegedReason as string)).decrypt(args)\n }\n\n async createHmac(args: CreateHmacArgs): Promise<CreateHmacResult> {\n return await new ProtoWallet(await this.getPrivilegedKey(args.privilegedReason as string)).createHmac(args)\n }\n\n async verifyHmac(args: VerifyHmacArgs): Promise<VerifyHmacResult> {\n return await new ProtoWallet(await this.getPrivilegedKey(args.privilegedReason as string)).verifyHmac(args)\n }\n\n async createSignature(args: CreateSignatureArgs): Promise<CreateSignatureResult> {\n return await new ProtoWallet(await this.getPrivilegedKey(args.privilegedReason as string)).createSignature(args)\n }\n\n async verifySignature(args: VerifySignatureArgs): Promise<VerifySignatureResult> {\n return await new ProtoWallet(await this.getPrivilegedKey(args.privilegedReason as string)).verifySignature(args)\n }\n}\n","export * from './WalletError'\nexport * from './WalletErrorFromJson'\nexport * from './WalletSigner.interfaces'\nexport * from './WalletStorage.interfaces'\nexport * from './ActionBatch.interfaces'\nexport * from './WERR_errors'\nexport { Validation } from '@bsv/sdk'\nexport * from './CertOpsWallet'\nexport * from './types'\nexport * from './WalletServices.interfaces'\nexport * from './PrivilegedKeyManager'\n","/**\n * If a log is being kept, add a time stamped line.\n * @param log Optional time stamped log to extend, or an object with a log property to update\n * @param lineToAdd Content to add to line.\n * @returns undefined or log extended by time stamped `lineToAdd` and new line.\n */\nexport function stampLog(log: string | undefined | { log?: string }, lineToAdd: string): string | undefined {\n const add = `${new Date().toISOString()} ${lineToAdd}\\n`\n if (typeof log === 'object' && typeof log.log === 'string') {\n log.log = log.log + add\n return log.log\n }\n if (typeof log === 'string') return log + add\n return undefined\n}\n\ninterface StampLogEntry {\n when: number\n rest: string\n delta: number\n newClock: boolean\n}\n\nfunction parseStampLog(log: string): { data: StampLogEntry[]; newClocks: number[] } {\n const data: StampLogEntry[] = []\n const newClocks: number[] = []\n let last = 0\n for (const line of log.split('\\n')) {\n const spaceAt = line.indexOf(' ')\n if (spaceAt < 0) continue\n const when = new Date(line.substring(0, spaceAt)).getTime()\n const rest = line.substring(spaceAt + 1)\n const delta = when - (last !== 0 ? last : when)\n const newClock = rest.i